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