The original ActiveRecord models:
class Food < ActiveRecord::Base has_and_belongs_to_many :ingredients scope :preservative, joins(:ingredients).where("ingredients.preservative" => true) end class Ingredient < ActiveRecord::Base endare tied together via a 1:n relationship. Furthermore there is scope, which shrinks the amount of foods having preservative ingredients. It has a name :preservative and receives a join and a condition (for more detailed explanation of ActiveRecord scopes go read: Scope the model!).
But it suffers knowing about the internal table structure of a different model, which increases the coupling between both classes.
That issue can be solved by merging scopes of different model classes:
class Food < ActiveRecord::Base has_and_belongs_to_many :ingredients scope :preservative, joins(:ingredients).merge(Ingredient.preservative) end class Ingredient < ActiveRecord::Base scope :preservative, where("#{table_name}.preservative" => true) endNow the Ingredient model takes the responsibility for its scope, where it belongs (please note that using ActiveRecord::ModelSchema::ClassMethods#table_name removes the knowledge about the table name in the scope itself).
The interesting part is the scope Food#preservative. Besides still joining the other model via the association, it uses ActiveRecord::SpawnMethods#merge for merging the scope Ingredient#preservative into the scope Food#preservative.
The usage:
preservative_foods = Food.preservativeFurther articles of interest:
Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17
Keine Kommentare:
Kommentar veröffentlichen