aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
authorMartin Emde <me@martinemde.com>2013-12-16 14:16:15 -0800
committerMartin Emde <me@martinemde.com>2013-12-16 14:16:15 -0800
commit8062a307942cb3f7a83bfc1a8cd81e3a1f8edc5b (patch)
treed048e55de1c12bf291317fe5c4441f1129cb420e /activerecord/lib/active_record
parent0dea33f770305f32ed7476f520f7c1ff17434fdc (diff)
downloadrails-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/active_record')
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb18
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)