Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'active_record'
- module RailsAdmin
- module ClassMethods
- # Returns the actual value that gets passed to .joins to join the target model to this one.
- def join_value_for(model, discriminant=:primary_association?)
- path = method_path_to(model, discriminant)
- return path[0] if path.length < 2
- join_value = {path[-2] => path[-1]}
- path[0...-2].reverse_each do |x|
- join_value = {x => join_value}
- end
- join_value
- end
- # Returns the methods associated with the reflection path that must be traversed to join
- # this model and the target model.
- def method_path_to(model, discriminant=:primary_association?)
- reflection_path_to(model, discriminant).map(&:name)
- end
- # Returns the reflection path that must be traversed to join this model and the target model.
- def reflection_path_to(model, discriminant=:primary_association?)
- join_path_to(model).each_cons(2)
- .map { |x,y| x.primary_reflection_with(y, discriminant) }
- end
- # Returns the shortest path between this model and any other model (the target model).
- def join_path_to(model)
- paths = [[self]]
- paths.each do |path|
- # Breadth-first search for the target model
- return path if (path[0] == self) && (path[-1] == model)
- path[-1].neighboring_joinables
- .map { |joinable| path + [joinable] }
- .select { |_path| _path.length == _path.uniq.length }
- .each { |selected| paths.push selected }
- end
- end
- # Returns models that 'neighbor' (in terms of associations) this model.
- def neighboring_joinables
- reflections.values.map(&:klass).uniq
- end
- # Returns all the reflections between this model and a neighboring model.
- def reflections_with(model)
- reflections.values.select { |reflection| reflection.klass == model}
- end
- # Uses a key paramater to preferentially select one reflection (possibly from many)
- # between this model and a neighboring model. Requires the monkey-patching of
- # ActiveRecord::Associations::Builder::Association to include :additional_options as a
- # valid option for all the association types.
- def primary_reflection_with(model, key=:primary_association?)
- # The presence of key parameter allows for more flexibility;
- # at Beech Street, I use the method parameter in conjunction with
- # specially marked associations to perform different joins for reporting
- # than for data access restrictions.
- return reflections_with(model)[0] if reflections_with(model).count == 1
- reflections_with(model).find do |reflection|
- # TODO: There is definitely some room for improvment of this algorithm.
- # Ideally, I'd like to see it be able to correctly distinguish from
- # from among several possible associations without the use of such flags.
- reflection.options[:additional_options].present? && reflection.options[:additional_options][key]
- end
- end
- end
- ActiveRecord::Base.send :extend, ClassMethods
- end
Add Comment
Please, Sign In to add comment