LoginSignup
49
44

More than 5 years have passed since last update.

accepts_nested_attributes_forの更新処理をカスタマイズする

Last updated at Posted at 2013-02-27

accepts_nested_attributes_for を使って1つのフォームで複数のテーブルを同時に更新している場合、子となるモデル側の更新処理をカスタマイズしたいケースがあります。
例えば画像を投稿するフォームで永続化しないパラメータとして photo のような属性を定義している場合、「画像のみを変更する場合」は AR::Base#changed?が true にならず、before_saveなどのコールバックを含め更新処理が一切走らず困ったことになります。

Bad Case

class FavoriteIdol < ActiveRecord::Base
  attr_accessor :photo

  before_save :save_photo

  private

  def save_photo
    if photo
      self.photo_saved_at = Time.now
      upload_photo(photo)
    end
  end
end

Solution

accepts_nested_attributes_for :relation を呼びだした際に定義される relation_attributes= というメソッドをオーバーライドします。
引数にはポストされたparamsの配列が格納されています。この配列を使い、関連オブジェクトの値を書き換える事で任意の更新処理を実装することができます。

class User < ActiveRecord::Base  
  accepts_nested_attributes_for :favorite_idols

  has_many :favorite_idols

  def favorite_idols_attributes=(listed_attributes)
    listed_attributes.each do |index, attributes|
      idol = favorite_idols.detect{|i| i.id == attributes["id"].to_i } || favorite_idols.build
      idol.assign_attributes(attributes)
      idol.photo_saved_at = Time.now if idol.photo.present?
    end
  end
end
49
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
44