csv_row_model 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +264 -202
- data/csv_row_model.gemspec +1 -1
- data/lib/csv_row_model.rb +7 -7
- data/lib/csv_row_model/concerns/{deep_class_var.rb → inherited_class_var.rb} +11 -11
- data/lib/csv_row_model/export.rb +3 -28
- data/lib/csv_row_model/export/file.rb +49 -0
- data/lib/csv_row_model/export/{single_model.rb → file_model.rb} +8 -17
- data/lib/csv_row_model/import.rb +19 -5
- data/lib/csv_row_model/import/attributes.rb +7 -6
- data/lib/csv_row_model/import/file.rb +24 -82
- data/lib/csv_row_model/import/file/callbacks.rb +2 -1
- data/lib/csv_row_model/import/{single_model.rb → file_model.rb} +20 -7
- data/lib/csv_row_model/import/presenter.rb +15 -9
- data/lib/csv_row_model/model.rb +1 -1
- data/lib/csv_row_model/model/children.rb +2 -2
- data/lib/csv_row_model/model/columns.rb +25 -2
- data/lib/csv_row_model/model/csv_string_model.rb +1 -10
- data/lib/csv_row_model/model/{single_model.rb → file_model.rb} +2 -1
- data/lib/csv_row_model/version.rb +1 -1
- metadata +8 -8
- data/lib/csv_row_model/export/csv.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5498738789715db182f898e6d048cf27368bc5b9
|
4
|
+
data.tar.gz: f70ad9d361f804afd025e3c5214dc63c2734f603
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60d6189fe5d90a7efb8e5630080f8b2d259fcef21beab143d54781b695c512b567c5f1bef27d11a329de9ba83145a03e5684208d7dde30c55639b09c1bbb55b6
|
7
|
+
data.tar.gz: 266ba89a88b2df74e1fa75f33bd9651fb27bb012d5707ac41567fbcbc3cded3cd97e4536d45170c1140ddef0ea9bd35ad2a4d1d05f15e83f22c0d4abf8f4620c
|
data/README.md
CHANGED
@@ -2,6 +2,65 @@
|
|
2
2
|
|
3
3
|
Import and export your custom CSVs with a intuitive shared Ruby interface.
|
4
4
|
|
5
|
+
First define your schema:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class ProjectRowModel
|
9
|
+
include CsvRowModel::Model
|
10
|
+
|
11
|
+
column :id
|
12
|
+
column :name
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
To export, define your export model like [`ActiveModel::Serializer`](https://github.com/rails-api/active_model_serializers)
|
17
|
+
and generate the file:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class ProjectExportRowModel < ProjectRowModel
|
21
|
+
include CsvRowModel::Export
|
22
|
+
|
23
|
+
# this is an override with the default implementation
|
24
|
+
def id
|
25
|
+
source_model.id
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
export_file = CsvRowModel::Export::File.new(ProjectExportRowModel)
|
30
|
+
export_file.generate { |csv| csv << project }
|
31
|
+
export_file.file # => <Tempfile>
|
32
|
+
export_file.to_s # => export_file.file.read
|
33
|
+
```
|
34
|
+
|
35
|
+
To import, define your import model, which works like [`ActiveRecord`](http://guides.rubyonrails.org/active_record_querying.html),
|
36
|
+
and iterate through a file:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
class ProjectImportRowModel < ProjectRowModel
|
40
|
+
include CsvRowModel::Import
|
41
|
+
|
42
|
+
# this is an override with the default implementation
|
43
|
+
def id
|
44
|
+
original_attribute(:id)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
import_file = CsvRowModel::Import::File.new(file_path, ProjectImportRowModel)
|
49
|
+
row_model = import_file.next
|
50
|
+
|
51
|
+
row_model.header # => ["id", "name"]
|
52
|
+
|
53
|
+
row_model.source_row # => ["1", "Some Project Name"]
|
54
|
+
row_model.mapped_row # => { id: "1", name: "Some Project Name" }, this is `source_row` mapped to `column_names`
|
55
|
+
row_model.attributes # => { id: "1", name: "Some Project Name" }, this is final attribute values mapped to `column_names`
|
56
|
+
|
57
|
+
row_model.id # => 1
|
58
|
+
row_model.name # => "Some Project Name"
|
59
|
+
|
60
|
+
row_model.previous # => <ProjectImportRowModel instance>
|
61
|
+
row_model.previous.previous # => nil, save memory by avoiding a linked list
|
62
|
+
```
|
63
|
+
|
5
64
|
## Installation
|
6
65
|
|
7
66
|
Add this line to your application's Gemfile:
|
@@ -18,68 +77,213 @@ Or install it yourself as:
|
|
18
77
|
|
19
78
|
$ gem install csv_row_model
|
20
79
|
|
21
|
-
##
|
80
|
+
## Export
|
81
|
+
|
82
|
+
### Header Value
|
83
|
+
To generate a header value, the following pseudocode is executed:
|
84
|
+
```ruby
|
85
|
+
def header(column_name)
|
86
|
+
# 1. Header Option
|
87
|
+
header = options(column_name)[:header]
|
22
88
|
|
23
|
-
|
89
|
+
# 2. format_header
|
90
|
+
header || format_header(column_name)
|
91
|
+
end
|
92
|
+
```
|
24
93
|
|
94
|
+
#### Header Option
|
95
|
+
Specify the header manually:
|
25
96
|
```ruby
|
26
97
|
class ProjectRowModel
|
27
98
|
include CsvRowModel::Model
|
99
|
+
column :name, header: "NAME"
|
100
|
+
end
|
101
|
+
```
|
28
102
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
103
|
+
#### Format Header
|
104
|
+
Override the `format_header` method to format column header names:
|
105
|
+
```ruby
|
106
|
+
class ProjectExportRowModel < ProjectRowModel
|
107
|
+
include CsvRowModel::Export
|
108
|
+
class << self
|
109
|
+
def format_header(column_name)
|
110
|
+
column_name.to_s.titleize
|
111
|
+
end
|
112
|
+
end
|
33
113
|
end
|
34
114
|
```
|
35
115
|
|
36
116
|
## Import
|
37
117
|
|
38
|
-
|
118
|
+
### Attribute Values
|
119
|
+
To generate a attribute value, the following pseudocode is executed:
|
39
120
|
|
121
|
+
```ruby
|
122
|
+
def original_attribute(column_name)
|
123
|
+
# 1. Get the raw CSV string value for the column
|
124
|
+
value = mapped_row[column_name]
|
125
|
+
|
126
|
+
# 2. Clean or format each cell
|
127
|
+
value = self.class.format_cell(value)
|
128
|
+
|
129
|
+
if value.present?
|
130
|
+
# 3a. Parse the cell value (which does nothing if no parsing is specified)
|
131
|
+
parse(value)
|
132
|
+
elsif default_exists?
|
133
|
+
# 3b. Set the default
|
134
|
+
default_for_column(column_name)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def original_attributes; @original_attributes ||= { id: original_attribute(:id) } end
|
139
|
+
|
140
|
+
def id; original_attribute[:id] end
|
141
|
+
```
|
142
|
+
|
143
|
+
#### Format Cell
|
144
|
+
Override the `format_cell` method to clean/format every cell:
|
40
145
|
```ruby
|
41
146
|
class ProjectImportRowModel < ProjectRowModel
|
42
147
|
include CsvRowModel::Import
|
148
|
+
class << self
|
149
|
+
def format_cell(cell, column_name, column_index)
|
150
|
+
cell = cell.strip
|
151
|
+
cell.blank? ? nil : cell
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
#### Type
|
158
|
+
Automatic type parsing.
|
43
159
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
160
|
+
```ruby
|
161
|
+
class ProjectImportRowModel
|
162
|
+
include CsvRowModel::Model
|
163
|
+
include CsvRowModel::Import
|
164
|
+
|
165
|
+
column :id, type: Integer
|
166
|
+
column :name, parse: ->(original_string) { parse(original_string) }
|
167
|
+
|
168
|
+
def parse(original_string)
|
169
|
+
"#{id} - #{original_string}"
|
48
170
|
end
|
49
171
|
end
|
50
172
|
```
|
51
173
|
|
52
|
-
|
174
|
+
There are validators for different types: `Boolean`, `Date`, `Float`, `Integer`. See [Validations](#validations) for more.
|
175
|
+
|
176
|
+
#### Default
|
177
|
+
Sets the default value of the cell:
|
178
|
+
```ruby
|
179
|
+
class ProjectImportRowModel
|
180
|
+
include CsvRowModel::Model
|
181
|
+
include CsvRowModel::Import
|
182
|
+
|
183
|
+
column :id, default: 1
|
184
|
+
column :name, default: -> { get_name }
|
185
|
+
|
186
|
+
def get_name; "John Doe" end
|
187
|
+
end
|
188
|
+
row_model = ProjectImportRowModel.new(["", ""])
|
189
|
+
row_model.id # => 1
|
190
|
+
row_model.name # => "John Doe"
|
191
|
+
row_model.default_changes # => { id: ["", 1], name: ["", "John Doe"] }
|
192
|
+
```
|
193
|
+
|
194
|
+
`DefaultChangeValidator` is provided to allows to add warnings when defaults are set. See [Validations](#default-changes) for more.
|
195
|
+
|
196
|
+
## Advanced Import
|
197
|
+
|
198
|
+
### Children
|
199
|
+
|
200
|
+
Child `RowModel` relationships can also be defined:
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
class UserImportRowModel
|
204
|
+
include CsvRowModel::Model
|
205
|
+
include CsvRowModel::Import
|
206
|
+
|
207
|
+
column :id, type: Integer
|
208
|
+
column :name
|
209
|
+
column :email
|
210
|
+
|
211
|
+
# uses ProjectImportRowModel#valid? to detect the child row
|
212
|
+
has_many :projects, ProjectImportRowModel
|
213
|
+
end
|
53
214
|
|
215
|
+
import_file = CsvRowModel::Import::File.new(file_path, UserImportRowModel)
|
216
|
+
row_model = import_file.next
|
217
|
+
row_model.projects # => [<ProjectImportRowModel>, ...]
|
218
|
+
```
|
219
|
+
|
220
|
+
### Layers
|
221
|
+
For complex `RowModel`s there are different layers you can work with:
|
54
222
|
```ruby
|
55
223
|
import_file = CsvRowModel::Import::File.new(file_path, ProjectImportRowModel)
|
56
224
|
row_model = import_file.next
|
57
225
|
|
58
|
-
|
226
|
+
# the three layers:
|
227
|
+
# 1. csv_string_model - represents the row BEFORE parsing (attributes are always strings)
|
228
|
+
row_model.csv_string_model
|
59
229
|
|
60
|
-
|
61
|
-
row_model
|
230
|
+
# 2. RowModel - represents the row AFTER parsing
|
231
|
+
row_model
|
62
232
|
|
63
|
-
|
64
|
-
row_model.
|
233
|
+
# 3. Presenter - an abstraction of a row
|
234
|
+
row_model.presenter
|
65
235
|
```
|
66
236
|
|
67
|
-
|
237
|
+
#### CsvStringModel
|
238
|
+
The `CsvStringModel` represents a row before parsing to add parsing validations.
|
68
239
|
|
69
240
|
```ruby
|
70
|
-
|
71
|
-
|
241
|
+
class ProjectImportRowModel
|
242
|
+
include CsvRowModel::Model
|
243
|
+
include CsvRowModel::Import
|
244
|
+
|
245
|
+
# Note the type definition here for parsing
|
246
|
+
column :id, type: Integer
|
247
|
+
|
248
|
+
# this is applied to the parsed CSV on the model
|
249
|
+
validates :id, numericality: { greater_than: 0 }
|
250
|
+
|
251
|
+
csv_string_model do
|
252
|
+
# define your csv_string_model here
|
253
|
+
|
254
|
+
# this is applied BEFORE the parsed CSV on csv_string_model
|
255
|
+
validates :id, presense: true
|
256
|
+
|
257
|
+
def random_method; "Hihi" end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Applied to the String
|
262
|
+
ProjectImportRowModel.new([""])
|
263
|
+
csv_string_model = row_model.csv_string_model
|
264
|
+
csv_string_model.random_method => "Hihi"
|
265
|
+
csv_string_model.valid? => false
|
266
|
+
csv_string_model.errors.full_messages # => ["Id can't be blank'"]
|
267
|
+
|
268
|
+
# Errors are propagated for simplicity
|
269
|
+
row_model.valid? # => false
|
270
|
+
row_model.errors.full_messages # => ["Id can't be blank'"]
|
271
|
+
|
272
|
+
# Applied to the parsed Integer
|
273
|
+
row_model = ProjectRowModel.new(["-1"])
|
274
|
+
row_model.valid? # => false
|
275
|
+
row_model.errors.full_messages # => ["Id must be greater than 0"]
|
72
276
|
```
|
73
277
|
|
74
|
-
|
278
|
+
Note that `CsvStringModel` validations are calculated after [Format Cell](#format-cell).
|
279
|
+
|
280
|
+
#### Presenter
|
75
281
|
For complex rows, you can wrap your `RowModel` with a presenter:
|
76
282
|
|
77
283
|
```ruby
|
78
284
|
class ProjectImportRowModel < ProjectRowModel
|
79
285
|
include CsvRowModel::Import
|
80
286
|
|
81
|
-
# same as above
|
82
|
-
|
83
287
|
presenter do
|
84
288
|
# define your presenter here
|
85
289
|
|
@@ -115,7 +319,7 @@ row_model = import_file.next
|
|
115
319
|
presenter = row_model.presenter
|
116
320
|
|
117
321
|
presenter.row_model # gets the row model underneath
|
118
|
-
|
322
|
+
presenter.project.name == presenter.row_model.name # => "Some Project Name"
|
119
323
|
```
|
120
324
|
|
121
325
|
The presenters are designed for another layer of validation---such as with the database.
|
@@ -127,70 +331,39 @@ Also, the `attribute` defines a dynamic `#project` method that:
|
|
127
331
|
3. Handles dependencies. When any of the dependencies are `invalid?`:
|
128
332
|
- The attribute block is not called and the attribute returns `nil`.
|
129
333
|
- `presenter.errors` for dependencies are cleaned. For the example above, if `row_model.id/name` are `invalid?`, then
|
130
|
-
the `:project` key is removed from the errors, so: `
|
131
|
-
|
132
|
-
## Children
|
334
|
+
the `:project` key is removed from the errors, so: `presenter.errors.keys # => [:id, :name]`
|
133
335
|
|
134
|
-
|
336
|
+
## Import Validations
|
135
337
|
|
136
|
-
|
137
|
-
|
138
|
-
include CsvRowModel::Model
|
139
|
-
include CsvRowModel::Import
|
338
|
+
Use [`ActiveModel::Validations`](http://api.rubyonrails.org/classes/ActiveModel/Validations.html) the `RowModel`'s [Layers](#layers).
|
339
|
+
Please read [Layers](#layers) for more information.
|
140
340
|
|
141
|
-
|
142
|
-
column :name
|
143
|
-
column :email
|
144
|
-
|
145
|
-
# uses ProjectImportRowModel#valid? to detect the child row
|
146
|
-
has_many :projects, ProjectImportRowModel
|
147
|
-
end
|
148
|
-
|
149
|
-
import_file = CsvRowModel::Import::File.new(file_path, UserImportRowModel)
|
150
|
-
row_model = import_file.next
|
151
|
-
row_model.projects # => [<ProjectImportRowModel>, ...]
|
152
|
-
```
|
341
|
+
Included is [`ActiveWarnings`](https://github.com/s12chung/active_warnings) on `Model` and `Presenter` for warnings.
|
153
342
|
|
154
|
-
## Column Options
|
155
|
-
### Default Attributes
|
156
|
-
For `Import`, `default_attributes` are calculated as thus:
|
157
|
-
- `format_cell`
|
158
|
-
- if `value_from_format_cell.blank?`, `default_lambda.call` or nil
|
159
|
-
- otherwise, `parse_lambda.call`
|
160
343
|
|
161
|
-
|
162
|
-
|
163
|
-
```ruby
|
164
|
-
class ProjectImportRowModel < ProjectRowModel
|
165
|
-
include CsvRowModel::Import
|
166
|
-
class << self
|
167
|
-
def format_cell(cell, column_name, column_index)
|
168
|
-
cell = cell.strip
|
169
|
-
cell.to_i.to_s == cell ? cell.to_i : cell
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
```
|
344
|
+
### Type Format
|
345
|
+
Notice that there are validators given for different types: `Boolean`, `Date`, `Float`, `Integer`:
|
174
346
|
|
175
|
-
#### Default
|
176
|
-
Called when `format_cell` is `value_from_format_cell.blank?`, it sets the default value of the cell:
|
177
347
|
```ruby
|
178
|
-
class ProjectImportRowModel
|
348
|
+
class ProjectImportRowModel
|
349
|
+
include CsvRowModel::Model
|
179
350
|
include CsvRowModel::Import
|
180
351
|
|
181
|
-
column :id,
|
182
|
-
column :name, default: -> { get_name }
|
352
|
+
column :id, type: Integer, validate_type: true
|
183
353
|
|
184
|
-
|
354
|
+
# the :validate_type option is the same as:
|
355
|
+
# csv_string_model do
|
356
|
+
# validates :id, integer_format: true, allow_blank: true
|
357
|
+
# end
|
185
358
|
end
|
186
|
-
row_model = ProjectImportRowModel.new(["", ""])
|
187
|
-
row_model.id # => 1
|
188
|
-
row_model.name # => "John Doe"
|
189
|
-
row_model.default_changes # => { id: ["", 1], name: ["", "John Doe"] }
|
190
359
|
|
360
|
+
ProjectRowModel.new(["not_a_number"])
|
361
|
+
row_model.valid? # => false
|
362
|
+
row_model.errors.full_messages # => ["Id is not a Integer format"]
|
191
363
|
```
|
192
364
|
|
193
|
-
|
365
|
+
### Default Changes
|
366
|
+
[Default Changes](#default) are tracked within [`ActiveWarnings`](https://github.com/s12chung/active_warnings).
|
194
367
|
|
195
368
|
```ruby
|
196
369
|
class ProjectImportRowModel
|
@@ -201,7 +374,6 @@ class ProjectImportRowModel
|
|
201
374
|
|
202
375
|
warnings do
|
203
376
|
validates :id, default_change: true
|
204
|
-
# validates :id, presence: true, works too. See ActiveWarnings gem for more.
|
205
377
|
end
|
206
378
|
end
|
207
379
|
|
@@ -210,101 +382,42 @@ row_model = ProjectImportRowModel.new([""])
|
|
210
382
|
row_model.unsafe? # => true
|
211
383
|
row_model.has_warnings? # => true, same as `#unsafe?`
|
212
384
|
row_model.warnings.full_messages # => ["Id changed by default"]
|
385
|
+
row_model.default_changes # => { id: ["", 1] }
|
213
386
|
```
|
214
387
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
```ruby
|
221
|
-
class ProjectImportRowModel < ProjectRowModel
|
222
|
-
include CsvRowModel::Import
|
223
|
-
|
224
|
-
column :id, type: Integer
|
225
|
-
column :name, parse: ->(original_string) { parse(original_string) }
|
226
|
-
|
227
|
-
def parse(original_string)
|
228
|
-
"#{id} - #{original_string}"
|
229
|
-
end
|
230
|
-
end
|
231
|
-
```
|
232
|
-
|
233
|
-
## Validations
|
234
|
-
|
235
|
-
Use [`ActiveModel::Validations`](http://api.rubyonrails.org/classes/ActiveModel/Validations.html)
|
236
|
-
on your `RowModel` or `Mapper`.
|
237
|
-
|
238
|
-
Included is [`ActiveWarnings`](https://github.com/s12chung/active_warnings) on `Model` and `Mapper` for warnings
|
239
|
-
(such as setting defaults), but not errors (which by default results in a skip).
|
240
|
-
|
241
|
-
`RowModel` has two validation layers on the `csv_string_model` (a model of `#mapped_row` with `::format_cell` applied) and itself:
|
388
|
+
### Skip and Abort
|
389
|
+
You can iterate through a file with the `#each` method, which calls `#next` internally.
|
390
|
+
`#next` will always return the next `RowModel` in the file. However, you can implement skips and
|
391
|
+
abort logic:
|
242
392
|
|
243
393
|
```ruby
|
244
|
-
class
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
column :id, type: Integer
|
249
|
-
|
250
|
-
# this is applied to the parsed CSV on the model
|
251
|
-
validates :id, numericality: { greater_than: 0 }
|
252
|
-
|
253
|
-
csv_string_model do
|
254
|
-
# this is applied before the parsed CSV on csv_string_model
|
255
|
-
validates :id, integer_format: true, allow_blank: true
|
394
|
+
class ProjectImportRowModel
|
395
|
+
# always skip
|
396
|
+
def skip?
|
397
|
+
true # original implementation: !valid? || presenter.skip?
|
256
398
|
end
|
257
399
|
end
|
258
400
|
|
259
|
-
|
260
|
-
|
261
|
-
row_model.valid? # => false
|
262
|
-
row_model.errors.full_messages # => ["Id is not a Integer format"]
|
263
|
-
|
264
|
-
# Applied to the parsed Integer
|
265
|
-
row_model = ProjectRowModel.new(["-1"])
|
266
|
-
row_model.valid? # => false
|
267
|
-
row_model.errors.full_messages # => ["Id must be greater than 0"]
|
268
|
-
```
|
269
|
-
|
270
|
-
Notice that there are validators given for different types: `Boolean`, `Date`, `Float`, `Integer`:
|
271
|
-
|
272
|
-
```ruby
|
273
|
-
class ProjectRowModel
|
274
|
-
include CsvRowModel::Model
|
275
|
-
|
276
|
-
# the :validate_type option does the commented code below.
|
277
|
-
column :id, type: Integer, validate_type: true
|
278
|
-
|
279
|
-
# csv_string_model do
|
280
|
-
# validates :id, integer_format: true, allow_blank: true
|
281
|
-
# end
|
401
|
+
CsvRowModel::Import::File.new(file_path, ProjectImportRowModel).each do |project_import_model|
|
402
|
+
# never yields here
|
282
403
|
end
|
283
404
|
```
|
284
405
|
|
285
|
-
|
286
|
-
## Callbacks
|
406
|
+
### Import Callbacks
|
287
407
|
`CsvRowModel::Import::File` can be subclassed to access
|
288
408
|
[`ActiveModel::Callbacks`](http://api.rubyonrails.org/classes/ActiveModel/Callbacks.html).
|
289
409
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
end
|
295
|
-
```
|
296
|
-
|
297
|
-
Within `#each`, **Skips** and **Aborts** will be done via the `skip?` or `abort?` method on the row model,
|
298
|
-
allowing the following callbacks:
|
299
|
-
|
300
|
-
* yield - `before`, `around`, or `after` the iteration yield
|
410
|
+
* each_iteration - `before`, `around`, or `after` the an iteration on `#each`.
|
411
|
+
Use this to handle exceptions. `return` and `break` may be called within the callback for
|
412
|
+
skips and aborts.
|
413
|
+
* next - `before`, `around`, or `after` each change in `current_row_model`
|
301
414
|
* skip - `before`
|
302
415
|
* abort - `before`
|
303
416
|
|
304
417
|
and implement the callbacks:
|
305
418
|
```ruby
|
306
419
|
class ImportFile < CsvRowModel::Import::File
|
307
|
-
|
420
|
+
around_each_iteration :logger_track
|
308
421
|
before_skip :track_skip
|
309
422
|
|
310
423
|
def logger_track(&block)
|
@@ -315,55 +428,4 @@ class ImportFile < CsvRowModel::Import::File
|
|
315
428
|
...
|
316
429
|
end
|
317
430
|
end
|
318
|
-
```
|
319
|
-
|
320
|
-
### Export RowModel
|
321
|
-
|
322
|
-
Maps each attribute of the `RowModel` to a column of a CSV row.
|
323
|
-
|
324
|
-
```ruby
|
325
|
-
class ProjectExportRowModel < ProjectRowModel
|
326
|
-
include CsvRowModel::Export
|
327
|
-
|
328
|
-
# Optionally it's possible to override the attribute method, by default it
|
329
|
-
# does source_model.public_send(attribute)
|
330
|
-
def name
|
331
|
-
"#{source_model.id} - #{source_model.name}"
|
332
|
-
end
|
333
|
-
end
|
334
|
-
```
|
335
|
-
|
336
|
-
### Export SingleModel
|
337
|
-
|
338
|
-
Maps each attribute of the `RowModel` to a row on the CSV.
|
339
|
-
|
340
|
-
```ruby
|
341
|
-
class ProjectExportRowModel < ProjectRowModel
|
342
|
-
include CsvRowModel::Export
|
343
|
-
include CsvRowModel::Export::SingleModel
|
344
|
-
|
345
|
-
|
346
|
-
end
|
347
|
-
```
|
348
|
-
|
349
|
-
And to export:
|
350
|
-
|
351
|
-
```ruby
|
352
|
-
export_csv = CsvRowModel::Export::Csv.new(ProjectExportRowModel)
|
353
|
-
csv_string = export_csv.generate do |csv|
|
354
|
-
csv.append_model(project) #optional you can pass a context
|
355
|
-
end
|
356
|
-
```
|
357
|
-
|
358
|
-
#### Format Header
|
359
|
-
Override the `format_header` method to format column header names:
|
360
|
-
```ruby
|
361
|
-
class ProjectExportRowModel < ProjectRowModel
|
362
|
-
include CsvRowModel::Export
|
363
|
-
class << self
|
364
|
-
def format_header(column_name)
|
365
|
-
column_name.to_s.titleize
|
366
|
-
end
|
367
|
-
end
|
368
|
-
end
|
369
431
|
```
|