README.md in csv_row_model-1.0.0.beta1 vs README.md in csv_row_model-1.0.0.beta2

- old
+ new

@@ -48,14 +48,14 @@ end import_file = CsvRowModel::Import::File.new(file_path, ProjectImportRowModel) row_model = import_file.next -row_model.header # => ["id", "name"] +row_model.headers # => ["id", "name"] row_model.source_row # => ["1", "Some Project Name"] -row_model.mapped_row # => { id: "1", name: "Some Project Name" }, this is `source_row` mapped to `column_names` +row_model.source_attributes # => { id: "1", name: "Some Project Name" }, this is `source_row` mapped to `column_names` row_model.attributes # => { id: "1", name: "Some Project Name" }, this is final attribute values mapped to `column_names` row_model.id # => 1 row_model.name # => "Some Project Name" @@ -121,11 +121,11 @@ To generate a attribute value, the following pseudocode is executed: ```ruby def original_attribute(column_name) # 1. Get the raw CSV string value for the column - value = mapped_row[column_name] + value = source_attributes[column_name] # 2. Clean or format each cell value = self.class.format_cell(cell, column_name, column_index, context) if value.present? @@ -278,10 +278,22 @@ import_file = CsvRowModel::Import::File.new(file_path, ProjectImportRowModel) import_file.each { |project_import_model| puts "does not yield here" } import_file.next # does not skip or abort ``` +### File Validations +You can also have file validations, while will make the entire import process abort. Currently, there is one provided validation. + +```ruby +class ImportFile < CsvRowModel::Import::File + validate :headers_invalid_row # checks if header is valid CSV syntax + validate :headers_count # calls #headers_invalid_row, then check the count. will ignore tailing empty headers +end +``` + +Can't be used for [Dynamic Columns](#dynamic-columns) or [File Model](#file-model)s. + ### Import Callbacks `CsvRowModel::Import::File` can be subclassed to access [`ActiveModel::Callbacks`](http://api.rubyonrails.org/classes/ActiveModel/Callbacks.html). * each_iteration - `before`, `around`, or `after` the an iteration on `#each`. @@ -348,11 +360,11 @@ row_model = ProjectRowModel.new(["-1"]) row_model.valid? # => false row_model.errors.full_messages # => ["Id must be greater than 0"] ``` -Note that `CsvStringModel` validations are calculated after [Format Cell](#format-cell). +Note that `CsvStringModel` validations are calculated after [Format Attribute](#format-cell). ### Represents A CSV is often a representation of database model(s), much like how JSON parameters represents models in requests. However, CSVs schemas are **flat** and **static** and JSON parameters are **tree structured** and **dynamic** (but often static). Because CSVs are flat, `RowModel`s are also flat, but they can represent various models. The `represents` interface attempts to simplify this for importing. @@ -427,22 +439,22 @@ import_file = CsvRowModel::Import::File.new(file_path, UserImportRowModel) row_model = import_file.next row_model.projects # => [<ProjectImportRowModel>, ...] ``` -## Dynamic columns +## Dynamic Columns Dynamic columns are columns that can expand to many columns. Currently, we can only one dynamic column after all other standard columns. The following: ```ruby class DynamicColumnModel include CsvRowModel::Model column :first_name column :last_name # header is optional, below is the default_implementation - dynamic_column :skills, header: ->(skill_name) { skill_name } + dynamic_column :skills, header: ->(skill_name) { skill_name }, header_models_context_key: :skills end ``` represents this table: @@ -451,11 +463,11 @@ | John | Doe | No | Yes | | Mario | Super | Yes | No | | Mike | Jackson | Yes | Yes | -The `format_dynamic_column_header(header_model, column_name, dynamic_column_index, index_of_column, context)` can +The `format_dynamic_column_header(header_model, column_name, dynamic_column_index, context)` can be used to defined like `format_header`. Defined in both import and export due to headers being used for both. ### Export Dynamic column attributes are arrays, but each item in the array is defined via singular attribute method like normal columns: @@ -468,11 +480,12 @@ # below is an override, this is the default implementation: skill_name # => "skill1", then "skill2" source_model.skills.include?(skill_name) ? "Yes" : "No" end end -# the `skills` context is mapped to generate an array +# `skills` in the context is used as the header, which is used in `def skill(skill_name)` above +# to change this context key, use the :header_models_context_key option export_file = CsvRowModel::Export::File.new(DynamicColumnExportModel, { skills: Skill.all }) export_file.generate do |csv| User.all.each { |user| csv << user } end ``` @@ -502,10 +515,10 @@ row_model = CsvRowModel::Import::File.new(file_path, DynamicColumnImportModel).next row_model.attributes # => { first_name: "John", last_name: "Doe", skills: ['No', 'Yes'] } row_model.skills # => ['No', 'Yes'] ``` -## File Model (Mapping) +## File Model If you have to deal with a mapping on a csv you can use FileModel, isn't complete a this time and many cases isn't covered but can be helpful Here an example of FileRowModel