Support :limit on update_all so that has_many with :limit can be safely updated

Signed-off-by: Michael Koziarski <michael@koziarski.com>
This commit is contained in:
Tarmo Tänav 2008-09-10 13:39:50 +03:00 committed by Michael Koziarski
parent 14d1560e85
commit 7c9851dbb6
5 changed files with 41 additions and 7 deletions

20
activerecord/lib/active_record/base.rb Normal file → Executable file

@ -769,10 +769,24 @@ def destroy(id)
# :order => 'created_at', :limit => 5 )
def update_all(updates, conditions = nil, options = {})
sql = "UPDATE #{quoted_table_name} SET #{sanitize_sql_for_assignment(updates)} "
scope = scope(:find)
add_conditions!(sql, conditions, scope)
add_order!(sql, options[:order], nil)
add_limit!(sql, options, nil)
select_sql = ""
add_conditions!(select_sql, conditions, scope)
if options.has_key?(:limit) || (scope && scope[:limit])
# Only take order from scope if limit is also provided by scope, this
# is useful for updating a has_many association with a limit.
add_order!(select_sql, options[:order], scope)
add_limit!(select_sql, options, scope)
sql.concat(connection.limited_update_conditions(select_sql, quoted_table_name, connection.quote_column_name(primary_key)))
else
add_order!(select_sql, options[:order], nil)
sql.concat(select_sql)
end
connection.update(sql, "#{name} Update")
end

@ -153,6 +153,10 @@ def case_sensitive_equality_operator
"="
end
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
"WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
end
protected
# Returns an array of record hashes with the column names as keys and
# column values as values.

@ -523,6 +523,10 @@ def case_sensitive_equality_operator
"= BINARY"
end
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
where_sql
end
private
def connect
@connection.reconnect = true if @connection.respond_to?(:reconnect=)

@ -76,7 +76,7 @@ class TopicWithProtectedContentAndAccessibleAuthorName < ActiveRecord::Base
end
class BasicsTest < ActiveRecord::TestCase
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
def test_table_exists
assert !NonExistentTable.table_exists?
@ -664,10 +664,21 @@ def test_update_all_with_order_and_limit
end
end
def test_update_all_ignores_order_limit_from_association
author = Author.find(1)
def test_update_all_ignores_order_without_limit_from_association
author = authors(:david)
assert_nothing_raised do
assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all("body = 'bulk update!'")
assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all([ "body = ?", "bulk update!" ])
end
end
def test_update_all_with_order_and_limit_updates_subset_only
author = authors(:david)
assert_nothing_raised do
assert_equal 1, author.posts_sorted_by_id_limited.size
assert_equal 2, author.posts_sorted_by_id_limited.find(:all, :limit => 2).size
assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ])
assert_equal "bulk update!", posts(:welcome).body
assert_not_equal "bulk update!", posts(:thinking).body
end
end

@ -2,6 +2,7 @@ class Author < ActiveRecord::Base
has_many :posts, :accessible => true
has_many :posts_with_comments, :include => :comments, :class_name => "Post"
has_many :posts_with_comments_sorted_by_comment_id, :include => :comments, :class_name => "Post", :order => 'comments.id'
has_many :posts_sorted_by_id_limited, :class_name => "Post", :order => 'posts.id', :limit => 1
has_many :posts_with_categories, :include => :categories, :class_name => "Post"
has_many :posts_with_comments_and_categories, :include => [ :comments, :categories ], :order => "posts.id", :class_name => "Post"
has_many :posts_containing_the_letter_a, :class_name => "Post"