将Rails模型转换为SQL插入查询?

Hen*_*hiu 7 ruby activerecord ruby-on-rails

有没有办法将Rails模型转换为插入查询?

例如,如果我有一个类似的模型:

m = Model.new
m.url = "url"
m.header = "header"
Run Code Online (Sandbox Code Playgroud)

如果我执行m.save,如何获取ActiveRecord将生成的相应SQL查询?

我想得到:"INSERT INTO模型(url,header)VALUES('url','header')"如果可能的话.

注意:我不想实际保存模型并返回查询(从日志文件等).如果我选择保存它,我想获得查询.

Nob*_*obu 8

在Rails 4.1上,我发现下面的代码片段工作:

record = Post.new(:title => 'Yay', :body => 'This is some insert SQL')

record.class.arel_table.create_insert
  .tap { |im| im.insert(record.send(
            :arel_attributes_with_values_for_create,
            record.attribute_names)) }
  .to_sql
Run Code Online (Sandbox Code Playgroud)

感谢https://coderwall.com/p/obrxhq/how-to-generate-activerecord-insert-sql


Sha*_*cci 2

在Rails 3.2.13中测试:我想这次我做对了,这次肯定不会持久化到数据库。它也不会触发验证或回调,因此它们更改的任何内容都不会出现在结果中,除非您以其他方式调用它们。

将其保存在 lib 中作为 insert_sqlable.rb 然后您可以

#in your models or you can send it to ActiveRecord::Base
include InsertSqlable
Run Code Online (Sandbox Code Playgroud)

然后是model.insert_sql就可以看到了。

#lib/insert_sqlable
module InsertSqlable
    def insert_sql
      values = arel_attributes_values
      primary_key_value = nil

      if self.class.primary_key && Hash === values
        primary_key_value = values[values.keys.find { |k|
          k.name == self.class.primary_key
        }]

        if !primary_key_value && connection.prefetch_primary_key?(self.class.table_name)
          primary_key_value = connection.next_sequence_value(self.class.sequence_name)
          values[self.class.arel_table[self.class.primary_key]] = primary_key_value
        end
      end

      im = self.class.arel_table.create_insert
      im.into self.class.arel_table

      conn = self.class.connection

      substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
      binds       = substitutes.map do |arel_attr, value|
        [self.class.columns_hash[arel_attr.name], value]
      end

      substitutes.each_with_index do |tuple, i|
        tuple[1] = conn.substitute_at(binds[i][0], i)
      end

      if values.empty? # empty insert
        im.values = Arel.sql(self.class.connectionconnection.empty_insert_statement_value)
      else
        im.insert substitutes
      end

      conn.to_sql(im,binds)
    end
end
Run Code Online (Sandbox Code Playgroud)

事实证明,代码位于 ActiveRecord::Relation 中,而不是 ActiveRecord::Persistence 中。唯一显着的变化是最后一行生成 sql 而不是执行它。