discourse-seed-fu 2.3.12

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 61855739941fabc2a6be38a7e1664a8827a9a76033f2ac775701fd8675c1463b
4
+ data.tar.gz: fed1eb46a4b37cb8e0cc1cfc394072fd6bc53392ba7010ffe641d8d1f537f5f1
5
+ SHA512:
6
+ metadata.gz: df3cc7391961357d0a83cf838a5ce52aee68f84d0917714466b5e2d01149387beab4b23457516a34cde120206a19be309f22686e72a2f694fac2389e15355dbe
7
+ data.tar.gz: c50ea60de121ade1ce94f7045d403aaa823534357a1d22e3c5041a606d7d435d5eb43fba414a15945f3e99e610fb23daed7df67cee77b5ca0c4862e8a1aacc37
data/CHANGELOG.md ADDED
@@ -0,0 +1,121 @@
1
+ Version 2.3.8
2
+ -------------
3
+
4
+ Bug fixes:
5
+
6
+ * Restored support for PostgreSQL with Rails versions before 5.0.0 broken in Seed Fu 2.3.7.
7
+
8
+ Version 2.3.7
9
+ -------------
10
+
11
+ Features:
12
+
13
+ * Postgresql >= 10.0 support
14
+
15
+ Version 2.3.6
16
+ -------------
17
+
18
+ Features:
19
+
20
+ * Rails 5.0 support
21
+
22
+ Version 2.3.5
23
+ -------------
24
+
25
+ Features:
26
+
27
+ * Rails 4.2 support
28
+
29
+ Version 2.3.3
30
+ -------------
31
+
32
+ Features:
33
+
34
+ * Capistrano v3 support (by @shishi)
35
+
36
+ Version 2.3.2
37
+ -------------
38
+
39
+ Features:
40
+
41
+ * Documentation improvements (by @george, @kenips, @joshuapinter)
42
+ * Fix documentation of seed_once method (by weedySeaDragon)
43
+ * Allow to seed data with an id < 1 (by @SamSaffron, @aserafin)
44
+ * Seeds work on postgresql when there is no primary key or if primary key has no sequence assigned (by @aserafin)
45
+
46
+ Version 2.3.1
47
+ -------------
48
+
49
+ Features:
50
+
51
+ * Rails 4.1 support added.
52
+ * Capistrano task included. (by @linjunpop)
53
+
54
+ Version 2.3.0
55
+ -------------
56
+
57
+ Features:
58
+
59
+ * Rails 4.0.X support added. (by @tkhr, @DanielWright)
60
+
61
+ Version 2.2.0
62
+ -------------
63
+
64
+ * Rails 3.2 support
65
+
66
+ Version 2.1.0
67
+ -------------
68
+
69
+ Features:
70
+
71
+ * Deprecations removed
72
+
73
+ * Rails 3.1 support added, Rails 3.0 support removed (please use 2.0.X line with 3.0)
74
+
75
+ Version 2.0.1
76
+ -------------
77
+
78
+ Bug fixes:
79
+
80
+ * Update the primary key sequence in PostgreSQL tables after seeding data. This ensures that id conflicts do not occur when records are subsequently added to the table.
81
+
82
+ * Raise ActiveRecord::RecordNotSaved if any of the saves fail (but they won't fail due to validation since saves are done without validation, so this guards against callbacks failing etc.)
83
+
84
+ Version 2.0.0
85
+ -------------
86
+
87
+ Features:
88
+
89
+ * Depends only on Active Record, not the whole of Rails
90
+
91
+ * The `Model.seed_many` syntax is now supported by `Model.seed`, and `Model.seed_many` is deprecated
92
+
93
+ * `Model.seed` supports adding multiple records without an explicit array argument. I.e. the following are equivalent:
94
+
95
+ Model.seed([
96
+ { :name => "Jon" },
97
+ { :name => "Emily" }
98
+ ])
99
+
100
+ Model.seed(
101
+ { :name => "Jon" },
102
+ { :name => "Emily }
103
+ )
104
+
105
+ * A side-effect of the above is another option for single seeds:
106
+
107
+ Model.seed(:name => "Jon")
108
+
109
+ * The `SEED` option to `rake db:seed_fu` is deprecated, and replaced by `FILTER` which works the same way.
110
+
111
+ * Added `SeedFu.quiet` boolean option, set to `true` if you don't want any output from Seed Fu.
112
+
113
+ * Added `SeedFu.fixture_paths`. Set to an array of paths to look for seed files in. Defaults to `["db/fixtures"]` in general, or `["#{Rails.root}/db/fixtures", "#{Rails.root}/db/fixtures/#{Rails.env}"]` when Seed Fu is installed as a Rails plugin.
114
+
115
+ * Added `SeedFu.seed` method which is basically a method equivalent of running `rake db:seed_fu` (the rake task now just basically called `SeedFu.seed`)
116
+
117
+ * Simplified and changed the `SeedFu::Writer` API, see docs for details
118
+
119
+ Bug fixes:
120
+
121
+ * Fix Rails 3 deprecation warnings and make seed-fu fully compatible with being installed as a gem
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008-2010 Michael Bleigh
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,173 @@
1
+ Seed Fu
2
+ =======
3
+
4
+ Seed Fu is an attempt to once and for all solve the problem of inserting and maintaining seed data in a database. It uses a variety of techniques gathered from various places around the web and combines them to create what is hopefully the most robust seed data system around.
5
+
6
+ Warning: API Changes
7
+ --------------------
8
+
9
+ Version 2.0.0 of Seed Fu introduced API changes. `Seed::Writer` was been completely overhauled and will require you to update your scripts. Some other deprecations were introduced, and support is fully removed in version 2.1.0. Please see the [CHANGELOG](CHANGELOG.md) for details.
10
+
11
+ The API documentation is available in full at [http://rubydoc.info/github/mbleigh/seed-fu/master/frames](http://rubydoc.info/github/mbleigh/seed-fu/master/frames).
12
+
13
+ Basic Example
14
+ -------------
15
+
16
+ ### In `db/fixtures/users.rb`
17
+
18
+ User.seed do |s|
19
+ s.id = 1
20
+ s.login = "jon"
21
+ s.email = "jon@example.com"
22
+ s.name = "Jon"
23
+ end
24
+
25
+ User.seed do |s|
26
+ s.id = 2
27
+ s.login = "emily"
28
+ s.email = "emily@example.com"
29
+ s.name = "Emily"
30
+ end
31
+
32
+ ### To load the data:
33
+
34
+ $ rake db:seed_fu
35
+ == Seed from /path/to/app/db/fixtures/users.rb
36
+ - User {:id=>1, :login=>"jon", :email=>"jon@example.com", :name=>"Jon"}
37
+ - User {:id=>2, :login=>"emily", :email=>"emily@example.com", :name=>"Emily"}
38
+
39
+ Installation
40
+ ------------
41
+
42
+ ### Rails 3.1, 3.2, 4.0, 4.1, 4.2, 5.0
43
+
44
+ Just add `gem 'seed-fu', '~> 2.3'` to your `Gemfile`
45
+
46
+ Seed Fu depends on Active Record, but doesn't have to be used with a full Rails app. Simply load and require the `seed-fu` gem and you're set.
47
+
48
+ ### Rails 3.0
49
+
50
+ The current version is not backwards compatible with Rails 3.0. Please use `gem 'seed-fu', '~> 2.0.0'`.
51
+
52
+ ### Rails 2.3
53
+
54
+ The current version is not backwards compatible with Rails 2.3. Please use `gem 'seed-fu', '~> 1.2.0'`.
55
+
56
+ Constraints
57
+ -----------
58
+
59
+ Constraints are used to identify seeds, so that they can be updated if necessary. For example:
60
+
61
+ Point.seed(:x, :y) do |s|
62
+ s.x = 4
63
+ s.y = 7
64
+ s.name = "Home"
65
+ end
66
+
67
+ The first time this seed is loaded, a `Point` record will be created. Now suppose the name is changed:
68
+
69
+ Point.seed(:x, :y) do |s|
70
+ s.x = 4
71
+ s.y = 7
72
+ s.name = "Work"
73
+ end
74
+
75
+ When this is run, Seed Fu will look for a `Point` based on the `:x` and `:y` constraints provided. It will see that a matching `Point` already exists and so update its attributes rather than create a new record.
76
+
77
+ If you do not want seeds to be updated after they have been created, use `seed_once`:
78
+
79
+ Point.seed_once(:x, :y) do |s|
80
+ s.x = 4
81
+ s.y = 7
82
+ s.name = "Home"
83
+ end
84
+
85
+ The default constraint just checks the `id` of the record.
86
+
87
+ Where to put seed files
88
+ -----------------------
89
+
90
+ By default, seed files are looked for in the following locations:
91
+
92
+ * `#{Rails.root}/db/fixtures` and `#{Rails.root}/db/fixtures/#{Rails.env}` in a Rails app
93
+ * `./db/fixtures` when loaded without Rails
94
+
95
+ You can change these defaults by modifying the `SeedFu.fixture_paths` array.
96
+
97
+ Seed files can be named whatever you like, and are loaded in alphabetical order.
98
+
99
+ Terser syntax
100
+ -------------
101
+
102
+ When loading lots of records, the above block-based syntax can be quite verbose. You can use the following instead:
103
+
104
+ User.seed(:id,
105
+ { :id => 1, :login => "jon", :email => "jon@example.com", :name => "Jon" },
106
+ { :id => 2, :login => "emily", :email => "emily@example.com", :name => "Emily" }
107
+ )
108
+
109
+ Rake task
110
+ ---------
111
+
112
+ Seed files can be run automatically using `rake db:seed_fu`. There are two options which you can pass:
113
+
114
+ * `rake db:seed_fu FIXTURE_PATH=path/to/fixtures` -- Where to find the fixtures
115
+ * `rake db:seed_fu FILTER=users,articles` -- Only run seed files with a filename matching the `FILTER`
116
+
117
+ You can also do a similar thing in your code by calling `SeedFu.seed(fixture_paths, filter)`.
118
+
119
+ Disable output
120
+ --------------
121
+
122
+ To disable output from Seed Fu, set `SeedFu.quiet = true`.
123
+
124
+ Handling large seed files
125
+ -------------------------
126
+
127
+ Seed files can be huge. To handle large files (over a million rows), try these tricks:
128
+
129
+ * Gzip your fixtures. Seed Fu will read .rb.gz files happily. `gzip -9` gives the best compression, and with Seed Fu's repetitive syntax, a 160M file can shrink to 16M.
130
+ * Add lines reading `# BREAK EVAL` in your big fixtures, and Seed Fu will avoid loading the whole file into memory. If you use `SeedFu::Writer`, these breaks are built into your generated fixtures.
131
+ * Load a single fixture at a time with the `FILTER` environment variable
132
+ * If you don't need Seed Fu's ability to update seed with new data, then you may find that [activerecord-import](https://github.com/zdennis/activerecord-import) is faster
133
+
134
+ Generating seed files
135
+ ---------------------
136
+
137
+ If you need to programmatically generate seed files, for example to convert a CSV file into a seed file, then you can use [`SeedFu::Writer`](lib/seed-fu/writer.rb).
138
+
139
+ Capistrano deployment
140
+ ---------------------
141
+
142
+ SeedFu has included Capistrano [deploy script](lib/seed-fu/capistrano.rb), you just need require that
143
+ in `config/deploy.rb`:
144
+
145
+ ```ruby
146
+ require 'seed-fu/capistrano'
147
+
148
+ # Trigger the task after update_code
149
+ after 'deploy:update_code', 'db:seed_fu'
150
+ ```
151
+
152
+ If you use Capistrano3, you should require another file.
153
+
154
+ ```ruby
155
+ require 'seed-fu/capistrano3'
156
+
157
+ # Trigger the task before publishing
158
+ before 'deploy:publishing', 'db:seed_fu'
159
+ ```
160
+
161
+ Bugs / Feature requests
162
+ -----------------------
163
+
164
+ Please report them on [Github Issues](https://github.com/mbleigh/seed-fu/issues).
165
+
166
+ Contributors
167
+ ------------
168
+
169
+ * [Michael Bleigh](http://www.mbleigh.com/) is the original author
170
+ * [Jon Leighton](http://jonathanleighton.com/) is the current maintainer
171
+ * Thanks to [Matthew Beale](https://github.com/mixonic) for his great work in adding the writer, making it faster and better.
172
+
173
+ Copyright © 2008-2010 Michael Bleigh, released under the MIT license
@@ -0,0 +1,36 @@
1
+ require 'active_record'
2
+ require 'active_support/core_ext/module/attribute_accessors'
3
+ require 'seed-fu/railtie' if defined?(Rails) && Rails.version >= "3"
4
+
5
+ module SeedFu
6
+ autoload :VERSION, 'seed-fu/version'
7
+ autoload :Seeder, 'seed-fu/seeder'
8
+ autoload :ActiveRecordExtension, 'seed-fu/active_record_extension'
9
+ autoload :BlockHash, 'seed-fu/block_hash'
10
+ autoload :Runner, 'seed-fu/runner'
11
+ autoload :Writer, 'seed-fu/writer'
12
+
13
+ mattr_accessor :quiet
14
+
15
+ # Set `SeedFu.quiet = true` to silence all output
16
+ @@quiet = false
17
+
18
+ mattr_accessor :fixture_paths
19
+
20
+ # Set this to be an array of paths to directories containing your seed files. If used as a Rails
21
+ # plugin, SeedFu will set to to contain `Rails.root/db/fixtures` and
22
+ # `Rails.root/db/fixtures/Rails.env`
23
+ @@fixture_paths = ['db/fixtures']
24
+
25
+ # Load seed data from files
26
+ # @param [Array] fixture_paths The paths to look for seed files in
27
+ # @param [Regexp] filter If given, only filenames matching this expression will be loaded
28
+ def self.seed(fixture_paths = SeedFu.fixture_paths, filter = nil)
29
+ Runner.new(fixture_paths, filter).run
30
+ end
31
+ end
32
+
33
+ # @public
34
+ class ActiveRecord::Base
35
+ extend SeedFu::ActiveRecordExtension
36
+ end
@@ -0,0 +1,65 @@
1
+ module SeedFu
2
+ module ActiveRecordExtension
3
+ # Load some seed data. There are two ways to do this.
4
+ #
5
+ # Verbose syntax
6
+ # --------------
7
+ #
8
+ # This will seed a single record. The `:id` parameter ensures that if a record already exists
9
+ # in the database with the same id, then it will be updated with the name and age, rather
10
+ # than created from scratch.
11
+ #
12
+ # Person.seed(:id) do |s|
13
+ # s.id = 1
14
+ # s.name = "Jon"
15
+ # s.age = 21
16
+ # end
17
+ #
18
+ # Note that `:id` is the default attribute used to identify a seed, so it need not be
19
+ # specified.
20
+ #
21
+ # Terse syntax
22
+ # ------------
23
+ #
24
+ # This is a more succinct way to load multiple records. Note that both `:x` and `:y` are being
25
+ # used to identify a seed here.
26
+ #
27
+ # Point.seed(:x, :y,
28
+ # { :x => 3, :y => 10, :name => "Home" },
29
+ # { :x => 5, :y => 9, :name => "Office" }
30
+ # )
31
+ def seed(*args, &block)
32
+ SeedFu::Seeder.new(self, *parse_seed_fu_args(args, block)).seed
33
+ end
34
+
35
+ # Has the same syntax as {#seed}, but if a record already exists with the same values for
36
+ # constraining attributes, it will not be updated.
37
+ #
38
+ # @example
39
+ # Person.seed(:id, :id => 1, :name => "Jon") # => Record created
40
+ # Person.seed(:id, :id => 1, :name => "Bob") # => Name changed
41
+ # Person.seed_once(:id, :id => 1, :name => "Harry") # => Name *not* changed
42
+ def seed_once(*args, &block)
43
+ constraints, data = parse_seed_fu_args(args, block)
44
+ SeedFu::Seeder.new(self, constraints, data, :insert_only => true).seed
45
+ end
46
+
47
+ private
48
+
49
+ def parse_seed_fu_args(args, block)
50
+ if block.nil?
51
+ if args.last.is_a?(Array)
52
+ # Last arg is an array of data, so assume the rest of the args are constraints
53
+ data = args.pop
54
+ [args, data]
55
+ else
56
+ # Partition the args, assuming the first hash is the start of the data
57
+ args.partition { |arg| !arg.is_a?(Hash) }
58
+ end
59
+ else
60
+ # We have a block, so assume the args are all constraints
61
+ [args, [SeedFu::BlockHash.new(block).to_hash]]
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ module SeedFu
2
+ # @private
3
+ class BlockHash
4
+ def initialize(proc)
5
+ @hash = {}
6
+ proc.call(self)
7
+ end
8
+
9
+ def to_hash
10
+ @hash
11
+ end
12
+
13
+ def method_missing(method_name, *args, &block)
14
+ if method_name.to_s =~ /^(.*)=$/ && args.length == 1 && block.nil?
15
+ @hash[$1] = args.first
16
+ else
17
+ super
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ Capistrano::Configuration.instance.load do
2
+ namespace :db do
3
+ desc "Load seed data into database"
4
+ task :seed_fu, :roles => :db, :only => { :primary => true } do
5
+ run "cd #{release_path} && bundle exec rake RAILS_ENV=#{rails_env} db:seed_fu"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1 @@
1
+ load File.expand_path('../../tasks/seed_fu_capistrano3.rake', __FILE__)
@@ -0,0 +1,14 @@
1
+ module SeedFu
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load "tasks/seed_fu.rake"
5
+ end
6
+
7
+ initializer 'seed_fu.set_fixture_paths' do
8
+ SeedFu.fixture_paths = [
9
+ Rails.root.join('db/fixtures').to_s,
10
+ Rails.root.join('db/fixtures/' + Rails.env).to_s
11
+ ]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,73 @@
1
+ require 'zlib'
2
+ require 'active_support/core_ext/array/wrap'
3
+
4
+ module SeedFu
5
+ # Runs seed files.
6
+ #
7
+ # It is not recommended to use this class directly. Instead, use {SeedFu.seed SeedFu.seed}, which creates
8
+ # an instead of {Runner} and calls {#run #run}.
9
+ #
10
+ # @see SeedFu.seed SeedFu.seed
11
+ class Runner
12
+ # @param [Array<String>] fixture_paths The paths where fixtures are located. Will use
13
+ # `SeedFu.fixture_paths` if {nil}. If the argument is not an array, it will be wrapped by one.
14
+ # @param [Regexp] filter If given, only seed files with a file name matching this pattern will
15
+ # be used
16
+ def initialize(fixture_paths = nil, filter = nil)
17
+ @fixture_paths = Array.wrap(fixture_paths || SeedFu.fixture_paths)
18
+ @filter = filter
19
+ end
20
+
21
+ # Run the seed files.
22
+ def run
23
+ puts "\n== Filtering seed files against regexp: #{@filter.inspect}" if @filter && !SeedFu.quiet
24
+
25
+ filenames.each do |filename|
26
+ run_file(filename)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def run_file(filename)
33
+ puts "\n== Seed from #{filename}" unless SeedFu.quiet
34
+
35
+ ActiveRecord::Base.transaction do
36
+ open(filename) do |file|
37
+ chunked_ruby = ''
38
+ file.each_line do |line|
39
+ if line == "# BREAK EVAL\n"
40
+ eval(chunked_ruby)
41
+ chunked_ruby = ''
42
+ else
43
+ chunked_ruby << line
44
+ end
45
+ end
46
+ eval(chunked_ruby) unless chunked_ruby == ''
47
+ end
48
+ end
49
+ end
50
+
51
+ def open(filename)
52
+ if filename[-3..-1] == '.gz'
53
+ Zlib::GzipReader.open(filename) do |file|
54
+ yield file
55
+ end
56
+ else
57
+ File.open(filename) do |file|
58
+ yield file
59
+ end
60
+ end
61
+ end
62
+
63
+ def filenames
64
+ filenames = []
65
+ @fixture_paths.each do |path|
66
+ filenames += (Dir[File.join(path, '*.rb')] + Dir[File.join(path, '*.rb.gz')]).sort
67
+ end
68
+ filenames.uniq!
69
+ filenames = filenames.find_all { |filename| filename =~ @filter } if @filter
70
+ filenames
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,107 @@
1
+ require 'active_support/core_ext/hash/keys'
2
+
3
+ module SeedFu
4
+ # Creates or updates seed records with data.
5
+ #
6
+ # It is not recommended to use this class directly. Instead, use `Model.seed`, and `Model.seed_once`,
7
+ # where `Model` is your Active Record model.
8
+ #
9
+ # @see ActiveRecordExtension
10
+ class Seeder
11
+ # @param [ActiveRecord::Base] model_class The model to be seeded
12
+ # @param [Array<Symbol>] constraints A list of attributes which identify a particular seed. If
13
+ # a record with these attributes already exists then it will be updated rather than created.
14
+ # @param [Array<Hash>] data Each item in this array is a hash containing attributes for a
15
+ # particular record.
16
+ # @param [Hash] options
17
+ # @option options [Boolean] :quiet (SeedFu.quiet) If true, output will be silenced
18
+ # @option options [Boolean] :insert_only (false) If true then existing records which match the
19
+ # constraints will not be updated, even if the seed data has changed
20
+ def initialize(model_class, constraints, data, options = {})
21
+ @model_class = model_class
22
+ @constraints = constraints.to_a.empty? ? [:id] : constraints
23
+ @data = data.to_a || []
24
+ @options = options.symbolize_keys
25
+
26
+ @options[:quiet] ||= SeedFu.quiet
27
+
28
+ validate_constraints!
29
+ validate_data!
30
+ end
31
+
32
+ # Insert/update the records as appropriate. Validation is skipped while saving.
33
+ # @return [Array<ActiveRecord::Base>] The records which have been seeded
34
+ def seed
35
+ records = @model_class.transaction do
36
+ @data.map { |record_data| seed_record(record_data.symbolize_keys) }
37
+ end
38
+ update_id_sequence
39
+ records
40
+ end
41
+
42
+ private
43
+
44
+ def validate_constraints!
45
+ unknown_columns = @constraints.map(&:to_s) - @model_class.column_names
46
+ unless unknown_columns.empty?
47
+ raise(ArgumentError,
48
+ "Your seed constraints contained unknown columns: #{column_list(unknown_columns)}. " +
49
+ "Valid columns are: #{column_list(@model_class.column_names)}.")
50
+ end
51
+ end
52
+
53
+ def validate_data!
54
+ raise ArgumentError, "Seed data missing" if @data.empty?
55
+ end
56
+
57
+ def column_list(columns)
58
+ '`' + columns.join("`, `") + '`'
59
+ end
60
+
61
+ def seed_record(data)
62
+ record = find_or_initialize_record(data)
63
+ return if @options[:insert_only] && !record.new_record?
64
+
65
+ puts " - #{@model_class} #{data.inspect}" unless @options[:quiet]
66
+
67
+ # Rails 3 or Rails 4 + rails/protected_attributes
68
+ if record.class.respond_to?(:protected_attributes) && record.class.respond_to?(:accessible_attributes)
69
+ record.assign_attributes(data, :without_protection => true)
70
+ # Rails 4 without rails/protected_attributes
71
+ else
72
+ record.assign_attributes(data)
73
+ end
74
+ record.save(:validate => false) || raise(ActiveRecord::RecordNotSaved, 'Record not saved!')
75
+ record
76
+ end
77
+
78
+ def find_or_initialize_record(data)
79
+ @model_class.where(constraint_conditions(data)).take ||
80
+ @model_class.new
81
+ end
82
+
83
+ def constraint_conditions(data)
84
+ Hash[@constraints.map { |c| [c, data[c.to_sym]] }]
85
+ end
86
+
87
+ def update_id_sequence
88
+ if @model_class.connection.adapter_name == "PostgreSQL" or @model_class.connection.adapter_name == "PostGIS"
89
+ return if @model_class.primary_key.nil? || @model_class.sequence_name.nil?
90
+
91
+ max_seeded_id = @data.filter_map { |d| d["id"] }.max
92
+ seq = @model_class.connection.execute(<<~SQL)
93
+ SELECT last_value
94
+ FROM #{@model_class.sequence_name}
95
+ SQL
96
+ last_seq_value = seq.first["last_value"]
97
+
98
+ if max_seeded_id && last_seq_value < max_seeded_id
99
+ # Update the sequence to start from the highest existing id
100
+ @model_class.connection.reset_pk_sequence!(@model_class.table_name)
101
+ else
102
+ # The sequence is already higher than any of our seeded ids - better not touch it
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,4 @@
1
+ module SeedFu
2
+ # The current version of Seed Fu
3
+ VERSION = '2.3.12'
4
+ end
@@ -0,0 +1,132 @@
1
+ module SeedFu
2
+ # {Writer} is used to programmatically generated seed files. For example, you might want to write
3
+ # a script which converts data in a CSV file to a valid Seed Fu seed file, which can then be
4
+ # imported.
5
+ #
6
+ # @example Basic usage
7
+ # SeedFu::Writer.write('path/to/file.rb', :class_name => 'Person', :constraints => [:first_name, :last_name]) do |writer|
8
+ # writer.add(:first_name => 'Jon', :last_name => 'Smith', :age => 21)
9
+ # writer.add(:first_name => 'Emily', :last_name => 'McDonald', :age => 24)
10
+ # end
11
+ #
12
+ # # Writes the following to the file:
13
+ # #
14
+ # # Person.seed(:first_name, :last_name,
15
+ # # {:first_name=>"Jon", :last_name=>"Smith", :age=>21},
16
+ # # {:first_name=>"Emily", :last_name=>"McDonald", :age=>24}
17
+ # # )
18
+ class Writer
19
+ cattr_accessor :default_options
20
+ @@default_options = {
21
+ :chunk_size => 100,
22
+ :constraints => [:id],
23
+ :seed_type => :seed
24
+ }
25
+
26
+ # @param [Hash] options
27
+ # @option options [String] :class_name *Required* The name of the Active Record model to
28
+ # generate seeds for
29
+ # @option options [Fixnum] :chunk_size (100) The number of seeds to write before generating a
30
+ # `# BREAK EVAL` line. (Chunking reduces memory usage when loading seeds.)
31
+ # @option options [:seed, :seed_once] :seed_type (:seed) The method to use when generating
32
+ # seeds. See {ActiveRecordExtension} for details.
33
+ # @option options [Array<Symbol>] :constraints ([:id]) The constraining attributes for the seeds
34
+ def initialize(options = {})
35
+ @options = self.class.default_options.merge(options)
36
+ raise ArgumentError, "missing option :class_name" unless @options[:class_name]
37
+ end
38
+
39
+ # Creates a new instance of {Writer} with the `options`, and then calls {#write} with the
40
+ # `io_or_filename` and `block`
41
+ def self.write(io_or_filename, options = {}, &block)
42
+ new(options).write(io_or_filename, &block)
43
+ end
44
+
45
+ # Writes the necessary headers and footers, and yields to a block within which the actual
46
+ # seed data should be writting using the `#<<` method.
47
+ #
48
+ # @param [IO] io_or_filename The IO to which writes will be made. (If an `IO` is given, it is
49
+ # your responsibility to close it after writing.)
50
+ # @param [String] io_or_filename The filename of a file to make writes to. (Will be opened and
51
+ # closed automatically.)
52
+ # @yield [self] make calls to `#<<` within the block
53
+ def write(io_or_filename, &block)
54
+ raise ArgumentError, "missing block" unless block_given?
55
+
56
+ if io_or_filename.respond_to?(:write)
57
+ write_to_io(io_or_filename, &block)
58
+ else
59
+ File.open(io_or_filename, 'w') do |file|
60
+ write_to_io(file, &block)
61
+ end
62
+ end
63
+ end
64
+
65
+ # Add a seed. Must be called within a block passed to {#write}.
66
+ # @param [Hash] seed The attributes for the seed
67
+ def <<(seed)
68
+ raise "You must add seeds inside a SeedFu::Writer#write block" unless @io
69
+
70
+ buffer = ''
71
+
72
+ if chunk_this_seed?
73
+ buffer << seed_footer
74
+ buffer << "# BREAK EVAL\n"
75
+ buffer << seed_header
76
+ end
77
+
78
+ buffer << ",\n"
79
+ buffer << ' ' + seed.inspect
80
+
81
+ @io.write(buffer)
82
+
83
+ @count += 1
84
+ end
85
+ alias_method :add, :<<
86
+
87
+ private
88
+
89
+ def write_to_io(io)
90
+ @io, @count = io, 0
91
+ @io.write(file_header)
92
+ @io.write(seed_header)
93
+ yield(self)
94
+ @io.write(seed_footer)
95
+ @io.write(file_footer)
96
+ ensure
97
+ @io, @count = nil, nil
98
+ end
99
+
100
+ def file_header
101
+ <<-END
102
+ # DO NOT MODIFY THIS FILE, it was auto-generated.
103
+ #
104
+ # Date: #{Time.now}
105
+ # Seeding #{@options[:class_name]}
106
+ # Written with the command:
107
+ #
108
+ # #{$0} #{$*.join}
109
+ #
110
+ END
111
+ end
112
+
113
+ def file_footer
114
+ <<-END
115
+ # End auto-generated file.
116
+ END
117
+ end
118
+
119
+ def seed_header
120
+ constraints = @options[:constraints] && @options[:constraints].map(&:inspect).join(', ')
121
+ "#{@options[:class_name]}.#{@options[:seed_type]}(#{constraints}"
122
+ end
123
+
124
+ def seed_footer
125
+ "\n)\n"
126
+ end
127
+
128
+ def chunk_this_seed?
129
+ @count != 0 && (@count % @options[:chunk_size]) == 0
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,38 @@
1
+ require 'discourse-seed-fu'
2
+
3
+ namespace :db do
4
+ desc <<-EOS
5
+ Loads seed data for the current environment. It will look for
6
+ ruby seed files in <RAILS_ROOT>/db/fixtures/ and
7
+ <RAILS_ROOT>/db/fixtures/<RAILS_ENV>/.
8
+
9
+ By default it will load any ruby files found. You can filter the files
10
+ loaded by passing in the FILTER environment variable with a comma-delimited
11
+ list of patterns to include. Any files not matching the pattern will
12
+ not be loaded.
13
+
14
+ You can also change the directory where seed files are looked for
15
+ with the FIXTURE_PATH environment variable.
16
+
17
+ Examples:
18
+ # default, to load all seed files for the current environment
19
+ rake db:seed_fu
20
+
21
+ # to load seed files matching orders or customers
22
+ rake db:seed_fu FILTER=orders,customers
23
+
24
+ # to load files from RAILS_ROOT/features/fixtures
25
+ rake db:seed_fu FIXTURE_PATH=features/fixtures
26
+ EOS
27
+ task :seed_fu => :environment do
28
+ if ENV["FILTER"]
29
+ filter = /#{ENV["FILTER"].gsub(/,/, "|")}/
30
+ end
31
+
32
+ if ENV["FIXTURE_PATH"]
33
+ fixture_paths = [ENV["FIXTURE_PATH"], ENV["FIXTURE_PATH"] + '/' + Rails.env]
34
+ end
35
+
36
+ SeedFu.seed(fixture_paths, filter)
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ namespace :db do
2
+ desc 'Load seed data into database'
3
+ task :seed_fu do
4
+ on roles(:db) do
5
+ within release_path do
6
+ with rails_env: fetch(:rails_env) do
7
+ execute :bundle, :exec, :rake, 'db:seed_fu'
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: discourse-seed-fu
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.3.12
5
+ platform: ruby
6
+ authors:
7
+ - Michael Bleigh
8
+ - Jon Leighton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2022-10-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '3.1'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '3.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: activesupport
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '3.1'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '3.1'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '2.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '2.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: pg
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: mysql2
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: sqlite3
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description: Seed Fu is an attempt to once and for all solve the problem of inserting
99
+ and maintaining seed data in a database. It uses a variety of techniques gathered
100
+ from various places around the web and combines them to create what is hopefully
101
+ the most robust seed data system around.
102
+ email:
103
+ - michael@intridea.com
104
+ - j@jonathanleighton.com
105
+ executables: []
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - CHANGELOG.md
110
+ - LICENSE
111
+ - README.md
112
+ - lib/discourse-seed-fu.rb
113
+ - lib/seed-fu/active_record_extension.rb
114
+ - lib/seed-fu/block_hash.rb
115
+ - lib/seed-fu/capistrano.rb
116
+ - lib/seed-fu/capistrano3.rb
117
+ - lib/seed-fu/railtie.rb
118
+ - lib/seed-fu/runner.rb
119
+ - lib/seed-fu/seeder.rb
120
+ - lib/seed-fu/version.rb
121
+ - lib/seed-fu/writer.rb
122
+ - lib/tasks/seed_fu.rake
123
+ - lib/tasks/seed_fu_capistrano3.rake
124
+ homepage: http://github.com/mbleigh/seed-fu
125
+ licenses:
126
+ - MIT
127
+ metadata: {}
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubygems_version: 3.1.6
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Easily manage seed data in your Active Record application
147
+ test_files: []