seed_dumpling 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 34ece3f93f37d8317c2a9d7ea58dfcd05eb4c041c5bb39a8a0e835b15eb9d9ec
4
+ data.tar.gz: 8ebb42ccb0329c74629bc8b3bc536da1430a360a97b9b598ea8b8425c794018f
5
+ SHA512:
6
+ metadata.gz: b968a70bcb038cd358d14f467cd98961c5dcad03d2452470d45ed9e878c8732dc3334b2cdfdffae4e0ea9057c32522162e75eb8b89eb5d55312ff15338600eee
7
+ data.tar.gz: 4573204701121d23e60047e80464b6b4674932e32e020184ee6ecba3998dc940fa8cd5ccb97e408f506757268f8f499d49c054c6f4a94f7b185e3574e706e5fb
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Mikael Henriksson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ Seed Dump
2
+ ========
3
+
4
+ Seed Dump is a Rails 7+ that adds a rake task named `db:seed:dump`.
5
+ It allows you to create seed data files from the existing data in your database.
6
+ You can also use Seed Dump from the Rails console. See below for usage examples.
7
+
8
+ Installation
9
+ ------------
10
+
11
+ Add it to your Gemfile with:
12
+ ```ruby
13
+ gem 'seed_dumpling'
14
+ ```
15
+ Or install it by hand:
16
+ ```sh
17
+ gem install seed_dumpling
18
+ ```
19
+ Examples
20
+ --------
21
+
22
+ ### Rake task
23
+
24
+ Dump all data directly to `db/seeds.rb`:
25
+ ```sh
26
+ rake db:seed:dump
27
+ ```
28
+ Result:
29
+ ```ruby
30
+ Product.create!([
31
+ { category_id: 1, description: "Long Sleeve Shirt", name: "Long Sleeve Shirt" },
32
+ { category_id: 3, description: "Plain White Tee Shirt", name: "Plain T-Shirt" }
33
+ ])
34
+ User.create!([
35
+ { password: "123456", username: "test_1" },
36
+ { password: "234567", username: "test_2" }
37
+ ])
38
+ ```
39
+
40
+ Dump only data from the users table and dump a maximum of 1 record:
41
+ ```sh
42
+ $ rake db:seed:dump MODELS=User LIMIT=1
43
+ ```
44
+
45
+ Result:
46
+ ```ruby
47
+ User.create!([
48
+ { password: "123456", username: "test_1" }
49
+ ])
50
+ ```
51
+
52
+ Append to `db/seeds.rb` instead of overwriting it:
53
+ ```sh
54
+ rake db:seed:dump APPEND=true
55
+ ```
56
+
57
+ Use another output file instead of `db/seeds.rb`:
58
+ ```sh
59
+ rake db:seed:dump FILE=db/seeds/users.rb
60
+ ```
61
+
62
+ Exclude `name` and `age` from the dump:
63
+ ```sh
64
+ rake db:seed:dump EXCLUDE=name,age
65
+ ```
66
+
67
+ There are more options that can be set— see below for all of them.
68
+
69
+ ### Console
70
+
71
+ Output a dump of all User records:
72
+ ```ruby
73
+ irb(main):001:0> puts SeedDumpling.dump(User)
74
+ User.create!([
75
+ { password: "123456", username: "test_1" },
76
+ { password: "234567", username: "test_2" }
77
+ ])
78
+ ```
79
+
80
+ Write the dump to a file:
81
+ ```ruby
82
+ irb(main):002:0> SeedDumpling.dump(User, file: 'db/seeds.rb')
83
+ ```
84
+
85
+ Append the dump to a file:
86
+ ```ruby
87
+ irb(main):003:0> SeedDumpling.dump(User, file: 'db/seeds.rb', append: true)
88
+ ```
89
+
90
+ Exclude `name` and `age` from the dump:
91
+ ```ruby
92
+ irb(main):004:0> SeedDumpling.dump(User, exclude: [:name, :age])
93
+ ```
94
+
95
+ Options are specified as a Hash for the second argument.
96
+
97
+ In the console, any relation of ActiveRecord rows can be dumped (not individual objects though)
98
+ ```ruby
99
+ irb(main):001:0> puts SeedDumpling.dump(User.where(is_admin: false))
100
+ User.create!([
101
+ { password: "123456", username: "test_1", is_admin: false },
102
+ { password: "234567", username: "test_2", is_admin: false }
103
+ ])
104
+ ```
105
+
106
+ Options
107
+ -------
108
+
109
+ Options are common to both the Rake task and the console, except where noted.
110
+
111
+ `append`: If set to `true`, append the data to the file instead of overwriting it. Default: `false`.
112
+
113
+ `batch_size`: Controls the number of records that are written to file at a given time. Default: 1000. If you're running out of memory when dumping, try decreasing this. If things are dumping too slow, trying increasing this.
114
+
115
+ `exclude`: Attributes to be excluded from the dump. Pass a comma-separated list to the Rake task (i.e. `name,age`) and an array on the console (i.e. `[:name, :age]`). Default: `[:id, :created_at, :updated_at]`.
116
+
117
+ `file`: Write to the specified output file. The Rake task default is `db/seeds.rb`. The console returns the dump as a string by default.
118
+
119
+ `import`: If `true`, output will be in the format needed by the [activerecord-import](https://github.com/zdennis/activerecord-import) gem, rather than the default format. Default: `false`.
120
+
121
+ `limit`: Dump no more than this amount of data. Default: no limit. Rake task only. In the console just pass in an ActiveRecord::Relation with the appropriate limit (e.g. `SeedDumpling.dump(User.limit(5))`).
122
+
123
+ `conditions`: Dump only specific records. In the console just pass in an ActiveRecord::Relation with the appropriate conditions (e.g. `SeedDumpling.dump(User.where(state: :active))`).
124
+
125
+ `model[s]`: Restrict the dump to the specified comma-separated list of models. Default: all models. If you are using a Rails engine you can dump a specific model by passing "EngineName::ModelName". Rake task only. Example: `rake db:seed:dump MODELS="User, Position, Function"`
126
+
127
+ `models_exclude`: Exclude the specified comma-separated list of models from the dump. Default: no models excluded. Rake task only. Example: `rake db:seed:dump MODELS_EXCLUDE="User"`
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SeedDumpling
4
+ module DumpMethods
5
+ #
6
+ # Helpermethods for enumerating active records
7
+ #
8
+ module Enumeration
9
+ def active_record_enumeration(records, options) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
10
+ # Ensure records are ordered by primary key if not already ordered
11
+ unless records.respond_to?(:arel) && records.arel.orders.present?
12
+ records = records.order("#{records.quoted_table_name}.#{records.quoted_primary_key} ASC")
13
+ end
14
+
15
+ num_of_batches, batch_size, last_batch_size = batch_params_from(records, options)
16
+
17
+ # Iterate over each batch
18
+ (1..num_of_batches).each do |batch_number|
19
+ last_batch = (batch_number == num_of_batches)
20
+ current_batch_size = last_batch ? last_batch_size : batch_size
21
+
22
+ # Fetch and process records for the current batch
23
+ record_strings = records
24
+ .offset((batch_number - 1) * batch_size)
25
+ .limit(current_batch_size)
26
+ .map { |record| dump_record(record, options) }
27
+
28
+ yield record_strings, last_batch
29
+ end
30
+ end
31
+
32
+ def enumerable_enumeration(records, options)
33
+ _, batch_size = batch_params_from(records, options)
34
+ record_strings = []
35
+
36
+ records.each_with_index do |record, index|
37
+ record_strings << dump_record(record, options)
38
+ last_batch = (index == records.size - 1)
39
+
40
+ if record_strings.size == batch_size || last_batch
41
+ yield record_strings, last_batch
42
+ record_strings = []
43
+ end
44
+ end
45
+ end
46
+
47
+ def batch_params_from(records, options)
48
+ batch_size = batch_size_from(options)
49
+ total_count = records.count
50
+
51
+ num_of_batches = (total_count.to_f / batch_size).ceil
52
+ remainder = total_count % batch_size
53
+ last_batch_size = remainder.zero? ? batch_size : remainder
54
+
55
+ [num_of_batches, batch_size, last_batch_size]
56
+ end
57
+
58
+ def batch_size_from(options)
59
+ options[:batch_size]&.to_i || 1000
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_text"
4
+ require "active_storage"
5
+
6
+ class SeedDumpling
7
+ # Provides methods for dumping database records into Ruby code that can be used
8
+ # as seeds. Handles various data types and supports both create and import formats.
9
+ module DumpMethods # rubocop:disable Metrics/ModuleLength
10
+ extend ActiveSupport::Concern
11
+
12
+ include Enumeration
13
+
14
+ class_methods do
15
+ def dump(...)
16
+ new.dump(...)
17
+ end
18
+ end
19
+
20
+ def dump(records, options = {})
21
+ return nil if records.none?
22
+
23
+ io = prepare_io(options)
24
+ write_records(records, io, options)
25
+ ensure
26
+ io&.close
27
+ end
28
+
29
+ private
30
+
31
+ def dump_record(record, options) # rubocop:disable Metrics/AbcSize
32
+ attributes = filter_attributes(record.attributes, options[:exclude])
33
+
34
+ # Make sure we include attachments and rich text in the final output
35
+ attributes["avatar"] = record.avatar if record.respond_to?(:avatar) && defined?(ActiveStorage::Attached::One)
36
+
37
+ attributes["photos"] = record.photos if record.respond_to?(:photos) && defined?(ActiveStorage::Attached::Many)
38
+
39
+ attributes["content"] = record.content if record.respond_to?(:content) && record.content.is_a?(ActionText::RichText)
40
+
41
+ formatted_attributes = format_attributes(attributes, options[:import])
42
+ wrap_attributes(formatted_attributes, options[:import])
43
+ end
44
+
45
+ def filter_attributes(attributes, exclude)
46
+ attributes.select do |key, _|
47
+ (key.is_a?(String) || key.is_a?(Symbol)) && exclude.exclude?(key.to_sym)
48
+ end
49
+ end
50
+
51
+ def format_attributes(attributes, import_format)
52
+ attributes.map do |attribute, value|
53
+ import_format ? value_to_s(value) : "#{attribute}: #{value_to_s(value)}"
54
+ end.join(", ")
55
+ end
56
+
57
+ def wrap_attributes(attribute_string, import_format)
58
+ open_char, close_char = import_format ? ["[", "]"] : ["{", "}"]
59
+ "#{open_char}#{attribute_string}#{close_char}"
60
+ end
61
+
62
+ def value_to_s(value) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
63
+ formatted_value = case value
64
+ when BigDecimal, IPAddr, ->(v) { rgeo_instance?(v) }
65
+ value.to_s
66
+ when Date, Time, DateTime
67
+ value.to_fs(:db)
68
+ when Range
69
+ range_to_string(value)
70
+ when ->(v) { defined?(ActiveStorage::Attached::One) && v.is_a?(ActiveStorage::Attached::One) }
71
+ handle_active_storage_one(value)
72
+ when ->(v) { defined?(ActiveStorage::Attached::Many) && v.is_a?(ActiveStorage::Attached::Many) }
73
+ handle_active_storage_many(value)
74
+ when ->(v) { defined?(ActionText::RichText) && v.is_a?(ActionText::RichText) }
75
+ handle_rich_text(value)
76
+ else
77
+ value
78
+ end
79
+ formatted_value.inspect
80
+ end
81
+
82
+ def range_to_string(range)
83
+ from = infinite_value?(range.begin) ? "" : range.begin
84
+ to = infinite_value?(range.end) ? "" : range.end
85
+ exclude_end = range.exclude_end? ? ")" : "]"
86
+ "[#{from},#{to}#{exclude_end}"
87
+ end
88
+
89
+ def rgeo_instance?(value)
90
+ value.class.ancestors.any? { |ancestor| ancestor.to_s == "RGeo::Feature::Instance" }
91
+ end
92
+
93
+ def infinite_value?(value)
94
+ value.respond_to?(:infinite?) && value.infinite?
95
+ end
96
+
97
+ def prepare_io(options)
98
+ if options[:file].present?
99
+ mode = options[:append] ? "a+" : "w+"
100
+ File.open(options[:file], mode)
101
+ else
102
+ StringIO.new
103
+ end
104
+ end
105
+
106
+ def write_records(records, io, options) # rubocop:disable Metrics/MethodLength
107
+ options[:exclude] ||= %i[id created_at updated_at]
108
+
109
+ method_call = build_method_call(records, options)
110
+ io.write(method_call)
111
+ io.write("[\n ")
112
+
113
+ enumeration_method = select_enumeration_method(records)
114
+ send(enumeration_method, records, options) do |record_strings, last_batch|
115
+ io.write(record_strings.join(",\n "))
116
+ io.write(",\n ") unless last_batch
117
+ end
118
+
119
+ io.write("\n]#{format_import_options(options)})\n")
120
+
121
+ return if options[:file].present?
122
+
123
+ io.rewind
124
+ io.read
125
+ end
126
+
127
+ def build_method_call(records, options)
128
+ method = options[:import] ? "import" : "create!"
129
+ model_name = determine_model(records)
130
+ if options[:import]
131
+ attributes_list = attribute_names(records, options).map { _1.to_sym.inspect }.join(", ")
132
+ "#{model_name}.#{method}([#{attributes_list}], "
133
+ else
134
+ "#{model_name}.#{method}("
135
+ end
136
+ end
137
+
138
+ def format_import_options(options)
139
+ return "" unless options[:import].is_a?(Hash)
140
+
141
+ options_string = options[:import].map { |key, value| "#{key}: #{value}" }.join(", ")
142
+ ", #{options_string}"
143
+ end
144
+
145
+ def attribute_names(records, options)
146
+ attributes = records.respond_to?(:attribute_names) ? records.attribute_names : records.first.attribute_names
147
+ attributes.reject { |name| options[:exclude].include?(name.to_sym) }
148
+ end
149
+
150
+ def determine_model(records)
151
+ if records.is_a?(Class)
152
+ records
153
+ elsif records.respond_to?(:model)
154
+ records.model
155
+ else
156
+ records.first.class
157
+ end
158
+ end
159
+
160
+ def select_enumeration_method(records)
161
+ if records.is_a?(ActiveRecord::Relation) || records.is_a?(Class)
162
+ :active_record_enumeration
163
+ else
164
+ :enumerable_enumeration
165
+ end
166
+ end
167
+
168
+ def handle_active_storage_one(attachment)
169
+ return nil unless attachment.attached?
170
+
171
+ copy_attachment_to_seeds_dir(attachment)
172
+
173
+ {
174
+ io: "File.open(Rails.root.join('db/seeds/files', '#{attachment.filename}'))",
175
+ filename: attachment.filename.to_s,
176
+ content_type: attachment.blob.content_type,
177
+ }
178
+ end
179
+
180
+ def handle_active_storage_many(attachments)
181
+ return [] unless attachments.attached?
182
+
183
+ attachments.map do |attachment|
184
+ copy_attachment_to_seeds_dir(attachment)
185
+
186
+ {
187
+ io: "File.open(Rails.root.join('db/seeds/files', '#{attachment.filename}'))",
188
+ filename: attachment.filename.to_s,
189
+ content_type: attachment.blob.content_type,
190
+ }
191
+ end
192
+ end
193
+
194
+ def copy_attachment_to_seeds_dir(attachment) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
195
+ return unless attachment&.blob
196
+
197
+ seeds_dir = Rails.root.join("db/seeds/files")
198
+ FileUtils.mkdir_p(seeds_dir)
199
+
200
+ target_path = seeds_dir.join(attachment.filename.to_s)
201
+
202
+ # Skip if file already exists
203
+ return if File.exist?(target_path)
204
+
205
+ begin
206
+ # Try to get direct file path first
207
+ source_path = attachment.blob.service.path_for(attachment.blob.key)
208
+ if source_path && File.exist?(source_path)
209
+ FileUtils.cp(source_path, target_path)
210
+ else
211
+ # Fallback to downloading for cloud storage
212
+ File.open(target_path, "wb") do |file|
213
+ attachment.download { |chunk| file.write(chunk) }
214
+ end
215
+ end
216
+ rescue StandardError => e
217
+ Rails.logger.error "Failed to copy attachment #{attachment.filename}: #{e.message}"
218
+ raise e
219
+ end
220
+ end
221
+
222
+ def handle_rich_text(rich_text)
223
+ rich_text.body&.to_html
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SeedDumpling
4
+ # Provides functionality for dumping database records to seed files using
5
+ # environment variables to configure the dump process. Supports model filtering,
6
+ # batch processing, and various output options.
7
+ module Environment
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ def dump_using_environment(...)
12
+ new.dump_using_environment(...)
13
+ end
14
+ end
15
+
16
+ def dump_using_environment(env = {}) # rubocop:disable Metrics/MethodLength
17
+ Rails.application.eager_load!
18
+
19
+ models = retrieve_models(env) - retrieve_models_exclude(env)
20
+
21
+ limit = retrieve_limit_value(env)
22
+ append = retrieve_append_value(env)
23
+ models.each do |model|
24
+ model = model.limit(limit) if limit.present?
25
+
26
+ SeedDumpling.dump(model,
27
+ append: append,
28
+ batch_size: retrieve_batch_size_value(env),
29
+ exclude: retrieve_exclude_value(env),
30
+ file: retrieve_file_value(env),
31
+ import: retrieve_import_value(env),
32
+ )
33
+
34
+ append = true # Always append for every model after the first
35
+ # (append for the first model is determined by
36
+ # the APPEND environment variable).
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ # Internal: Array of Strings corresponding to Active Record model class names
43
+ # that should be excluded from the dump.
44
+ ACTIVE_RECORD_INTERNAL_MODELS = ["ActiveRecord::SchemaMigration",
45
+ "ActiveRecord::InternalMetadata"].freeze
46
+
47
+ # Internal: Retrieves an Array of Active Record model class constants to be
48
+ # dumped.
49
+ #
50
+ # If a "MODEL" or "MODELS" environment variable is specified, there will be
51
+ # an attempt to parse the environment variable String by splitting it on
52
+ # commmas and then converting it to constant.
53
+ #
54
+ # Model classes that do not have corresponding database tables or database
55
+ # records will be filtered out, as will model classes internal to Active
56
+ # Record.
57
+ #
58
+ # env - Hash of environment variables from which to parse Active Record
59
+ # model classes. The Hash is not optional but the "MODEL" and "MODELS"
60
+ # keys are optional.
61
+ #
62
+ # Returns the Array of Active Record model classes to be dumped.
63
+ def retrieve_models(env) # rubocop:disable Metrics/AbcSize
64
+ # Parse either the "MODEL" environment variable or the "MODELS"
65
+ # environment variable, with "MODEL" taking precedence.
66
+ models_env = env["MODEL"] || env["MODELS"]
67
+
68
+ # If there was a use models environment variable, split it and
69
+ # convert the given model string (e.g. "User") to an actual
70
+ # model constant (e.g. User).
71
+ #
72
+ # If a models environment variable was not given, use descendants of
73
+ # ActiveRecord::Base as the target set of models. This should be all
74
+ # model classes in the project.
75
+ models = if models_env
76
+ models_env.split(",")
77
+ .collect { |x| x.strip.underscore.singularize.camelize.constantize }
78
+ else
79
+ ActiveRecord::Base.descendants
80
+ end
81
+
82
+ # Filter the set of models to exclude:
83
+ # - The ActiveRecord::SchemaMigration model which is internal to Rails
84
+ # and should not be part of the dumped data.
85
+ # - Models that don't have a corresponding table in the database.
86
+ # - Models whose corresponding database tables are empty.
87
+ models.select do |model|
88
+ ACTIVE_RECORD_INTERNAL_MODELS.exclude?(model.to_s) &&
89
+ model.table_exists? &&
90
+ model.exists?
91
+ end
92
+ end
93
+
94
+ # Internal: Returns a Boolean indicating whether the value for the "APPEND"
95
+ # key in the given Hash is equal to the String "true" (ignoring case),
96
+ # false if no value exists.
97
+ def retrieve_append_value(env)
98
+ parse_boolean_value(env["APPEND"])
99
+ end
100
+
101
+ # Internal: Returns a Boolean indicating whether the value for the "IMPORT"
102
+ # key in the given Hash is equal to the String "true" (ignoring case),
103
+ # false if no value exists.
104
+ def retrieve_import_value(env)
105
+ parse_boolean_value(env["IMPORT"])
106
+ end
107
+
108
+ # Internal: Retrieves an Array of Class constants parsed from the value for
109
+ # the "MODELS_EXCLUDE" key in the given Hash, and an empty Array if such
110
+ # key exists.
111
+ def retrieve_models_exclude(env)
112
+ env["MODELS_EXCLUDE"].to_s
113
+ .split(",")
114
+ .collect { |x| x.strip.underscore.singularize.camelize.constantize }
115
+ end
116
+
117
+ # Internal: Retrieves an Integer from the value for the "LIMIT" key in the
118
+ # given Hash, and nil if no such key exists.
119
+ def retrieve_limit_value(env)
120
+ retrieve_integer_value("LIMIT", env)
121
+ end
122
+
123
+ # Internal: Retrieves an Array of Symbols from the value for the "EXCLUDE"
124
+ # key from the given Hash, and nil if no such key exists.
125
+ def retrieve_exclude_value(env)
126
+ env["EXCLUDE"]&.split(",")&.map { |e| e.strip.to_sym }
127
+ end
128
+
129
+ # Internal: Retrieves the value for the "FILE" key from the given Hash, and
130
+ # 'db/seeds.rb' if no such key exists.
131
+ def retrieve_file_value(env)
132
+ env["FILE"] || "db/seeds.rb"
133
+ end
134
+
135
+ # Internal: Retrieves an Integer from the value for the "BATCH_SIZE" key in
136
+ # the given Hash, and nil if no such key exists.
137
+ def retrieve_batch_size_value(env)
138
+ retrieve_integer_value("BATCH_SIZE", env)
139
+ end
140
+
141
+ # Internal: Retrieves an Integer from the value for the given key in
142
+ # the given Hash, and nil if no such key exists.
143
+ def retrieve_integer_value(key, hash)
144
+ hash[key]&.to_i
145
+ end
146
+
147
+ # Internal: Parses a Boolean from the given value.
148
+ def parse_boolean_value(value)
149
+ value.to_s.downcase == "true"
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SeedDumpling
4
+ # Rails integration for SeedDupling
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load "tasks/seed_dumpling.rake"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SeedDumpling
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ipaddr"
4
+ require "seed_dumpling/dump_methods/enumeration"
5
+ require "seed_dumpling/dump_methods"
6
+ require "seed_dumpling/environment"
7
+
8
+ # Tool for extracting database records into a format suitable for
9
+ # Rails' db/seeds.rb. Supports various data types and configurable output formats.
10
+ class SeedDumpling
11
+ include Environment
12
+ include DumpMethods
13
+
14
+ require "seed_dumpling/railtie" if defined?(Rails)
15
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :db do
4
+ namespace :seed do
5
+ desc "Dump records from the database into db/seeds.rb"
6
+ task dump: :environment do
7
+ SeedDumpling.dump_using_environment(ENV)
8
+ end
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seed_dumpling
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mikael Henriksson
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-01-06 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord-import
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rails
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.0'
33
+ - - "<"
34
+ - !ruby/object:Gem::Version
35
+ version: '9.0'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '7.0'
43
+ - - "<"
44
+ - !ruby/object:Gem::Version
45
+ version: '9.0'
46
+ description: Dump (parts) of your database to db/seedspec.rb to get a headstart creating
47
+ a meaningful seedspec.rb file.
48
+ email: mikael@mhenrixon.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - LICENSE.txt
54
+ - README.md
55
+ - lib/seed_dumpling.rb
56
+ - lib/seed_dumpling/dump_methods.rb
57
+ - lib/seed_dumpling/dump_methods/enumeration.rb
58
+ - lib/seed_dumpling/environment.rb
59
+ - lib/seed_dumpling/railtie.rb
60
+ - lib/seed_dumpling/version.rb
61
+ - lib/tasks/seed_dumpling.rake
62
+ homepage: https://github.com/mhenrixon/dumpling
63
+ licenses:
64
+ - MIT
65
+ metadata:
66
+ rubygems_mfa_required: 'true'
67
+ homepage_uri: https://github.com/mhenrixon/dumpling
68
+ source_code_uri: https://github.com/mhenrixon/dumpling
69
+ changelog_uri: https://github.com/mhenrixon/dumpling/blob/up/CHANGELOG.md
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 3.2.0
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubygems_version: 3.6.2
85
+ specification_version: 4
86
+ summary: Seed Dumper for Rails
87
+ test_files: []