3

爲了便於說明添加額外的條件,我要創建一個全新的Rails使用SQLite(3.2.13)項目。當使用first_or_create,在after_create回調,型號查詢得到自動

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 

這是一個已經被Blog.first線模型的after_create生成的查詢。

本來應該是一個簡單的LIMIT 1查詢沒有任何條件,現在有一個name條件添加到查詢。經過大量測試後,我意識到正在添加的條件是Blog.where(name: 'First Blog').first_or_create!....行中提到的條件。

換句話說,什麼條件我在where使用first_or_create似乎都會自動加入到after_create回調運行的所有查詢之前。

我無法想象爲什麼會被預期的行爲,但如果是,我找不到它的任何地方記錄。

沒有任何人有任何洞察到這種行爲?這是在after_create回調中打破了我所有的查詢。

回答

5

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