planter 0.0.13 → 0.1.2
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 +8 -7
- data/lib/planter/seeder.rb +122 -151
- data/lib/planter/version.rb +2 -2
- metadata +4 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39fe6b05679379fdcf8c619b1db28fdac6a6f89eec521b3e8cf3f3667a471c49
|
4
|
+
data.tar.gz: 42693cdccc9239a069996c74455edc658b339a894eff5b984ec00bba47a88797
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3ffd760187e67c1f57b7daf7a1bba7f019470f1324ddaf72d1412c34930ea520eea449aebd0cea43b6b48de948f93ba80f47bafe6de782f550c35daf0bb8508
|
7
|
+
data.tar.gz: cfd8daff8e7d45a9d72411c195b31be7d1ddde9b562a03397b43f0848360c701d569289ab32e3260bf03f765752cd81fa123f3b597d9b08cc69ac9a6cab7bb6f
|
data/README.md
CHANGED
@@ -144,8 +144,8 @@ class UsersSeeder < Planter::Seeder
|
|
144
144
|
end
|
145
145
|
```
|
146
146
|
|
147
|
-
`ERB` can be used in the CSV files if you end the file name with `.csv.erb
|
148
|
-
For example, `users.csv.erb`.
|
147
|
+
`ERB` can be used in the CSV files if you end the file name with `.csv.erb` or
|
148
|
+
`.erb.csv`. For example, `users.csv.erb`.
|
149
149
|
|
150
150
|
```
|
151
151
|
participant_id,name
|
@@ -207,13 +207,16 @@ Running `rails planter:seed` should now seed your `users` table.
|
|
207
207
|
|
208
208
|
You can also seed children records for every existing record of a parent model.
|
209
209
|
For example, to seed an address for every user, you'd need to create an
|
210
|
-
`AddressesSeeder` that uses the `
|
210
|
+
`AddressesSeeder` that uses the `parent` option, as seen below. This option
|
211
|
+
should be the name of the `belongs_to` association in your model. The primary
|
212
|
+
key, foreign key, and model name of the parent will all be determined by
|
213
|
+
reflecting on the association.
|
211
214
|
|
212
215
|
```ruby
|
213
216
|
require 'faker'
|
214
217
|
|
215
218
|
class AddressesSeeder < Planter::Seeder
|
216
|
-
seeding_method :data_array,
|
219
|
+
seeding_method :data_array, parent: :user
|
217
220
|
|
218
221
|
def data
|
219
222
|
[{
|
@@ -227,9 +230,7 @@ end
|
|
227
230
|
```
|
228
231
|
|
229
232
|
Note that specifying `number_of_records` in this instance will create that many
|
230
|
-
records *for each record of the parent model*.
|
231
|
-
association if it's different from the table name, using the `:assocation`
|
232
|
-
option.
|
233
|
+
records *for each record of the parent model*.
|
233
234
|
|
234
235
|
### Custom seeds
|
235
236
|
To write your own custom seeds, just overload the `seed` method and do whatever
|
data/lib/planter/seeder.rb
CHANGED
@@ -26,7 +26,7 @@ module Planter
|
|
26
26
|
# Another way to seed is to create records from a data array. To do this,
|
27
27
|
# your class must implement a +data+ attribute or method, which is an array
|
28
28
|
# of hashes. Note that this class already provides the +attr_reader+ for this
|
29
|
-
# attribute, so the most you have to do
|
29
|
+
# attribute, so the most you have to do is create instance variables in your
|
30
30
|
# constructor. If if you want your data to be different for each new record
|
31
31
|
# (via Faker, +Array#sample+, etc.), you'll probably want to supply a method
|
32
32
|
# called data that returns an array of new data each time.
|
@@ -38,15 +38,17 @@ module Planter
|
|
38
38
|
# end
|
39
39
|
# end
|
40
40
|
#
|
41
|
-
# In both of the above methods, you can specify +
|
42
|
-
# +association
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
41
|
+
# In both of the above methods, you can specify a +parent+ association, which
|
42
|
+
# is the +belongs_to+ association name in your model, which, when specified,
|
43
|
+
# records will be created for each record in the parent table. For example,
|
44
|
+
# if we're seeding the users table, and the model is +User+, which belongs to
|
45
|
+
# +Person+, then doing the following will create a user record for each
|
46
|
+
# record in the Person table. Note that nothing is automatically done to
|
47
|
+
# prevent any validation errors; you must do this on your own, mostly likely
|
48
|
+
# using +Faker+ or a similar library.
|
47
49
|
# require 'planter'
|
48
50
|
# class UsersSeeder < Planter::Seeder
|
49
|
-
# seeding_method :data_array,
|
51
|
+
# seeding_method :data_array, parent: :person
|
50
52
|
# def data
|
51
53
|
# [{foo: 'bar', baz: 'bar'}]
|
52
54
|
# end
|
@@ -54,9 +56,8 @@ module Planter
|
|
54
56
|
#
|
55
57
|
# You can also set +number_of_records+ to determine how many times each
|
56
58
|
# record in the +data+ array will get created. The default is 1. Note that if
|
57
|
-
# this attribute is set alongside +
|
58
|
-
#
|
59
|
-
# record in the parent table.
|
59
|
+
# this attribute is set alongside +parent+, +number_of_records+ will be how
|
60
|
+
# many records will be created for each record in the parent table.
|
60
61
|
# require 'planter'
|
61
62
|
# class UsersSeeder < Planter::Seeder
|
62
63
|
# seeding_method :data_array, number_of_records: 5
|
@@ -127,7 +128,7 @@ module Planter
|
|
127
128
|
# class must set this attribute via +seeding_method+.
|
128
129
|
#
|
129
130
|
# @return [String]
|
130
|
-
class_attribute :
|
131
|
+
class_attribute :parent
|
131
132
|
|
132
133
|
##
|
133
134
|
# The number of records to create from each record in the +data+ array. If
|
@@ -137,116 +138,72 @@ module Planter
|
|
137
138
|
# @return [Integer]
|
138
139
|
class_attribute :number_of_records
|
139
140
|
|
140
|
-
##
|
141
|
-
# When using +parent_model+, the association name. Your class can set this
|
142
|
-
# attribute via +seeding_method+.
|
143
|
-
#
|
144
|
-
# @return [Symbol]
|
145
|
-
class_attribute :association
|
146
|
-
|
147
141
|
##
|
148
142
|
# The csv file corresponding to the model.
|
149
143
|
#
|
150
144
|
# @return [String]
|
151
|
-
class_attribute :
|
145
|
+
class_attribute :csv_name
|
152
146
|
|
153
147
|
##
|
154
148
|
# The seeding method specified.
|
155
149
|
#
|
156
150
|
# @return [Symbol]
|
157
|
-
class_attribute :
|
151
|
+
class_attribute :seed_method
|
158
152
|
|
159
153
|
##
|
160
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
association: nil,
|
201
|
-
csv_name: nil,
|
202
|
-
unique_columns: nil,
|
203
|
-
erb_trim_mode: nil
|
204
|
-
)
|
205
|
-
if !SEEDING_METHODS.include?(method.intern)
|
206
|
-
raise ArgumentError, "Method must be: #{SEEDING_METHODS.join(', ')}"
|
207
|
-
elsif association && !parent_model
|
208
|
-
raise ArgumentError, "Must specify :parent_model with :association"
|
209
|
-
end
|
210
|
-
|
211
|
-
self.seeding_method = method
|
212
|
-
self.number_of_records = number_of_records
|
213
|
-
self.model = model || to_s.delete_suffix('Seeder').singularize
|
214
|
-
self.parent_model = parent_model
|
215
|
-
self.association = parent_model && (association || determine_association)
|
216
|
-
self.csv_file = determine_csv_filename(csv_name) if seeding_method == :csv
|
217
|
-
self.erb_trim_mode = erb_trim_mode || Planter.config.erb_trim_mode
|
218
|
-
self.unique_columns =
|
219
|
-
case unique_columns
|
220
|
-
when String, Symbol then [unique_columns.intern]
|
221
|
-
when Array then unique_columns.map(&:intern)
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
private
|
226
|
-
|
227
|
-
def determine_association # :nodoc:
|
228
|
-
associations =
|
229
|
-
parent_model.constantize.reflect_on_all_associations.map(&:name)
|
230
|
-
table = to_s.delete_suffix('Seeder').underscore.split('/').last
|
231
|
-
|
232
|
-
[table, table.singularize].map(&:intern).each do |t|
|
233
|
-
return t if associations.include?(t)
|
234
|
-
end
|
235
|
-
|
236
|
-
raise ArgumentError, "Couldn't determine association name"
|
154
|
+
# If your class is going to use the inherited +seed+ method, you must tell
|
155
|
+
# it which +seeding_method+ to use. The argument to this method must be
|
156
|
+
# included in the +SEEDING_METHODS+ array.
|
157
|
+
#
|
158
|
+
# @param [Symbol] seed_method
|
159
|
+
#
|
160
|
+
# @kwarg [Integer] number_of_records
|
161
|
+
#
|
162
|
+
# @kwarg [String] model
|
163
|
+
#
|
164
|
+
# @kwarg [Symbol, String] parent
|
165
|
+
#
|
166
|
+
# @kwarg [Symbol, String] csv_name
|
167
|
+
#
|
168
|
+
# @kwarg [Symbol, String] unique_columns
|
169
|
+
#
|
170
|
+
# @kwarg [String] erb_trim_mode
|
171
|
+
#
|
172
|
+
# @example
|
173
|
+
# require 'planter'
|
174
|
+
# class UsersSeeder < Planter::Seeder
|
175
|
+
# seeding_method :csv,
|
176
|
+
# number_of_records: 2,
|
177
|
+
# model: 'User'
|
178
|
+
# parent: :person,
|
179
|
+
# csv_name: :awesome_users,
|
180
|
+
# unique_columns %i[username email],
|
181
|
+
# erb_trim_mode: '<>'
|
182
|
+
# end
|
183
|
+
def self.seeding_method(
|
184
|
+
seed_method,
|
185
|
+
number_of_records: 1,
|
186
|
+
model: nil,
|
187
|
+
parent: nil,
|
188
|
+
csv_name: nil,
|
189
|
+
unique_columns: nil,
|
190
|
+
erb_trim_mode: nil
|
191
|
+
)
|
192
|
+
if !SEEDING_METHODS.include?(seed_method.intern)
|
193
|
+
raise ArgumentError, "Method must be: #{SEEDING_METHODS.join(', ')}"
|
237
194
|
end
|
238
195
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
196
|
+
self.seed_method = seed_method
|
197
|
+
self.number_of_records = number_of_records
|
198
|
+
self.model = model || to_s.delete_suffix('Seeder').singularize
|
199
|
+
self.parent = parent
|
200
|
+
self.csv_name = csv_name || to_s.delete_suffix('Seeder').underscore
|
201
|
+
self.erb_trim_mode = erb_trim_mode || Planter.config.erb_trim_mode
|
202
|
+
self.unique_columns =
|
203
|
+
case unique_columns
|
204
|
+
when String, Symbol then [unique_columns.intern]
|
205
|
+
when Array then unique_columns.map(&:intern)
|
246
206
|
end
|
247
|
-
|
248
|
-
raise ArgumentError, "Couldn't find csv for #{model}"
|
249
|
-
end
|
250
207
|
end
|
251
208
|
|
252
209
|
##
|
@@ -254,8 +211,9 @@ module Planter
|
|
254
211
|
# valid +seeding_method+, and not implement its own +seed+ method.
|
255
212
|
def seed
|
256
213
|
validate_attributes
|
214
|
+
extract_data_from_csv if seed_method == :csv
|
257
215
|
|
258
|
-
|
216
|
+
parent ? create_records_from_parent : create_records
|
259
217
|
end
|
260
218
|
|
261
219
|
protected
|
@@ -263,69 +221,82 @@ module Planter
|
|
263
221
|
##
|
264
222
|
# Creates records from the +data+ attribute.
|
265
223
|
def create_records
|
266
|
-
data.each
|
267
|
-
number_of_records.times do
|
268
|
-
rec.transform_values { |value| value == 'NULL' ? nil : value }
|
269
|
-
unique, attrs = split_record(rec)
|
270
|
-
model.constantize.where(unique).first_or_create!(attrs)
|
271
|
-
end
|
272
|
-
end
|
224
|
+
data.each { |record| create_record(record) }
|
273
225
|
end
|
274
226
|
|
275
227
|
##
|
276
|
-
# Create records from the +data+ attribute for each record in the
|
277
|
-
# +parent_table+, via the specified +association+.
|
228
|
+
# Create records from the +data+ attribute for each record in the +parent+.
|
278
229
|
def create_records_from_parent
|
279
|
-
parent_model.constantize.
|
280
|
-
|
281
|
-
data.each { |rec| send(create_method, assoc_rec, association, rec) }
|
282
|
-
end
|
230
|
+
parent_model.constantize.pluck(primary_key).each do |parent_id|
|
231
|
+
data.each { |record| create_record(record, parent_id: parent_id) }
|
283
232
|
end
|
284
233
|
end
|
285
234
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
end
|
293
|
-
|
294
|
-
def create_has_many(assoc_rec, association, rec) # :nodoc:
|
295
|
-
unique, attrs = split_record(rec)
|
296
|
-
assoc_rec.public_send(association).where(unique).first_or_create!(attrs)
|
297
|
-
end
|
298
|
-
|
299
|
-
def create_has_one(assoc_rec, association, rec) # :nodoc:
|
300
|
-
if assoc_rec.public_send(association)
|
301
|
-
assoc_rec.public_send(association).update_attributes(rec)
|
302
|
-
else
|
303
|
-
assoc_rec.public_send("create_#{association}", rec)
|
235
|
+
def create_record(record, parent_id: nil)
|
236
|
+
number_of_records.times do
|
237
|
+
unique, attrs = split_record(record)
|
238
|
+
model.constantize.where(
|
239
|
+
unique.tap { |u| u[foreign_key] = parent_id if parent_id }
|
240
|
+
).first_or_create!(attrs)
|
304
241
|
end
|
305
242
|
end
|
306
243
|
|
307
244
|
def validate_attributes # :nodoc:
|
308
|
-
case
|
245
|
+
case seed_method.intern
|
309
246
|
when :csv
|
310
|
-
|
311
|
-
if csv_file.end_with?('.erb')
|
312
|
-
contents = ERB.new(contents, trim_mode: erb_trim_mode).result(binding)
|
313
|
-
end
|
314
|
-
|
315
|
-
@data ||= ::CSV.parse(
|
316
|
-
contents, headers: true, header_converters: :symbol
|
317
|
-
).map(&:to_hash)
|
247
|
+
raise "Couldn't find csv for #{model}" unless full_csv_name
|
318
248
|
when :data_array
|
319
|
-
raise
|
249
|
+
raise 'data is not defined in the seeder' if public_send(:data).nil?
|
320
250
|
else
|
321
|
-
raise
|
251
|
+
raise 'seeding_method not defined in the seeder'
|
322
252
|
end
|
323
253
|
end
|
324
254
|
|
325
255
|
def split_record(rec) # :nodoc:
|
326
256
|
return [rec, {}] unless unique_columns
|
257
|
+
|
327
258
|
u = unique_columns.each_with_object({}) { |c, h| h[c] = rec.delete(c) }
|
328
259
|
[u, rec]
|
329
260
|
end
|
261
|
+
|
262
|
+
def association_options
|
263
|
+
@association_options ||=
|
264
|
+
model.constantize.reflect_on_association(parent).options
|
265
|
+
end
|
266
|
+
|
267
|
+
def primary_key
|
268
|
+
@primary_key ||=
|
269
|
+
association_options.fetch(:primary_key, :id)
|
270
|
+
end
|
271
|
+
|
272
|
+
def foreign_key
|
273
|
+
@foreign_key ||=
|
274
|
+
association_options.fetch(:foreign_key, "#{parent}_id")
|
275
|
+
end
|
276
|
+
|
277
|
+
def parent_model
|
278
|
+
@parent_model ||=
|
279
|
+
association_options.fetch(:class_name, parent.to_s.classify)
|
280
|
+
end
|
281
|
+
|
282
|
+
def full_csv_name
|
283
|
+
@full_csv_name ||=
|
284
|
+
%W[#{csv_name}.csv #{csv_name}.csv.erb #{csv_name}.erb.csv]
|
285
|
+
.map { |f| Rails.root.join(Planter.config.csv_files_directory, f).to_s }
|
286
|
+
.find { |f| ::File.file?(f) }
|
287
|
+
end
|
288
|
+
|
289
|
+
def extract_data_from_csv
|
290
|
+
contents = ::File.read(full_csv_name)
|
291
|
+
if full_csv_name.include?('.erb')
|
292
|
+
contents = ERB.new(contents, trim_mode: erb_trim_mode).result(binding)
|
293
|
+
end
|
294
|
+
|
295
|
+
@data ||= ::CSV.parse(
|
296
|
+
contents,
|
297
|
+
headers: true,
|
298
|
+
header_converters: :symbol
|
299
|
+
).map(&:to_hash)
|
300
|
+
end
|
330
301
|
end
|
331
302
|
end
|
data/lib/planter/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: planter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Gray
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,20 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 6.1.
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 6.1.3.1
|
19
|
+
version: 6.1.4.4
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: 6.1.
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 6.1.3.1
|
26
|
+
version: 6.1.4.4
|
33
27
|
description: Create a seeder for each table in your database, and easily seed from
|
34
28
|
CSV or custom methods
|
35
29
|
email:
|