class DirtySeed::Sorter
Sorts ActiveRecord models depending on their associations
Attributes
Public Class Methods
Initializes an instance @param models [Array<DirtySeed::Model>] @return [DirtySeed::Sorter]
# File lib/dirty_seed/sorter.rb, line 9 def initialize(models = []) @models = models end
Public Instance Methods
Sorts models depending on their associations @return [Array<Class>] classes inheriting from ActiveRecord::Base @note Use procedural over fonctional -> do not use recursivity
# File lib/dirty_seed/sorter.rb, line 16 def sort reset until unsorted.empty? count_up || break self.current = unsorted.first sort_current end sorted end
Private Instance Methods
Updates count or return false if limite is exceeded @return [Boolean]
# File lib/dirty_seed/sorter.rb, line 43 def count_up return false if counter >= models.count * 5 self.counter = counter + 1 end
Is the association dependent from an unsorted model? @param association [DirtySeed::Association] @return [Boolean]
# File lib/dirty_seed/sorter.rb, line 119 def dependent?(association) return if flexible_dependencies && association.optional? # When flexible_dependencies is activated, at least one polymorphic relation should be sorted # Either, all polymorphic relations should be sorted method = flexible_dependencies ? :any? : :all? association.associated_models.public_send(method) do |active_record_model| unsorted.map(&:__getobj__).include? active_record_model end end
Activates flexible_dependencies
option to prevent infinite loop @return [void]
# File lib/dirty_seed/sorter.rb, line 69 def flexible_dependencies! self.flexible_dependencies = true self.checked = Set.new end
Is current independent from any unsorted model? @return [Boolean] @example
Given a model Foo And Foo.belongs_to(:bar) And Foo.belongs_to(:zed, optional: true) And Bar is sorted And Zed is not sorted yet If @flexible_dependencies is false (all relations should be sorted) Then Foo is not independent Else (required relations should be sorted) Then Foo is independent
@example
Given a model Foo And Foo.belongs_to(:fooable, polymorphic: true) And Bar.has_many(:foos, as: :fooable) And Zed.has_many(:foos, as: :fooable) And Bar is sorted And Zed is not sorted yet If @flexible_dependencies is false (all relations should be sorted) Then Foo is not independent Else (at least one relation - in case of polymorpism - should be sorted) Then Foo is independent
# File lib/dirty_seed/sorter.rb, line 110 def independent? return true if unsorted.one? current.associations.none? { |association| dependent?(association) } end
Chooses if current should be added to sorted ones or not @return [void]
# File lib/dirty_seed/sorter.rb, line 76 def insert_or_rotate # if current is independent of any unsorted model if independent? # removed current from unsorted and add it to sorted sorted << unsorted.shift else # rotate models array so current will be sorted at the end unsorted.rotate! end end
Is the current model already checked? @return [Boolean]
# File lib/dirty_seed/sorter.rb, line 63 def loop? checked.include? current end
Reset state before sorting @return [void]
# File lib/dirty_seed/sorter.rb, line 33 def reset self.counter = 0 self.flexible_dependencies = false self.unsorted = models.clone self.sorted = [] self.checked = Set.new end
Sort the current model @return [void]
# File lib/dirty_seed/sorter.rb, line 51 def sort_current flexible_dependencies! if loop? insert_or_rotate # rescue from errors coming from RDBMS or related rescue StandardError unsorted.delete(current) ensure checked << current end