Guest User

Untitled

a guest
Nov 18th, 2018
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.03 KB | None | 0 0
  1. require 'active_record'
  2.  
  3. module RailsAdmin
  4. module ClassMethods
  5. # Returns the actual value that gets passed to .joins to join the target model to this one.
  6. def join_value_for(model, discriminant=:primary_association?)
  7. path = method_path_to(model, discriminant)
  8. return path[0] if path.length < 2
  9.  
  10. join_value = {path[-2] => path[-1]}
  11. path[0...-2].reverse_each do |x|
  12. join_value = {x => join_value}
  13. end
  14. join_value
  15. end
  16.  
  17. # Returns the methods associated with the reflection path that must be traversed to join
  18. # this model and the target model.
  19. def method_path_to(model, discriminant=:primary_association?)
  20. reflection_path_to(model, discriminant).map(&:name)
  21. end
  22.  
  23. # Returns the reflection path that must be traversed to join this model and the target model.
  24. def reflection_path_to(model, discriminant=:primary_association?)
  25. join_path_to(model).each_cons(2)
  26. .map { |x,y| x.primary_reflection_with(y, discriminant) }
  27. end
  28.  
  29. # Returns the shortest path between this model and any other model (the target model).
  30. def join_path_to(model)
  31. paths = [[self]]
  32. paths.each do |path|
  33. # Breadth-first search for the target model
  34. return path if (path[0] == self) && (path[-1] == model)
  35.  
  36. path[-1].neighboring_joinables
  37. .map { |joinable| path + [joinable] }
  38. .select { |_path| _path.length == _path.uniq.length }
  39. .each { |selected| paths.push selected }
  40. end
  41. end
  42.  
  43. # Returns models that 'neighbor' (in terms of associations) this model.
  44. def neighboring_joinables
  45. reflections.values.map(&:klass).uniq
  46. end
  47.  
  48. # Returns all the reflections between this model and a neighboring model.
  49. def reflections_with(model)
  50. reflections.values.select { |reflection| reflection.klass == model}
  51. end
  52.  
  53. # Uses a key paramater to preferentially select one reflection (possibly from many)
  54. # between this model and a neighboring model. Requires the monkey-patching of
  55. # ActiveRecord::Associations::Builder::Association to include :additional_options as a
  56. # valid option for all the association types.
  57. def primary_reflection_with(model, key=:primary_association?)
  58. # The presence of key parameter allows for more flexibility;
  59. # at Beech Street, I use the method parameter in conjunction with
  60. # specially marked associations to perform different joins for reporting
  61. # than for data access restrictions.
  62. return reflections_with(model)[0] if reflections_with(model).count == 1
  63.  
  64. reflections_with(model).find do |reflection|
  65. # TODO: There is definitely some room for improvment of this algorithm.
  66. # Ideally, I'd like to see it be able to correctly distinguish from
  67. # from among several possible associations without the use of such flags.
  68. reflection.options[:additional_options].present? && reflection.options[:additional_options][key]
  69. end
  70. end
  71. end
  72.  
  73. ActiveRecord::Base.send :extend, ClassMethods
  74. end
Add Comment
Please, Sign In to add comment