2013年8月4日日曜日

after_saveイベントで作成した子モデルが反映されるタイミング


上手のような親子関係(鮭とイクラ)を持つモデルにおいて、親モデルを作成した時点で子モデルを自動的に作成するようにしたい。

Shakeモデルは前回の記事で既に作成しているので、子となるIkuraモデルを今回新規に作成する。(実行結果は省略)
rails g model ikura shake:references name:string
rake db:migrate
親モデルShakeのafter_saveというイベントに合わせて子クラスIkuraを生成するように実装してみる。
class Shake < ActiveRecord::Base
  has_many :ikuras

  after_save :create_ikuras

  private

  def create_ikuras
    if ikuras.blank?
      ikura1 = Ikura.new
      ikura1.shake_id = id
      ikura1.name = 'First Ikura'
      ikura1.save
    end
  end
end
さっそくコンソールで実行してみても、子モデルが生成されていない。
Loading development environment (Rails 3.2.1)
irb(main):001:0> shake = Shake.new
=> #<Shake id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):002:0> shake.name = 'First Shake'
=> "First Shake"
irb(main):003:0> shake.save
=> true
irb(main):004:0> shake.ikuras
=> []
どうもおかしいと思ってIkuraモデルを全件表示してみると、ちゃんと生成されている。
irb(main):001:0> Ikura.all
=> [#<Ikura id: 1, shake_id: 1, name: "First Ikura", created_at: "2013-08-04 01:
42:32", updated_at: "2013-08-04 01:42:32">]
Shakeクラスをリロードしてみると子モデルとして格納されている。
irb(main):002:0> shake = Shake.first
=> #<Shake id: 1, name: "First Shake", created_at: "2013-08-04 01:42:31", update
d_at: "2013-08-04 01:42:31">
irb(main):003:0> shake.ikuras
=> [#<Ikura id: 1, shake_id: 1, name: "First Ikura", created_at: "2013-08-04 01:
42:32", updated_at: "2013-08-04 01:42:32">]
単に子モデルを生成しただけではすぐにインスタンスに反映されず、下記のように明示的に親クラス側の配列に追加しておく必要があるようだ。
  def create_ikuras
    if ikuras.blank?
      ikura1 = Ikura.new
      ikura1.shake_id = id
      ikura1.name = 'First Ikura'
      ikura1.save
      ikuras << ikura1
    end
  end
ShakeモデルをNewしてsaveすると、子モデルのikurasが直ちに追加されるようなった。
irb(main):001:0> shake = Shake.new
=> #<Shake id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):002:0> shake.name = 'Second Shake'
=> "Second Shake"
irb(main):003:0> shake.save
=> true
irb(main):004:0> shake.ikuras
=> [#<Ikura id: 2, shake_id: 2, name: "First Ikura", created_at: "2013-08-04 04:
35:58", updated_at: "2013-08-04 04:35:58">]

0 件のコメント:

コメントを投稿