planter 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +201 -0
- data/Rakefile +18 -0
- data/lib/planter.rb +122 -0
- data/lib/planter/config.rb +53 -0
- data/lib/planter/railtie.rb +6 -0
- data/lib/planter/seeder.rb +195 -0
- data/lib/planter/version.rb +7 -0
- data/lib/tasks/planter_tasks.rake +4 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fe6195656eb33a7e774e6f5fb37e6f1dbcf6d7be33230c97605f291201d04de0
|
4
|
+
data.tar.gz: 68e04cc88dde75734fd06b69e0fd783f8f1849cb9d7f6e73fd33c18814cb1c61
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dbcea200bc37aa0d691cc001a918bcafea73a6c37754f83dea3f56867c4cb0773f474d276477c71081c03a5cc83d592b5ff511e745005e3bb17919436943b33a
|
7
|
+
data.tar.gz: 26f4beb0e5613aedbb6308bcad145a5cd39c20f328fbfa6fb7db0f6bb588128c6c031c014ef00a61d519f246e89eea9e14b05d4126a990fca7235349a9615c9f
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2021 Evan Gray
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
# Planter
|
2
|
+
> Pre-release version! Anything is subject to change in the near future!
|
3
|
+
|
4
|
+
Seeds for Rails applications can get complicated fast, and Rails doesn't provide
|
5
|
+
much for assisting with this process. This plugin seeks to rectify that by
|
6
|
+
providing easy ways to seed specific tables by hooking into the existing `rails
|
7
|
+
db:seed` task.
|
8
|
+
|
9
|
+
Features include:
|
10
|
+
|
11
|
+
- Seed tables from CSV files, an array of hashes, or custom methods.
|
12
|
+
- Seed specific tables with `rails db:seed TABLES=users,addresses`.
|
13
|
+
- Control the number of records being created.
|
14
|
+
- Seed associations.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'planter'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
$ bundle
|
27
|
+
```
|
28
|
+
|
29
|
+
Or install it yourself as:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
$ gem install planter
|
33
|
+
```
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
Let's assume you'd like to seed your `users` table.
|
37
|
+
|
38
|
+
To get started, simply add the following to your `db/seeds.rb` file. Note that
|
39
|
+
the `config.tables` should be an array of the tables to seed. They should be in
|
40
|
+
the correct order to successfully seed the tables when considering associations.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
require 'planter'
|
44
|
+
|
45
|
+
Planter.configure do |config|
|
46
|
+
config.tables = %i[ users ]
|
47
|
+
end
|
48
|
+
|
49
|
+
Planter.seed
|
50
|
+
```
|
51
|
+
|
52
|
+
Then, create a directory called `db/seeds`, and create a file called
|
53
|
+
`db/seeds/users_seeder.rb`. In that file, create the following class. Note the
|
54
|
+
name of the seeder is the name of the table, plus `Seeder`, and it inherits from
|
55
|
+
`Planter::Seeder`.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class UsersSeeder < Planter::Seeder
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
You then need to choose a seeding method, of which there are currently three.
|
63
|
+
|
64
|
+
### Seeding from CSV
|
65
|
+
To seed from CSV, you simply need to add the following to your seeder class.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class UsersSeeder < Planter::Seeder
|
69
|
+
seeding_method :standard_csv
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
Then, create a directory called `db/seed_files`, and create a csv file called
|
74
|
+
`db/seed_files/users.csv`. In this file, the header should be the field names,
|
75
|
+
and the rest of the rows should be the corresponding data.
|
76
|
+
|
77
|
+
```
|
78
|
+
email,username
|
79
|
+
test1@example.com,test1
|
80
|
+
test2@example.com,test2
|
81
|
+
```
|
82
|
+
|
83
|
+
If the CSV files are not located in the project, you can specify a `:csv_file`
|
84
|
+
option. Note that the value must be a full path.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
class UsersSeeder < Planter::Seeder
|
88
|
+
seeding_method :standard_csv, csv_file: '/home/me/users.csv'
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
Running `rails db:seed` will now seed your `users` table.
|
93
|
+
|
94
|
+
## Seeding from a data array
|
95
|
+
If you need dynamic seeds, you can add something similar to the following to
|
96
|
+
your seeder class. In this example, we'll use
|
97
|
+
[faker](https://github.com/faker-ruby/faker).
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
require 'faker' # You should really just require this in `db/seeds.rb`.
|
101
|
+
|
102
|
+
class UsersSeeder < Planter::Seeder
|
103
|
+
seeding_method :data_array, number_of_records: 10
|
104
|
+
|
105
|
+
def data
|
106
|
+
[{
|
107
|
+
email: Faker::Internet.email,
|
108
|
+
username: Faker::Name.name
|
109
|
+
}]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
The `number_of_records` option allows you to only create one array element, but
|
115
|
+
create ten records. If you leave this option off, you'll need your array to have
|
116
|
+
ten elements to create ten records. It's also worth noting that setting an
|
117
|
+
instance variable called `@data` from an `initialize` method would also work, as
|
118
|
+
the `Planter::Seeder` parent class automatically provides `attr_reader :data`.
|
119
|
+
|
120
|
+
Running `rails db:seed` should now seed your `users` table.
|
121
|
+
|
122
|
+
You can also seed children records for every existing record of a parent model.
|
123
|
+
For example, to seed an address for every user, you'd need to create an
|
124
|
+
`AddressesSeeder` that uses the `parent_model` option, as seen below.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
require 'faker'
|
128
|
+
|
129
|
+
class AddressesSeeder < Planter::Seeder
|
130
|
+
seeding_method :data_array, parent_model: 'User'
|
131
|
+
|
132
|
+
def data
|
133
|
+
[{
|
134
|
+
street: Faker::Address.street_address,
|
135
|
+
city: Faker::Address.city,
|
136
|
+
state: Faker::Address.state_abbr,
|
137
|
+
zip: Faker::Address.zip
|
138
|
+
}]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
Note that specifying `number_of_records` in this instance will create that many
|
144
|
+
records *for each record of the parent model*. You can also specify the
|
145
|
+
association if it's different from the table name, using the `assocation:`
|
146
|
+
option. Currently, associations are assumed to be as `has_many`, so the
|
147
|
+
association is plural by default. Any help with making this more heuristically
|
148
|
+
complete would be welcome.
|
149
|
+
|
150
|
+
### Custom seeds
|
151
|
+
To write your own custom seeds, just overload the `seed` method and do whatever
|
152
|
+
you need to do.
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
class UsersSeeder < Planter::Seeder
|
156
|
+
USERS = {
|
157
|
+
'test1@example.com' => { username: 'John Smith' }
|
158
|
+
'test2@example.com' => { username: 'Jane Smith' }
|
159
|
+
}
|
160
|
+
|
161
|
+
def seed
|
162
|
+
USERS.each { |email, attrs| User.where(email).first_or_create!(attrs) }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
## Customization
|
168
|
+
You can change the directories of both the seeder files and the csv files. In
|
169
|
+
your `configure` block in `db/seeds.rb`, you can add the following. Note that,
|
170
|
+
in both instances, the path should be relative to `Rails.root`.
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
require 'planter'
|
174
|
+
|
175
|
+
Planter.configure do |config|
|
176
|
+
config.seeders_directory = 'db/seeder_classes'
|
177
|
+
config.csv_files_directory = 'db/csvs'
|
178
|
+
config.tables = %i[
|
179
|
+
users
|
180
|
+
addresses
|
181
|
+
]
|
182
|
+
end
|
183
|
+
|
184
|
+
Planter.seed
|
185
|
+
```
|
186
|
+
|
187
|
+
## License
|
188
|
+
The gem is available as open source under the terms of the [MIT
|
189
|
+
License](https://opensource.org/licenses/MIT).
|
190
|
+
|
191
|
+
## Reporting Bugs and Requesting Features
|
192
|
+
If you have an idea or find a bug, please [create an
|
193
|
+
issue](https://github.com/evanthegrayt/planter/issues/new). Just make sure
|
194
|
+
the topic doesn't already exist. Better yet, you can always submit a Pull
|
195
|
+
Request.
|
196
|
+
|
197
|
+
## Self-Promotion
|
198
|
+
I do these projects for fun, and I enjoy knowing that they're helpful to people.
|
199
|
+
Consider starring [the repository](https://github.com/evanthegrayt/planter)
|
200
|
+
if you like it! If you love it, follow me [on
|
201
|
+
Github](https://github.com/evanthegrayt)!
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.pattern = 'test/**/*_test.rb'
|
9
|
+
t.verbose = false
|
10
|
+
end
|
11
|
+
|
12
|
+
RDoc::Task.new do |rdoc|
|
13
|
+
rdoc.main = 'README.md'
|
14
|
+
rdoc.rdoc_dir = 'doc'
|
15
|
+
rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
task default: :test
|
data/lib/planter.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'csv'
|
4
|
+
require 'planter/version'
|
5
|
+
require 'planter/railtie'
|
6
|
+
require 'planter/config'
|
7
|
+
require 'planter/seeder'
|
8
|
+
|
9
|
+
##
|
10
|
+
# Class that seeders should inherit from. Seeder files should be in +db/seeds+,
|
11
|
+
# and named +TABLE_seeder.rb+, where +TABLE+ is the name of the table being
|
12
|
+
# seeded (I.E. +users_seeder.rb+). The seeder's class name should be the same
|
13
|
+
# as the file name, but camelized. So, +UsersSeeder+. The directory where the
|
14
|
+
# seeder files are located can be changed via an initializer.
|
15
|
+
#
|
16
|
+
# The most basic way to seed is to have a CSV file with the same name as the
|
17
|
+
# table in +db/seed_files/+. So, +users.csv+. This CSV should have the table's
|
18
|
+
# column names as header. To seed using this method, your class should look
|
19
|
+
# like the following. Note that +:csv_file+ is not required; it defaults to the
|
20
|
+
# table name with a +csv+ file extension. The directory where the seed files
|
21
|
+
# are kept can be changed via an initializer.
|
22
|
+
# # db/seeds/users_seeder.rb
|
23
|
+
# require 'planter'
|
24
|
+
# class UsersSeeder < Planter::Seeder
|
25
|
+
# seeding_method :standard_csv, csv_file: '/home/me/users.csv'
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# Another way to seed is to create records from a data array. To do this, your
|
29
|
+
# class must implement a +data+ attribute or method, which is an array of
|
30
|
+
# hashes. Note that this class already provides the +attr_reader+ for this
|
31
|
+
# attribute, so the most you have to do it create instance variables in your
|
32
|
+
# constructor. If if you want your data to be different for each new record
|
33
|
+
# (via Faker, +Array#sample+, etc.), you'll probably want to supply a method
|
34
|
+
# called data that returns an array of new data each time.
|
35
|
+
# require 'planter'
|
36
|
+
# class UsersSeeder < Planter::Seeder
|
37
|
+
# seeding_method :data_array
|
38
|
+
# def data
|
39
|
+
# [{foo: 'bar', baz: 'bar'}]
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# In both of the above methods, you can specify +parent_model+ and
|
44
|
+
# +association+. If specified, records will be created via that parent model's
|
45
|
+
# association. If +association+ is not provided, it will be assumed to be the
|
46
|
+
# model name, pluralized and snake-cased (implying a +has_many+ relationship).
|
47
|
+
# For example, if we're seeding the users table, and the model is +User+, the
|
48
|
+
# association will default to +users+.
|
49
|
+
# require 'planter'
|
50
|
+
# class UsersSeeder < Planter::Seeder
|
51
|
+
# seeding_method :data_array, parent_model: 'Person', association: :users
|
52
|
+
# def data
|
53
|
+
# [{foo: 'bar', baz: 'bar'}]
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# You can also set +number_of_records+ to determine how many times each record
|
58
|
+
# in the +data+ array will get created. The default is 1. Note that if this
|
59
|
+
# attribute is set alongside +parent_model+ and +association+,
|
60
|
+
# +number_of_records+ will be how many records will be created for each record
|
61
|
+
# in the parent table.
|
62
|
+
# require 'planter'
|
63
|
+
# class UsersSeeder < Planter::Seeder
|
64
|
+
# seeding_method :data_array, number_of_records: 5
|
65
|
+
# def data
|
66
|
+
# [{foo: 'bar', baz: 'bar'}]
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# If you need to seed a different way, put your own custom +seed+ method in
|
71
|
+
# your seeder class and do whatever needs to be done.
|
72
|
+
module Planter
|
73
|
+
##
|
74
|
+
# The seeder configuration.
|
75
|
+
#
|
76
|
+
# @return [Planter::Config]
|
77
|
+
def self.config
|
78
|
+
@config ||= Planter::Config.new
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Resets the config back to its initial state.
|
83
|
+
#
|
84
|
+
# @return [Planter::Config]
|
85
|
+
def self.reset_config
|
86
|
+
@config = Planter::Config.new
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Quick way of configuring the directories via an initializer.
|
91
|
+
#
|
92
|
+
# @return [self]
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# Planter.configure do |app_seeder|
|
96
|
+
# app_seeder.tables = %i[users]
|
97
|
+
# app_seeder.seeders_directory = 'db/seeds'
|
98
|
+
# app_seeder.csv_files_directory = 'db/seed_files'
|
99
|
+
# end
|
100
|
+
def self.configure
|
101
|
+
config.tap { |c| yield c }
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# This is the method to call from your +db/seeds.rb+. It seeds the tables
|
106
|
+
# listed in +Planter.config.tables+. To seed specific tables at
|
107
|
+
# runtime, you can set the +TABLES+ environmental variable to a
|
108
|
+
# comma-separated list of tables.
|
109
|
+
#
|
110
|
+
# @example
|
111
|
+
# rails db:seed TABLES=users,accounts
|
112
|
+
def self.seed
|
113
|
+
tables = ENV['TABLES']&.split(',') || config.tables&.map(&:to_s)
|
114
|
+
raise RuntimeError, 'No tables specified; nothing to do' unless tables&.any?
|
115
|
+
|
116
|
+
tables.each do |table|
|
117
|
+
require Rails.root.join(config.seeders_directory, "#{table}_seeder.rb").to_s
|
118
|
+
puts "Seeding #{table}" unless config.quiet
|
119
|
+
"#{table.camelize}Seeder".constantize.new.seed
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Planter
|
4
|
+
##
|
5
|
+
# Configure the application seeder.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# Planter.configure { |seeder| seeder.tables = %i[users] }
|
9
|
+
class Config
|
10
|
+
##
|
11
|
+
# Tell the application where the seeder classes are kept. Must be a path
|
12
|
+
# relative to +Rails.root+.
|
13
|
+
#
|
14
|
+
# @param [String] directory
|
15
|
+
#
|
16
|
+
# @return [String]
|
17
|
+
attr_accessor :seeders_directory
|
18
|
+
|
19
|
+
##
|
20
|
+
# Tell the application where the CSV seed files are kept. Must be a path
|
21
|
+
# relative to +Rails.root+.
|
22
|
+
#
|
23
|
+
# @param [String] directory
|
24
|
+
#
|
25
|
+
# @return [String]
|
26
|
+
attr_accessor :csv_files_directory
|
27
|
+
|
28
|
+
##
|
29
|
+
# Tell the application what tables to seed. Elements should be in the correct
|
30
|
+
# order, and can be strings or symbols.
|
31
|
+
#
|
32
|
+
# @param [Array] tables
|
33
|
+
#
|
34
|
+
# @return [Array]
|
35
|
+
attr_accessor :tables
|
36
|
+
|
37
|
+
##
|
38
|
+
# When true, don't print output when seeding.
|
39
|
+
#
|
40
|
+
# @param [Boolean] quiet
|
41
|
+
#
|
42
|
+
# @return [Boolean]
|
43
|
+
attr_accessor :quiet
|
44
|
+
|
45
|
+
##
|
46
|
+
# Create a new instance of the config.
|
47
|
+
def initialize
|
48
|
+
@quiet = false
|
49
|
+
@seeders_directory = ::File.join('db', 'seeds')
|
50
|
+
@csv_files_directory = ::File.join('db', 'seed_files')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Planter
|
4
|
+
##
|
5
|
+
# The class your seeder files should inherit from.
|
6
|
+
class Seeder
|
7
|
+
##
|
8
|
+
# The allowed seeding methods.
|
9
|
+
#
|
10
|
+
# @return [Array]
|
11
|
+
SEEDING_METHODS = %i[standard_csv data_array].freeze
|
12
|
+
|
13
|
+
##
|
14
|
+
# Array of hashes used to create records. Your class must set this
|
15
|
+
# attribute when using +data_hash+ seeding method, although it's probably
|
16
|
+
# more likely that you'll want to define a method that returns a new set of
|
17
|
+
# data each time (via +Faker+, +Array#sample+, etc.). When using
|
18
|
+
# +standard_csv+, +data+ will be set to the data within the csv. You can
|
19
|
+
# override this.
|
20
|
+
#
|
21
|
+
# @return [Array]
|
22
|
+
attr_reader :data
|
23
|
+
|
24
|
+
##
|
25
|
+
# If your class is going to use the inherited +seed+ method, you must tell
|
26
|
+
# it which +seeding_method+ to use. The argument to this method must be
|
27
|
+
# included in the +SEEDING_METHODS+ array.
|
28
|
+
#
|
29
|
+
# @param [Symbol] seeding_method
|
30
|
+
#
|
31
|
+
# @param [Hash] options
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# require 'planter'
|
35
|
+
# class UsersSeeder < Planter::Seeder
|
36
|
+
# seeding_method :data_array,
|
37
|
+
# model: 'User'
|
38
|
+
# parent_model: 'Person',
|
39
|
+
# association: :users,
|
40
|
+
# number_of_records: 2
|
41
|
+
# end
|
42
|
+
def self.seeding_method(method, **options)
|
43
|
+
if !SEEDING_METHODS.include?(method.intern)
|
44
|
+
raise ArgumentError, "Method must be one of #{SEEDING_METHODS.join(', ')}"
|
45
|
+
elsif options[:association] && !options[:parent_model]
|
46
|
+
raise ArgumentError, "Must specify :parent_model with :association"
|
47
|
+
end
|
48
|
+
|
49
|
+
@seeding_method = method
|
50
|
+
@number_of_records = options.fetch(:number_of_records, 1)
|
51
|
+
@model = options.fetch(:model, to_s.delete_suffix('Seeder').singularize)
|
52
|
+
@parent_model = options[:parent_model]
|
53
|
+
@association = @parent_model && options.fetch(:association) do
|
54
|
+
determine_association(options)
|
55
|
+
end
|
56
|
+
return unless @seeding_method == :standard_csv
|
57
|
+
|
58
|
+
@csv_file = options.fetch(:csv_file, Rails.root.join(
|
59
|
+
Planter.config.csv_files_directory,
|
60
|
+
"#{to_s.delete_suffix('Seeder').underscore}.csv"
|
61
|
+
).to_s)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.determine_association(options) # :nodoc:
|
65
|
+
associations =
|
66
|
+
@parent_model.constantize.reflect_on_all_associations.map(&:name)
|
67
|
+
table = to_s.delete_suffix('Seeder').underscore.split('/').last
|
68
|
+
|
69
|
+
[table, table.singularize].map(&:intern).each do |t|
|
70
|
+
return t if associations.include?(t)
|
71
|
+
end
|
72
|
+
|
73
|
+
raise ArgumentError, 'Could not determine association name'
|
74
|
+
end
|
75
|
+
private_class_method :determine_association
|
76
|
+
|
77
|
+
##
|
78
|
+
# The default seed method. To use this method, your class must provide a
|
79
|
+
# valid +seeding_method+, and not implement its own +seed+ method.
|
80
|
+
def seed
|
81
|
+
validate_attributes
|
82
|
+
|
83
|
+
parent_model ? create_records_from_parent : create_records
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
##
|
89
|
+
# The seeding method specified.
|
90
|
+
#
|
91
|
+
# @return [Symbol]
|
92
|
+
def seeding_method
|
93
|
+
@seeding_method ||= self.class.instance_variable_get('@seeding_method')
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# The model for the table being seeded. If the model name you need is
|
98
|
+
# different, change via +seeding_method+.
|
99
|
+
#
|
100
|
+
# @return [String]
|
101
|
+
def model
|
102
|
+
@model ||= self.class.instance_variable_get('@model')
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# The model of the parent. When provided with +association+, records in the
|
107
|
+
# +data+ array, will be created for each record in the parent table. Your
|
108
|
+
# class must set this attribute via +seeding_method+.
|
109
|
+
#
|
110
|
+
# @return [String]
|
111
|
+
def parent_model
|
112
|
+
@parent_model ||= self.class.instance_variable_get('@parent_model')
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# When using +parent_model+, the association name. Your class can set this
|
117
|
+
# attribute via +seeding_method+.
|
118
|
+
#
|
119
|
+
# @return [Symbol]
|
120
|
+
def association
|
121
|
+
@association ||= self.class.instance_variable_get('@association')
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# The number of records to create from each record in the +data+ array. If
|
126
|
+
# nil, defaults to 1, but you can override this in your class via
|
127
|
+
# +seeding_method+.
|
128
|
+
#
|
129
|
+
# @return [Integer]
|
130
|
+
def number_of_records
|
131
|
+
@number_of_records ||=
|
132
|
+
self.class.instance_variable_get('@number_of_records')
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# The csv file corresponding to the model.
|
137
|
+
#
|
138
|
+
# @return [String]
|
139
|
+
def csv_file
|
140
|
+
@csv_file ||= self.class.instance_variable_get('@csv_file')
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Creates records from the +data+ attribute.
|
145
|
+
def create_records
|
146
|
+
data.each do |rec|
|
147
|
+
number_of_records.times do
|
148
|
+
model.constantize.where(
|
149
|
+
rec.transform_values { |value| value == 'NULL' ? nil : value }
|
150
|
+
).first_or_create!
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# Create records from the +data+ attribute for each record in the
|
157
|
+
# +parent_table+, via the specified +association+.
|
158
|
+
def create_records_from_parent
|
159
|
+
parent_model.constantize.all.each do |assoc_rec|
|
160
|
+
number_of_records.times do
|
161
|
+
data.each { |rec| send(create_method, assoc_rec, association, rec) }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def create_method
|
169
|
+
parent_model.constantize.reflect_on_association(
|
170
|
+
association
|
171
|
+
).macro.to_s.include?('many') ? :create_has_many : :create_has_one
|
172
|
+
end
|
173
|
+
|
174
|
+
def create_has_many(assoc_rec, association, rec)
|
175
|
+
assoc_rec.public_send(association).where(rec).first_or_create!
|
176
|
+
end
|
177
|
+
|
178
|
+
def create_has_one(assoc_rec, association, rec)
|
179
|
+
assoc_rec.public_send("create_#{association}", rec)
|
180
|
+
end
|
181
|
+
|
182
|
+
def validate_attributes # :nodoc:
|
183
|
+
case seeding_method.intern
|
184
|
+
when :standard_csv
|
185
|
+
raise "#{csv_file} does not exist" unless ::File.file?(csv_file)
|
186
|
+
|
187
|
+
@data ||= ::CSV.table(csv_file).map(&:to_hash)
|
188
|
+
when :data_array
|
189
|
+
raise "Must define '@data'" if public_send(:data).nil?
|
190
|
+
else
|
191
|
+
raise("Must set 'seeding_method'")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: planter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Evan Gray
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-05-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 6.1.3
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 6.1.3.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 6.1.3
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 6.1.3.1
|
33
|
+
description: Create a seeder for each table in your database, and easily seed from
|
34
|
+
CSV or custom methods
|
35
|
+
email:
|
36
|
+
- evanthegrayt@vivaldi.net
|
37
|
+
executables: []
|
38
|
+
extensions: []
|
39
|
+
extra_rdoc_files: []
|
40
|
+
files:
|
41
|
+
- LICENSE
|
42
|
+
- README.md
|
43
|
+
- Rakefile
|
44
|
+
- lib/planter.rb
|
45
|
+
- lib/planter/config.rb
|
46
|
+
- lib/planter/railtie.rb
|
47
|
+
- lib/planter/seeder.rb
|
48
|
+
- lib/planter/version.rb
|
49
|
+
- lib/tasks/planter_tasks.rake
|
50
|
+
homepage: https://github.com/evanthegrayt/planter
|
51
|
+
licenses:
|
52
|
+
- MIT
|
53
|
+
metadata:
|
54
|
+
allowed_push_host: https://rubygems.org
|
55
|
+
homepage_uri: https://github.com/evanthegrayt/planter
|
56
|
+
source_code_uri: https://github.com/evanthegrayt/planter
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubygems_version: 3.2.3
|
73
|
+
signing_key:
|
74
|
+
specification_version: 4
|
75
|
+
summary: Framework for seeding rails applications.
|
76
|
+
test_files: []
|