Navigation Menu

Skip to content

Commit

Permalink
Support updates with joins. Fixes rails#522.
Browse files Browse the repository at this point in the history
  • Loading branch information
jonleighton committed Aug 11, 2011
1 parent e6fdfd0 commit bb40a97
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 4 deletions.
Expand Up @@ -306,6 +306,15 @@ def sanitize_limit(limit)
end
end

# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
# on mysql (even when aliasing the tables), but mysql allows using JOIN directly in
# an UPDATE statement, so in the mysql adapters we redefine this to do that.
def join_to_update(update, select) #:nodoc:
subselect = select.clone
subselect.ast.cores.last.projections = [update.ast.key]
update.wheres = [update.ast.key.in(subselect)]
end

protected
# Returns an array of record hashes with the column names as keys and
# column values as values.
Expand Down
Expand Up @@ -577,6 +577,10 @@ def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
where_sql
end

def join_to_update(update, select) #:nodoc:
update.table select.ast.cores.last.source
end

protected
def quoted_columns_for_index(column_names, options = {})
length = options[:length] if options.is_a?(Hash)
Expand Down
Expand Up @@ -491,6 +491,10 @@ def release_savepoint
execute("RELEASE SAVEPOINT #{current_savepoint_name}")
end

def join_to_update(update, select) #:nodoc:
update.table select.ast.cores.last.source
end

# SCHEMA STATEMENTS ========================================

def structure_dump #:nodoc:
Expand Down
13 changes: 9 additions & 4 deletions activerecord/lib/active_record/relation.rb
Expand Up @@ -217,13 +217,18 @@ def update_all(updates, conditions = nil, options = {})
where(conditions).apply_finder_options(options.slice(:limit, :order)).update_all(updates)
else
stmt = arel.compile_update(Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates)))
stmt.key = table[primary_key]

if limit = arel.limit
stmt.take limit
if joins_values.any?
@klass.connection.join_to_update(stmt, arel)
else
if limit = arel.limit
stmt.take limit
end

stmt.order(*arel.orders)
end

stmt.order(*arel.orders)
stmt.key = table[primary_key]
@klass.connection.update stmt, 'SQL', bind_values
end
end
Expand Down
8 changes: 8 additions & 0 deletions activerecord/test/cases/relations_test.rb
Expand Up @@ -965,4 +965,12 @@ def test_eager_loading_with_conditions_on_joins
def test_ordering_with_extra_spaces
assert_equal authors(:david), Author.order('id DESC , name DESC').last
end

def test_update_all_with_joins
comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id)
count = comments.count

assert_equal count, comments.update_all(:post_id => posts(:thinking).id)
assert_equal posts(:thinking), comments(:greetings).post
end
end

0 comments on commit bb40a97

Please sign in to comment.