2012-05-30 18:09:13 -04:00
|
|
|
require "cases/helper"
|
2015-01-09 12:29:13 -05:00
|
|
|
require "models/author"
|
|
|
|
require "models/binary"
|
|
|
|
require "models/cake_designer"
|
|
|
|
require "models/chef"
|
|
|
|
require "models/comment"
|
|
|
|
require "models/edge"
|
2015-02-04 10:44:48 -05:00
|
|
|
require "models/essay"
|
2015-01-09 12:29:13 -05:00
|
|
|
require "models/post"
|
|
|
|
require "models/price_estimate"
|
|
|
|
require "models/topic"
|
|
|
|
require "models/treasure"
|
|
|
|
require "models/vertex"
|
2012-05-30 18:09:13 -04:00
|
|
|
|
|
|
|
module ActiveRecord
|
|
|
|
class WhereTest < ActiveRecord::TestCase
|
2015-02-04 10:44:48 -05:00
|
|
|
fixtures :posts, :edges, :authors, :binaries, :essays
|
2013-01-24 17:29:03 -05:00
|
|
|
|
|
|
|
def test_where_copies_bind_params
|
|
|
|
author = authors(:david)
|
|
|
|
posts = author.posts.where('posts.id != 1')
|
|
|
|
joined = Post.where(id: posts)
|
|
|
|
|
|
|
|
assert_operator joined.length, :>, 0
|
|
|
|
|
|
|
|
joined.each { |post|
|
|
|
|
assert_equal author, post.author
|
|
|
|
assert_not_equal 1, post.id
|
|
|
|
}
|
|
|
|
end
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2015-01-19 17:17:43 -05:00
|
|
|
def test_where_copies_bind_params_in_the_right_order
|
|
|
|
author = authors(:david)
|
|
|
|
posts = author.posts.where.not(id: 1)
|
|
|
|
joined = Post.where(id: posts, title: posts.first.title)
|
|
|
|
|
|
|
|
assert_equal joined, [posts.first]
|
|
|
|
end
|
|
|
|
|
2015-01-09 12:29:13 -05:00
|
|
|
def test_where_copies_arel_bind_params
|
|
|
|
chef = Chef.create!
|
|
|
|
CakeDesigner.create!(chef: chef)
|
|
|
|
|
|
|
|
cake_designers = CakeDesigner.joins(:chef).where(chefs: { id: chef.id })
|
|
|
|
chefs = Chef.where(employable: cake_designers)
|
|
|
|
|
|
|
|
assert_equal [chef], chefs.to_a
|
|
|
|
end
|
|
|
|
|
2013-11-02 22:45:03 -04:00
|
|
|
def test_rewhere_on_root
|
|
|
|
assert_equal posts(:welcome), Post.rewhere(title: 'Welcome to the weblog').first
|
|
|
|
end
|
|
|
|
|
2012-09-11 14:11:51 -04:00
|
|
|
def test_belongs_to_shallow_where
|
2012-09-12 18:32:50 -04:00
|
|
|
author = Author.new
|
|
|
|
author.id = 1
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
assert_equal Post.where(author_id: 1).to_sql, Post.where(author: author).to_sql
|
2012-09-11 14:11:51 -04:00
|
|
|
end
|
|
|
|
|
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")
2013-12-16 17:16:15 -05:00
|
|
|
def test_belongs_to_nil_where
|
|
|
|
assert_equal Post.where(author_id: nil).to_sql, Post.where(author: nil).to_sql
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_belongs_to_array_value_where
|
|
|
|
assert_equal Post.where(author_id: [1,2]).to_sql, Post.where(author: [1,2]).to_sql
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_belongs_to_nested_relation_where
|
|
|
|
expected = Post.where(author_id: Author.where(id: [1,2])).to_sql
|
|
|
|
actual = Post.where(author: Author.where(id: [1,2])).to_sql
|
|
|
|
|
|
|
|
assert_equal expected, actual
|
|
|
|
end
|
|
|
|
|
2012-09-11 14:11:51 -04:00
|
|
|
def test_belongs_to_nested_where
|
2012-09-12 18:32:50 -04:00
|
|
|
parent = Comment.new
|
|
|
|
parent.id = 1
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
expected = Post.where(comments: { parent_id: 1 }).joins(:comments)
|
|
|
|
actual = Post.where(comments: { parent: parent }).joins(:comments)
|
|
|
|
|
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
2012-09-11 14:11:51 -04:00
|
|
|
end
|
|
|
|
|
2014-08-14 06:44:29 -04:00
|
|
|
def test_belongs_to_nested_where_with_relation
|
|
|
|
author = authors(:david)
|
|
|
|
|
|
|
|
expected = Author.where(id: author ).joins(:posts)
|
|
|
|
actual = Author.where(posts: { author_id: Author.where(id: author.id) }).joins(:posts)
|
|
|
|
|
|
|
|
assert_equal expected.to_a, actual.to_a
|
|
|
|
end
|
|
|
|
|
2012-09-11 14:11:51 -04:00
|
|
|
def test_polymorphic_shallow_where
|
2012-09-12 18:32:50 -04:00
|
|
|
treasure = Treasure.new
|
|
|
|
treasure.id = 1
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: 1)
|
|
|
|
actual = PriceEstimate.where(estimate_of: treasure)
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
2012-09-11 14:11:51 -04:00
|
|
|
end
|
|
|
|
|
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")
2013-12-16 17:16:15 -05:00
|
|
|
def test_polymorphic_nested_array_where
|
|
|
|
treasure = Treasure.new
|
|
|
|
treasure.id = 1
|
|
|
|
hidden = HiddenTreasure.new
|
|
|
|
hidden.id = 2
|
|
|
|
|
|
|
|
expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: [treasure, hidden])
|
|
|
|
actual = PriceEstimate.where(estimate_of: [treasure, hidden])
|
|
|
|
|
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_polymorphic_nested_relation_where
|
|
|
|
expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: Treasure.where(id: [1,2]))
|
|
|
|
actual = PriceEstimate.where(estimate_of: Treasure.where(id: [1,2]))
|
|
|
|
|
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
|
|
|
end
|
|
|
|
|
2012-09-11 14:11:51 -04:00
|
|
|
def test_polymorphic_sti_shallow_where
|
2012-09-12 18:32:50 -04:00
|
|
|
treasure = HiddenTreasure.new
|
|
|
|
treasure.id = 1
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: 1)
|
|
|
|
actual = PriceEstimate.where(estimate_of: treasure)
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
2012-09-11 14:11:51 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_polymorphic_nested_where
|
2012-09-12 18:32:50 -04:00
|
|
|
thing = Post.new
|
|
|
|
thing.id = 1
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
expected = Treasure.where(price_estimates: { thing_type: 'Post', thing_id: 1 }).joins(:price_estimates)
|
|
|
|
actual = Treasure.where(price_estimates: { thing: thing }).joins(:price_estimates)
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
2012-09-11 14:11:51 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_polymorphic_sti_nested_where
|
2012-09-12 18:32:50 -04:00
|
|
|
treasure = HiddenTreasure.new
|
|
|
|
treasure.id = 1
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
expected = Treasure.where(price_estimates: { estimate_of_type: 'Treasure', estimate_of_id: 1 }).joins(:price_estimates)
|
|
|
|
actual = Treasure.where(price_estimates: { estimate_of: treasure }).joins(:price_estimates)
|
2012-09-11 14:11:51 -04:00
|
|
|
|
2012-09-12 18:32:50 -04:00
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
2012-09-11 14:11:51 -04:00
|
|
|
end
|
2013-08-20 07:21:23 -04:00
|
|
|
|
|
|
|
def test_decorated_polymorphic_where
|
|
|
|
treasure_decorator = Struct.new(:model) do
|
|
|
|
def self.method_missing(method, *args, &block)
|
|
|
|
Treasure.send(method, *args, &block)
|
|
|
|
end
|
|
|
|
|
|
|
|
def is_a?(klass)
|
|
|
|
model.is_a?(klass)
|
|
|
|
end
|
|
|
|
|
|
|
|
def method_missing(method, *args, &block)
|
|
|
|
model.send(method, *args, &block)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
treasure = Treasure.new
|
|
|
|
treasure.id = 1
|
|
|
|
decorated_treasure = treasure_decorator.new(treasure)
|
|
|
|
|
|
|
|
expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: 1)
|
|
|
|
actual = PriceEstimate.where(estimate_of: decorated_treasure)
|
|
|
|
|
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
|
|
|
end
|
2012-05-30 18:09:13 -04:00
|
|
|
|
2013-05-01 14:33:11 -04:00
|
|
|
def test_aliased_attribute
|
|
|
|
expected = Topic.where(heading: 'The First Topic')
|
|
|
|
actual = Topic.where(title: 'The First Topic')
|
|
|
|
|
|
|
|
assert_equal expected.to_sql, actual.to_sql
|
|
|
|
end
|
|
|
|
|
2012-05-30 18:09:13 -04:00
|
|
|
def test_where_error
|
|
|
|
assert_raises(ActiveRecord::StatementInvalid) do
|
|
|
|
Post.where(:id => { 'posts.author_id' => 10 }).first
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_with_table_name
|
|
|
|
post = Post.first
|
|
|
|
assert_equal post, Post.where(:posts => { 'id' => post.id }).first
|
|
|
|
end
|
2012-07-05 07:24:59 -04:00
|
|
|
|
|
|
|
def test_where_with_table_name_and_empty_hash
|
2013-02-08 16:53:49 -05:00
|
|
|
assert_equal 0, Post.where(:posts => {}).count
|
2012-07-05 07:24:59 -04:00
|
|
|
end
|
|
|
|
|
2013-01-08 17:00:26 -05:00
|
|
|
def test_where_with_table_name_and_empty_array
|
2013-02-08 14:22:10 -05:00
|
|
|
assert_equal 0, Post.where(:id => []).count
|
2013-01-08 17:00:26 -05:00
|
|
|
end
|
|
|
|
|
2012-07-05 07:24:59 -04:00
|
|
|
def test_where_with_empty_hash_and_no_foreign_key
|
2013-02-08 16:53:49 -05:00
|
|
|
assert_equal 0, Edge.where(:sink => {}).count
|
2012-07-05 07:24:59 -04:00
|
|
|
end
|
2012-12-06 22:00:33 -05:00
|
|
|
|
|
|
|
def test_where_with_blank_conditions
|
|
|
|
[[], {}, nil, ""].each do |blank|
|
|
|
|
assert_equal 4, Edge.where(blank).order("sink_id").to_a.size
|
|
|
|
end
|
|
|
|
end
|
2014-07-06 01:49:19 -04:00
|
|
|
|
|
|
|
def test_where_with_integer_for_string_column
|
|
|
|
count = Post.where(:title => 0).count
|
|
|
|
assert_equal 0, count
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_with_float_for_string_column
|
|
|
|
count = Post.where(:title => 0.0).count
|
|
|
|
assert_equal 0, count
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_with_boolean_for_string_column
|
|
|
|
count = Post.where(:title => false).count
|
|
|
|
assert_equal 0, count
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_with_decimal_for_string_column
|
|
|
|
count = Post.where(:title => BigDecimal.new(0)).count
|
|
|
|
assert_equal 0, count
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_with_duration_for_string_column
|
|
|
|
count = Post.where(:title => 0.seconds).count
|
|
|
|
assert_equal 0, count
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_with_integer_for_binary_column
|
|
|
|
count = Binary.where(:data => 0).count
|
|
|
|
assert_equal 0, count
|
|
|
|
end
|
2015-02-04 10:44:48 -05:00
|
|
|
|
|
|
|
def test_where_on_association_with_custom_primary_key
|
|
|
|
author = authors(:david)
|
|
|
|
essay = Essay.where(writer: author).first
|
|
|
|
|
|
|
|
assert_equal essays(:david_modest_proposal), essay
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_on_association_with_custom_primary_key_with_relation
|
|
|
|
author = authors(:david)
|
|
|
|
essay = Essay.where(writer: Author.where(id: author.id)).first
|
|
|
|
|
|
|
|
assert_equal essays(:david_modest_proposal), essay
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_on_association_with_relation_performs_subselect_not_two_queries
|
|
|
|
author = authors(:david)
|
|
|
|
|
|
|
|
assert_queries(1) do
|
|
|
|
Essay.where(writer: Author.where(id: author.id)).to_a
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_on_association_with_custom_primary_key_with_array_of_base
|
|
|
|
author = authors(:david)
|
|
|
|
essay = Essay.where(writer: [author]).first
|
|
|
|
|
|
|
|
assert_equal essays(:david_modest_proposal), essay
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_where_on_association_with_custom_primary_key_with_array_of_ids
|
|
|
|
essay = Essay.where(writer: ["David"]).first
|
|
|
|
|
|
|
|
assert_equal essays(:david_modest_proposal), essay
|
|
|
|
end
|
2015-10-02 04:26:16 -04:00
|
|
|
|
|
|
|
def test_where_with_strong_parameters
|
|
|
|
protected_params = Class.new do
|
|
|
|
attr_reader :permitted
|
|
|
|
alias :permitted? :permitted
|
|
|
|
|
|
|
|
def initialize(parameters)
|
|
|
|
@parameters = parameters
|
|
|
|
@permitted = false
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_h
|
|
|
|
@parameters
|
|
|
|
end
|
|
|
|
|
|
|
|
def permit!
|
|
|
|
@permitted = true
|
|
|
|
self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
author = authors(:david)
|
|
|
|
params = protected_params.new(name: author.name)
|
|
|
|
assert_raises(ActiveModel::ForbiddenAttributesError) { Author.where(params) }
|
|
|
|
assert_equal author, Author.where(params.permit!).first
|
|
|
|
end
|
2012-05-30 18:09:13 -04:00
|
|
|
end
|
|
|
|
end
|