diff options
author | Martin Emde <me@martinemde.com> | 2013-12-16 14:16:15 -0800 |
---|---|---|
committer | Martin Emde <me@martinemde.com> | 2013-12-16 14:16:15 -0800 |
commit | 8062a307942cb3f7a83bfc1a8cd81e3a1f8edc5b (patch) | |
tree | d048e55de1c12bf291317fe5c4441f1129cb420e /activerecord/lib | |
parent | 0dea33f770305f32ed7476f520f7c1ff17434fdc (diff) | |
download | rails-8062a307942cb3f7a83bfc1a8cd81e3a1f8edc5b.tar.gz rails-8062a307942cb3f7a83bfc1a8cd81e3a1f8edc5b.tar.bz2 rails-8062a307942cb3f7a83bfc1a8cd81e3a1f8edc5b.zip |
Better support for `where()` conditions that use an association name.
Using the name of an association in `where` previously worked only
if the value was a single `ActiveRecrd::Base` object. e.g.
Post.where(author: Author.first)
Any other values, including `nil`, would cause invalid SQL to be
generated. This change supports arguments in the `where` query
conditions where the key is a `belongs_to` association name and the
value is `nil`, an `Array` of `ActiveRecord::Base` objects, or an
`ActiveRecord::Relation` object.
# Given the Post model
class Post < ActiveRecord::Base
belongs_to :author
end
# nil value finds records where the association is not set
Post.where(author: nil)
# SELECT "posts".* FROM "posts" WHERE "posts"."author_id" IS NULL
# Array values find records where the association foreign key
# matches the ids of the passed ActiveRecord models, resulting
# in the same query as Post.where(author_id: [1,2])
authors_array = [Author.find(1), Author.find(2)]
Post.where(author: authors_array)
# ActiveRecord::Relation values find records using the same
# query as Post.where(author_id: Author.where(last_name: "Emde"))
Post.where(author: Author.where(last_name: "Emde"))
Polymorphic `belongs_to` associations will continue to be handled
appropriately, with the polymorphic `association_type` field added
to the query to match the base class of the value. This feature
previously only worked when the value was a single `ActveRecord::Base`.
class Post < ActiveRecord::Base
belongs_to :author, polymorphic: true
end
Post.where(author: Author.where(last_name: "Emde"))
# Generates a query similar to:
Post.where(author_id: Author.where(last_name: "Emde"), author_type: "Author")
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/relation/predicate_builder.rb | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index c60cd27a83..1252af7635 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -55,9 +55,9 @@ module ActiveRecord # # For polymorphic relationships, find the foreign key and type: # PriceEstimate.where(estimate_of: treasure) - if klass && value.is_a?(Base) && reflection = klass.reflect_on_association(column.to_sym) - if reflection.polymorphic? - queries << build(table[reflection.foreign_type], value.class.base_class) + if klass && reflection = klass.reflect_on_association(column.to_sym) + if reflection.polymorphic? && base_class = polymorphic_base_class_from_value(value) + queries << build(table[reflection.foreign_type], base_class) end column = reflection.foreign_key @@ -67,6 +67,18 @@ module ActiveRecord queries end + def self.polymorphic_base_class_from_value(value) + case value + when Relation + value.klass.base_class + when Array + val = value.compact.first + val.class.base_class if val.is_a?(Base) + when Base + value.class.base_class + end + end + def self.references(attributes) attributes.map do |key, value| if value.is_a?(Hash) |