csv_row_model 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
```
|