aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x[-rw-r--r--]activerecord/lib/active_record/base.rb20
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb4
-rw-r--r--activerecord/test/cases/base_test.rb19
-rw-r--r--activerecord/test/models/author.rb1
5 files changed, 41 insertions, 7 deletions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index d7c67bc10d..fc6d762fcd 100644..100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -769,10 +769,24 @@ module ActiveRecord #:nodoc:
# :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
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index aaf9e2e73f..8fc89de22b 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -153,6 +153,10 @@ module ActiveRecord
"="
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.
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index f1d13698c3..c2a0fb72bf 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -523,6 +523,10 @@ module ActiveRecord
"= 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=)
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 67358fedd6..bda6f346f0 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -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 @@ class BasicsTest < ActiveRecord::TestCase
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
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index c6aa0293c2..ad0123cf2c 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -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"