dirty_seed 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +44 -0
- data/Rakefile +22 -0
- data/lib/dirty_seed.rb +23 -0
- data/lib/dirty_seed/assigners/dirty_assigner.rb +32 -0
- data/lib/dirty_seed/assigners/dirty_boolean.rb +14 -0
- data/lib/dirty_seed/assigners/dirty_date.rb +14 -0
- data/lib/dirty_seed/assigners/dirty_float.rb +28 -0
- data/lib/dirty_seed/assigners/dirty_integer.rb +86 -0
- data/lib/dirty_seed/assigners/dirty_string.rb +49 -0
- data/lib/dirty_seed/assigners/dirty_time.rb +14 -0
- data/lib/dirty_seed/data_model.rb +80 -0
- data/lib/dirty_seed/dirty_association.rb +106 -0
- data/lib/dirty_seed/dirty_attribute.rb +64 -0
- data/lib/dirty_seed/dirty_model.rb +123 -0
- data/lib/dirty_seed/engine.rb +11 -0
- data/lib/dirty_seed/exceptions.rb +6 -0
- data/lib/dirty_seed/method_missing_helper.rb +49 -0
- data/lib/dirty_seed/sorter.rb +118 -0
- data/lib/dirty_seed/version.rb +6 -0
- data/lib/tasks/dirty_seed_tasks.rake +8 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/javascript/packs/application.js +15 -0
- data/spec/dummy/app/jobs/application_job.rb +7 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/alfa.rb +5 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/bravo.rb +3 -0
- data/spec/dummy/app/models/charlie.rb +5 -0
- data/spec/dummy/app/models/delta.rb +4 -0
- data/spec/dummy/app/models/echo.rb +3 -0
- data/spec/dummy/app/models/foxtrot.rb +2 -0
- data/spec/dummy/app/models/golf.rb +2 -0
- data/spec/dummy/app/models/hotel.rb +4 -0
- data/spec/dummy/app/models/india.rb +4 -0
- data/spec/dummy/app/models/juliett.rb +21 -0
- data/spec/dummy/app/models/kilo.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +33 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/config/application.rb +18 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +62 -0
- data/spec/dummy/config/environments/production.rb +112 -0
- data/spec/dummy/config/environments/test.rb +49 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/dummy/config/initializers/assets.rb +12 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +28 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +27 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/puma.rb +38 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/config/storage.yml +34 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20200923100317_create_alfas.rb +15 -0
- data/spec/dummy/db/migrate/20200923100328_create_bravos.rb +12 -0
- data/spec/dummy/db/migrate/20200923100329_create_charlies.rb +9 -0
- data/spec/dummy/db/migrate/20200923100330_create_deltas.rb +10 -0
- data/spec/dummy/db/migrate/20200923100331_create_echos.rb +9 -0
- data/spec/dummy/db/migrate/20200923100332_create_foxtrots.rb +9 -0
- data/spec/dummy/db/migrate/20200923100334_create_hotels.rb +7 -0
- data/spec/dummy/db/migrate/20200923100335_create_indias.rb +11 -0
- data/spec/dummy/db/migrate/20200923100336_create_julietts.rb +11 -0
- data/spec/dummy/db/migrate/20200923100337_create_kilos.rb +13 -0
- data/spec/dummy/db/schema.rb +105 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +217 -0
- data/spec/dummy/log/test.log +95379 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/spec/factories/bars.rb +8 -0
- data/spec/dummy/spec/factories/foos.rb +7 -0
- data/spec/dummy/spec/models/alfa_spec.rb +6 -0
- data/spec/dummy/spec/models/bravo_spec.rb +6 -0
- data/spec/dummy/spec/models/charlie_spec.rb +6 -0
- data/spec/dummy/spec/models/delta_spec.rb +6 -0
- data/spec/dummy/spec/models/echo_spec.rb +6 -0
- data/spec/dummy/tmp/development_secret.txt +1 -0
- data/spec/lib/dirty_seed/assigners/dirty_assigner_spec.rb +13 -0
- data/spec/lib/dirty_seed/assigners/dirty_boolean_spec.rb +13 -0
- data/spec/lib/dirty_seed/assigners/dirty_date_spec.rb +15 -0
- data/spec/lib/dirty_seed/assigners/dirty_float_spec.rb +47 -0
- data/spec/lib/dirty_seed/assigners/dirty_integer_spec.rb +49 -0
- data/spec/lib/dirty_seed/assigners/dirty_string_spec.rb +15 -0
- data/spec/lib/dirty_seed/assigners/dirty_time_spec.rb +15 -0
- data/spec/lib/dirty_seed/data_model_spec.rb +72 -0
- data/spec/lib/dirty_seed/dirty_association_spec.rb +64 -0
- data/spec/lib/dirty_seed/dirty_attribute_spec.rb +49 -0
- data/spec/lib/dirty_seed/dirty_model_spec.rb +102 -0
- data/spec/lib/dirty_seed/sorter_spec.rb +46 -0
- data/spec/lib/tasks/dirty_seed_tasks_spec.rb +21 -0
- data/spec/rails_helper.rb +44 -0
- data/spec/support/helpers.rb +30 -0
- metadata +282 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DirtySeed
|
4
|
+
# Represents an Active Record association
|
5
|
+
class DirtyAssociation
|
6
|
+
extend ::DirtySeed::MethodMissingHelper
|
7
|
+
forward_missing_methods_to :reflections
|
8
|
+
|
9
|
+
attr_reader :dirty_model, :reflection
|
10
|
+
|
11
|
+
# Initializes an instance
|
12
|
+
# @param dirty_model [DirtySeed::DirtyModel]
|
13
|
+
# @param reflection [ActiveRecord::Reflection::BelongsToReflection]
|
14
|
+
# @return [DirtySeed::DirtyAssociation]
|
15
|
+
def initialize(dirty_model, reflection)
|
16
|
+
@dirty_model = dirty_model
|
17
|
+
@reflection = reflection
|
18
|
+
end
|
19
|
+
|
20
|
+
# Assigns a random value to the association
|
21
|
+
# @param instance [Object] an instance of a class inheriting from ApplicationRecord
|
22
|
+
# @return [void]
|
23
|
+
def assign_value(instance)
|
24
|
+
return if associated_models.empty?
|
25
|
+
|
26
|
+
instance.public_send(:"#{name}=", value)
|
27
|
+
rescue ArgumentError => e
|
28
|
+
@errors << e
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a random instance matching the reflection
|
32
|
+
# @return [Object] an instance of a class inheriting from ApplicationRecord
|
33
|
+
def value
|
34
|
+
random_model = associated_models.sample
|
35
|
+
random_id = random_model.pluck(:id).sample
|
36
|
+
random_model.find_by(id: random_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the reflection name
|
40
|
+
# @return [String]
|
41
|
+
def name
|
42
|
+
reflection.name
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the attribute containing the foreign key
|
46
|
+
# @return [Symbol]
|
47
|
+
def attribute
|
48
|
+
:"#{name}_id"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the attribute containing the foreign type (for polymorphic associations)
|
52
|
+
# @example
|
53
|
+
# Given Bar.belongs_to(:barable, polymorphic: true)
|
54
|
+
# And self.model == Bar
|
55
|
+
# Then it returns barable_type
|
56
|
+
# @return [Symbol]
|
57
|
+
def type_key
|
58
|
+
reflection.foreign_type&.to_sym
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns or defines associated_models
|
62
|
+
# @return [Array<Class>] a class inheriting from ApplicationRecord
|
63
|
+
def associated_models
|
64
|
+
polymorphic? ? polymorphic_associations : regular_associations
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns true if the reflection is polymorphic
|
68
|
+
# @example
|
69
|
+
# Given Bar.belongs_to(:barable, polymorphic: true)
|
70
|
+
# And self.model == Bar
|
71
|
+
# Then it returns true
|
72
|
+
# @return [Boolean]
|
73
|
+
def polymorphic?
|
74
|
+
reflection.options[:polymorphic]
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# Returns the reflected models for a regular association
|
80
|
+
# @example
|
81
|
+
# Given Bar.belongs_to(:foo)
|
82
|
+
# And Foo.has_many(:bars)
|
83
|
+
# And self.model == Bar
|
84
|
+
# Then it returns [Foo]
|
85
|
+
# @return [Array<Class>] a class inheriting from ApplicationRecord
|
86
|
+
def regular_associations
|
87
|
+
[reflection.klass]
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns the reflected models for a polymorphic association
|
91
|
+
# @example
|
92
|
+
# Given Bar.belongs_to(:barable, polymorphic: true)
|
93
|
+
# And Foo.has_many(:bars, as: :barable)
|
94
|
+
# And Zed.has_many(:bars, as: :barable)
|
95
|
+
# And #model is Bar
|
96
|
+
# Then it returns [Foo, Zed]
|
97
|
+
# @return [Array<Class>] a class inheriting from ApplicationRecord
|
98
|
+
def polymorphic_associations
|
99
|
+
DirtySeed::DataModel.active_record_models.select do |active_record_model|
|
100
|
+
active_record_model.reflections.values.any? do |arm_reflection|
|
101
|
+
arm_reflection.options[:as]&.to_sym == name
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DirtySeed
|
4
|
+
# Represents an Active Record attribute
|
5
|
+
class DirtyAttribute
|
6
|
+
extend ::DirtySeed::MethodMissingHelper
|
7
|
+
forward_missing_methods_to :column
|
8
|
+
|
9
|
+
attr_reader :dirty_model, :column
|
10
|
+
|
11
|
+
# Initializes an instance
|
12
|
+
# @param dirty_model [DirtySeed::DirtyModel]
|
13
|
+
# @param column [ActiveRecord::ConnectionAdapters::Column]
|
14
|
+
# @return [DirtySeed::DirtyAttribute]
|
15
|
+
def initialize(dirty_model, column)
|
16
|
+
@dirty_model = dirty_model
|
17
|
+
@column = column
|
18
|
+
end
|
19
|
+
|
20
|
+
# Assigns a value to the attribute
|
21
|
+
# @param instance [Object] an instance of a class inheriting from ApplicationRecord
|
22
|
+
# @param sequence [Integer]
|
23
|
+
# @return [void]
|
24
|
+
def assign_value(instance, sequence)
|
25
|
+
instance.assign_attributes(name => value(sequence))
|
26
|
+
rescue ArgumentError => e
|
27
|
+
dirty_model.errors << e
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns a value matching type and validators
|
31
|
+
# @param sequence [Integer]
|
32
|
+
# @return [Object, nil]
|
33
|
+
def value(sequence)
|
34
|
+
assigner = "DirtySeed::Assigners::Dirty#{type.capitalize}".constantize
|
35
|
+
assigner.new(self, sequence).value
|
36
|
+
# If attribute type is not currently handled (json, array...) return nil
|
37
|
+
rescue NameError
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns attribute name
|
42
|
+
# @return [Symbol]
|
43
|
+
def name
|
44
|
+
column.name.to_sym
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns attribute type
|
48
|
+
# @return [Symbol]
|
49
|
+
def type
|
50
|
+
return :float if column.sql_type_metadata.type == :decimal
|
51
|
+
return :time if column.sql_type_metadata.type == :datetime
|
52
|
+
|
53
|
+
column.sql_type_metadata.type
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns an validators related to the current attribute
|
57
|
+
# @return [Array<ActiveModel::Validations::EachValidators>]
|
58
|
+
def validators
|
59
|
+
dirty_model.validators.select do |validator|
|
60
|
+
validator.attributes.include? name
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DirtySeed
|
4
|
+
# Represents an Active Record model
|
5
|
+
class DirtyModel
|
6
|
+
extend ::DirtySeed::MethodMissingHelper
|
7
|
+
forward_missing_methods_to :model
|
8
|
+
|
9
|
+
attr_reader :model, :seeded
|
10
|
+
attr_writer :errors
|
11
|
+
|
12
|
+
PROTECTED_COLUMNS = %w[
|
13
|
+
id
|
14
|
+
type
|
15
|
+
created_at
|
16
|
+
updated_at
|
17
|
+
encrypted_password
|
18
|
+
reset_password_token
|
19
|
+
reset_password_sent_at
|
20
|
+
remember_created_at
|
21
|
+
].freeze
|
22
|
+
private_constant :PROTECTED_COLUMNS
|
23
|
+
|
24
|
+
# Initializes an instance
|
25
|
+
# @param model [Class] a class inheriting from ApplicationRecord
|
26
|
+
# @return [DirtySeed::DirtyModel]
|
27
|
+
def initialize(model)
|
28
|
+
@model = model
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns models where models are associated to the current model through a has_many or has_one associations
|
32
|
+
# @return [Array<Class>] ActiveRecord models
|
33
|
+
def associated_models
|
34
|
+
associations.map(&:associated_models).flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns an dirty associations representing the self.model belongs_to associations
|
38
|
+
# @return [Array<DirtySeed::DirtyAssociation>]
|
39
|
+
def associations
|
40
|
+
included_reflections.map do |reflection|
|
41
|
+
DirtySeed::DirtyAssociation.new(self, reflection)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns model attributes
|
46
|
+
# @return [Array<String>]
|
47
|
+
def attributes
|
48
|
+
included_columns.map do |column|
|
49
|
+
DirtySeed::DirtyAttribute.new(self, column)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns uniq errors
|
54
|
+
# @return [Array<Error>]
|
55
|
+
def errors
|
56
|
+
@errors.flatten.uniq
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates instances for each model
|
60
|
+
# @param count [Integer]
|
61
|
+
# @return [void]
|
62
|
+
def seed(count = 5)
|
63
|
+
reset_info
|
64
|
+
count.times do |sequence|
|
65
|
+
create_instance(sequence)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# Reset seed info
|
72
|
+
# @return [void]
|
73
|
+
def reset_info
|
74
|
+
@seeded = 0
|
75
|
+
@errors = []
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates an instance
|
79
|
+
# @param sequence [Integer]
|
80
|
+
# @return [void]
|
81
|
+
def create_instance(sequence)
|
82
|
+
instance = model.new
|
83
|
+
associations.each { |association| association.assign_value(instance) }
|
84
|
+
attributes.each { |attribute| attribute.assign_value(instance, sequence) }
|
85
|
+
if instance.save
|
86
|
+
@seeded += 1
|
87
|
+
else
|
88
|
+
@errors << instance.errors.full_messages
|
89
|
+
end
|
90
|
+
rescue ActiveRecord::ActiveRecordError => e
|
91
|
+
errors << e
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns columns that should be treated as regular attributes
|
95
|
+
# @return [Array<ActiveRecord::ConnectionAdapters::Column>]
|
96
|
+
def included_columns
|
97
|
+
excluded = PROTECTED_COLUMNS + reflection_related_attributes
|
98
|
+
model.columns.reject do |column|
|
99
|
+
column.name.in? excluded
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns attributes related to an association
|
104
|
+
# @example
|
105
|
+
# ["foo_id", "doable_id", "doable_type"]
|
106
|
+
# @return [Array<String>]
|
107
|
+
def reflection_related_attributes
|
108
|
+
all_reflection_related_attributes =
|
109
|
+
associations.map do |association|
|
110
|
+
[association.attribute, association.type_key].compact
|
111
|
+
end
|
112
|
+
all_reflection_related_attributes.flatten.map(&:to_s)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns reflections of the model
|
116
|
+
# @return [Array<ActiveRecord::Reflection::BelongsToReflection>]
|
117
|
+
def included_reflections
|
118
|
+
model.reflections.values.select do |reflection|
|
119
|
+
reflection.is_a? ActiveRecord::Reflection::BelongsToReflection
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DirtySeed
|
4
|
+
# Forwards missing method to another object if it matches
|
5
|
+
module MethodMissingHelper
|
6
|
+
# Defines missing_method and respond_to_missing? methods
|
7
|
+
# @param addressee_key [Object]
|
8
|
+
# @return [Object]
|
9
|
+
# @raise [NoMethodError]
|
10
|
+
def forward_missing_methods_to(addressee_key)
|
11
|
+
define_addressee(addressee_key)
|
12
|
+
define_method_missing
|
13
|
+
define_respond_to_missing?
|
14
|
+
end
|
15
|
+
|
16
|
+
# Defines addressee method
|
17
|
+
# @param addressee_key [Object]
|
18
|
+
# @return [void]
|
19
|
+
def define_addressee(addressee_key)
|
20
|
+
define_method :addressee do
|
21
|
+
public_send(addressee_key)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Defines missing_method method so it returns the adressee or calls super
|
26
|
+
# @example
|
27
|
+
# calling #name on a DirtyModel instance will call name on its @model object
|
28
|
+
# @return [void]
|
29
|
+
def define_method_missing
|
30
|
+
define_method :method_missing do |method_name, *args, &block|
|
31
|
+
return super(method_name, *args, &block) unless addressee.respond_to?(method_name)
|
32
|
+
|
33
|
+
addressee.public_send(method_name, *args, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Defines respond_to_missing? method to matches the method_missing behavior
|
38
|
+
# @return [void]
|
39
|
+
def define_respond_to_missing?
|
40
|
+
define_method :respond_to_missing? do |method_name, _include_private = false|
|
41
|
+
# :nocov:
|
42
|
+
return super(method_name, _include_private = false) unless addressee.respond_to?(method_name)
|
43
|
+
|
44
|
+
true
|
45
|
+
# :nocov:
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DirtySeed
|
4
|
+
# Sorts ActiveRecord models depending on their associations
|
5
|
+
class Sorter
|
6
|
+
attr_reader :models, :sorted, :checked, :current, :skip_optional
|
7
|
+
alias unsorted models
|
8
|
+
|
9
|
+
# Initializes an instance
|
10
|
+
# @param models [Array<Class>] models inheriting from ActiveRecord::Base
|
11
|
+
# @return [DirtySeed::Sorter]
|
12
|
+
def initialize(models = [])
|
13
|
+
@models = models
|
14
|
+
@sorted = []
|
15
|
+
@checked = []
|
16
|
+
@current = unsorted.first
|
17
|
+
end
|
18
|
+
|
19
|
+
# Sorts models depending on their associations
|
20
|
+
# @return [Array<Class>] classes inheriting from ActiveRecord::Base
|
21
|
+
def sort!
|
22
|
+
return sorted if unsorted.empty?
|
23
|
+
|
24
|
+
set_current
|
25
|
+
# active skip_optional option to prevent infinite loop
|
26
|
+
skip_optional! if break_loop?
|
27
|
+
insert_or_rotate
|
28
|
+
sort!
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Defines the current model to be sorted and add it to the checked ones
|
34
|
+
# @return [Class] class inheriting from ActiveRecord::Base
|
35
|
+
def set_current
|
36
|
+
@current = unsorted.first
|
37
|
+
checked << current
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns true if the current model has already been checked and skip optional option is not already activated
|
41
|
+
# @return [Boolean]
|
42
|
+
def break_loop?
|
43
|
+
current.in?(checked) && !skip_optional
|
44
|
+
end
|
45
|
+
|
46
|
+
# Activates skip_optional option to prevent infinite loop
|
47
|
+
# @return [void]
|
48
|
+
def skip_optional!
|
49
|
+
# if skip_optional is already true
|
50
|
+
# there is an infinite loop of belongs_to associations
|
51
|
+
raise DirtySeed::CyclicalAssociationsError if skip_optional
|
52
|
+
|
53
|
+
@skip_optional = true
|
54
|
+
@checked = []
|
55
|
+
end
|
56
|
+
|
57
|
+
# Chooses if current should be added to sorted ones or not
|
58
|
+
# @return [void]
|
59
|
+
def insert_or_rotate
|
60
|
+
# if the current is dependent form a non-sorted model
|
61
|
+
if dependent?
|
62
|
+
# rotate models array so current will be sorted at the end
|
63
|
+
unsorted.rotate!
|
64
|
+
else
|
65
|
+
# removed current from unsorted and add it to sorted
|
66
|
+
sorted << unsorted.shift
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns true if @current belongs_to a model that has not been sorted yet
|
71
|
+
# @return [Boolean]
|
72
|
+
def dependent?
|
73
|
+
return false if unsorted.one?
|
74
|
+
|
75
|
+
current.reflections.values.any? do |reflection|
|
76
|
+
belongs_to?(reflection) &&
|
77
|
+
unsorted.any? do |model|
|
78
|
+
mirror?(model, reflection)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns true if relfection is a :belongs_to kind
|
84
|
+
# @param reflection [ActiveRecord::Reflection::AssociationReflection]
|
85
|
+
# @return [Boolean]
|
86
|
+
def belongs_to?(reflection)
|
87
|
+
return false if reflection.options[:optional] && skip_optional
|
88
|
+
|
89
|
+
reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns true if model is or can be the <reflection> mirror
|
93
|
+
# @param model [ActiveRecord model]
|
94
|
+
# @param reflection [ActiveRecord::Reflection::AssociationReflection]
|
95
|
+
# @example
|
96
|
+
# Given `Foo.belongs_to(:bar)`
|
97
|
+
# And `Bar.has_many(:foos)`
|
98
|
+
# And <reflection> is the belongs_to reflection
|
99
|
+
# Then mirror?(Bar, reflection) returns true
|
100
|
+
# @example
|
101
|
+
# Given `Foo.belongs_to(:foable, polymorphic: true)`
|
102
|
+
# And `Bar.has_many(:foos, as: :foable)`
|
103
|
+
# And `Baz.has_many(:foos, as: :foable)`
|
104
|
+
# And <reflection> is the Foo "belongs_to" reflection
|
105
|
+
# Then mirror?(Bar, reflection) returns true
|
106
|
+
# And mirror?(Baz, reflection) returns true
|
107
|
+
# @return [Boolean]
|
108
|
+
def mirror?(model, reflection)
|
109
|
+
if reflection.options[:polymorphic]
|
110
|
+
model.reflections.values.any? do |model_reflection|
|
111
|
+
model_reflection.options[:as] == reflection.name
|
112
|
+
end
|
113
|
+
else
|
114
|
+
model == reflection.klass
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|