10

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

例如,如果我有这样的模型:

m = Model.new
m.url = "url"
m.header = "header"

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

如果可能,我想得到:“INSERT INTO models(url, header) VALUES('url', 'header')”。

注意:我不想实际保存模型并取回查询(来自日志文件等)。如果我选择保存查询,我想获取它。

4

4 回答 4

10

在 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

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

于 2015-01-26T20:42:44.817 回答
2

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

将它保存在 lib 中作为 insert_sqlable.rb 然后你可以

#in your models or you can send it to ActiveRecord::Base
include InsertSqlable

然后就是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

原来代码在 ActiveRecord::Relation 中而不是 ActiveRecord::Persistence 中。唯一显着的变化是生成 sql 而不是执行它的最后一行。

于 2013-04-23T02:46:29.090 回答
1

如果您不想保存模型,请在完成对象后调用 m.destroy。

您可以像这样调试它来记录sql查询

Rails.logger.debug "插入模型(url, header) VALUES(#{m.url}, #{m.header}).inspect

于 2013-04-23T02:14:17.450 回答
0

在互联网和论坛上搜索了很多之后,我想我找到了一个更好的解决方案:只需要两行代码

我找到了一个很好的 gem 可以完全满足你的要求,但是这个 gem 只适用于 Rails 3.2 和更早版本。我和作者谈过,他不想再支持这个宝石了。所以我自己发现了如何支持 Rails 4.0,现在我正在维护这个 gem。

在此处下载“models-to-sql-rails”gem,支持 Rails 4.0 及更早版本。


使用此 gem,您可以轻松地执行以下操作。(values里面的例子只是个玩笑,在你的对象中使用它时你会得到正确的值)。

对于对象:

object.to_sql_insert
# INSERT INTO modelName (field1, field2) VALUES ('Wow, amaze gem', 'much doge')

对于对象数组:

array_of_objects.to_sql_insert
# INSERT INTO modelName (field1, field2) VALUES ('Awesome doge', "im fucking cop")
# INSERT INTO modelName (field1, field2) VALUES ('much profit', 'much doge')
# (...)

只要看看这个项目的 Github,你就会发现如何安装和使用这个美妙的 gem。

于 2014-02-01T04:46:55.503 回答