【问题标题】:When using first_or_create, in the after_create callback, the Model queries get extra conditions added automatically使用 first_or_create 时,在 after_create 回调中,模型查询会自动添加额外的条件
【发布时间】:2013-05-09 11:50:19
【问题描述】:

出于解释的目的,我将使用 SQLite 创建一个全新的 Rails (3.2.13) 项目。

rails new TestApp
cd TestApp/
rake db:create
rails g model Blog name:string description:string
rake db:migrate

这是Blog 模型的内容。

class Blog < ActiveRecord::Base
  attr_accessible :description, :name

  after_create :print_other_name


  private

  def print_other_name
    # Just for example, running a query here.
    blog = Blog.first
  end
end

然后打开rails console

1.9.3-p125 :001 > blog = Blog.where( name: 'First Blog' ).first_or_create!( description: 'This is the first blog' )

  Blog Load (0.2ms)  SELECT "blogs".* FROM "blogs" WHERE "blogs"."name" = 'First Blog' LIMIT 1
   (0.1ms)  begin transaction
  SQL (63.9ms)  INSERT INTO "blogs" ("created_at", "description", "name", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Thu, 09 May 2013 11:30:31 UTC +00:00], ["description", "This is the first blog"], ["name", "First Blog"], ["updated_at", Thu, 09 May 2013 11:30:31 UTC +00:00]]
  ======>>>>>>> Blog Load (0.6ms)  SELECT "blogs".* FROM "blogs" WHERE "blogs"."name" = 'First Blog' LIMIT 1
   (1.5ms)  commit transaction
 => #<Blog id: 1, name: "First Blog", description: "This is the first blog", created_at: "2013-05-09 11:30:31", updated_at: "2013-05-09 11:30:31">

在上面的代码块中,请看INSERT查询之后已经运行的查询:

Blog Load (0.6ms)  SELECT "blogs".* FROM "blogs" WHERE "blogs"."name" = 'First Blog' LIMIT 1

这是由模型的after_create 中的Blog.first 行生成的查询。

本来应该是一个没有任何条件的简单LIMIT 1 查询,现在在查询中添加了一个name 条件。并且经过大量测试,我意识到被添加的条件是Blog.where( name: 'First Blog' ).first_or_create!.... 行中提到的条件。

换句话说,我在first_or_create 之前在where 中使用的任何条件似乎都会自动添加到after_create 回调中运行的所有查询中。

我无法想象为什么这是预期的行为,但如果是,我在任何地方都找不到它的文档。

有人对这种行为有任何见解吗?这打破了我在 after_create 回调中的所有查询。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 activerecord ruby-on-rails-3.2


    【解决方案1】:

    first_or_create 将整个查询包装在 where 子句定义的范围内。您可以通过两种方式解决此问题:

    1. 不要使用first_or_create,而是使用find_or_create_by,比如

      Blog.find_or_create_by( name: 'First Blog' )
      
    2. 在所有包含如下查询的回调中使用unscoped

      def print_other_name
        # Just for example, running a query here.
        blog = Blog.unscoped.first
      end
      

    【讨论】:

      猜你喜欢
      • 2012-04-05
      • 1970-01-01
      • 2020-10-04
      • 1970-01-01
      • 2020-08-14
      • 1970-01-01
      • 1970-01-01
      • 2013-06-01
      • 2018-08-31
      相关资源
      最近更新 更多