D1D2D3D4D5
D1D2D3D4D5

Reputation: 151

How to access raw SQL statement generated by update_all (ActiveRecord method)

I'm just wondering if there's a way to access the raw SQL that's executed for an update_all ActiveRecord request. As an example, take the simple example below:

Something.update_all( ["to_update = ?"], ["id = ?" my_id] )

In the rails console I can see the raw SQL statement so I'm guessing it's available for me to access in some way?

PS - I'm specifically interested in update_all and can't change it to anything else.

Thanks!

Upvotes: 6

Views: 2698

Answers (2)

jvalanen
jvalanen

Reputation: 2977

If you have set RAILS_LOG_LEVEL=debug Rails shows you which SQL statement it executed.

# Start Rails console in debug mode
$ RAILS_LOG_LEVEL=debug rails c

# Run your query
[1] pry(main)> Something.update_all( ["to_update = ?"], ["id = ?" my_id] )
SQL (619.8ms) UPDATE "somethings" WHERE id = 123 SET to_update = my_id;

# ^it prints out the query it executed

Upvotes: 4

max
max

Reputation: 102240

If you look at the way update_all is implemented you can't call to_sql on it like you can on relations since it executes directly and returns an integer (the number of rows executed).

There is no way to tap into the flow or get the desired result except by duplicating the entire method and changing the last line:

module ActiveRecord
  # = Active Record \Relation
  class Relation
    def update_all_to_sql(updates)
      raise ArgumentError, "Empty list of attributes to change" if updates.blank?

      if eager_loading?
        relation = apply_join_dependency
        return relation.update_all(updates)
      end

      stmt = Arel::UpdateManager.new

      stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates))
      stmt.table(table)

      if has_join_values? || offset_value
        @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
      else
        stmt.key = arel_attribute(primary_key)
        stmt.take(arel.limit)
        stmt.order(*arel.orders)
        stmt.wheres = arel.constraints
      end

      #- @klass.connection.update stmt, "#{@klass} Update All"
      stmt.to_sql
    end
  end
end

The reason you see the log statements is that they are logged by the connection when it executes the statements. While you can override the logging its not really possible to do it for calls from a single AR method.

Upvotes: 5

Related Questions