3

説明のために、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

Blog.firstこれは、モデルの の行によって生成されたクエリですafter_create

LIMIT 1条件のない単純なクエリであったはずのものが、クエリにname条件が追加されました。そして、いろいろテストした結果、追加される条件は、そのBlog.where( name: 'First Blog' ).first_or_create!....行に記載されている条件であることに気付きました。

つまり、に使用した条件は、コールバックで実行されるすべてのクエリに自動的に追加されるようです。wherefirst_or_createafter_create

なぜこれが予想される動作なのか想像できませんが、そうであれば、どこにも文書化されていません。

誰かがこの行動について何か洞察を持っていますか? これは、コールバックですべてのクエリを壊していafter_createます。

4

1 に答える 1

5

first_or_create、クエリ全体を where 句で定義されたスコープにラップします。これは、次の 2 つの方法で解決できます。

  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
    
于 2013-05-09T21:11:40.833 に答える