1. ホーム
  2. ruby-on-rails

[解決済み] Ruby on Railsでセッターメソッドをオーバーライドする正しい方法は何ですか?

2022-04-24 19:10:40

質問

Ruby on Rails 3.2.2を使用していますが、myクラスの属性のセッターメソッドをオーバーライドする方法が以下の通りかどうか知りたいのですが、正しい方法ですか?

attr_accessible :attribute_name

def attribute_name=(value)
  ... # Some custom operation.

  self[:attribute_name] = value
end

上記のコードは期待通りに動作しているようです。しかし 上記のコードを使用することで、将来的に問題が発生するかどうか、少なくとも、Ruby on Railsでどのような問題を想定すべきか/発生する可能性があるかどうかを知りたいのです。 . もしこれがセッターメソッドをオーバーライドする正しい方法でないとしたら、何が正しい方法なのでしょうか?


備考 : もし私がコード

attr_accessible :attribute_name

def attribute_name=(value)
  ... # Some custom operation.

  self.attribute_name = value
end

以下のようなエラーが発生します。

SystemStackError (stack level too deep):
  actionpack (3.2.2) lib/action_dispatch/middleware/reloader.rb:70

解決方法は?

=========================================================================== 更新日:2017年7月19日

では、その Railsのドキュメント を使用することを提案しています。 super このように

class Model < ActiveRecord::Base

  def attribute_name=(value)
    # custom actions
    ###
    super(value)
  end

end

===========================================================================

オリジナル回答

モデルを通してアクセスしながら、テーブルのカラムのセッターメソッドをオーバーライドしたい場合、この方法があります。

class Model < ActiveRecord::Base
  attr_accessible :attribute_name

  def attribute_name=(value)
    # custom actions
    ###
    write_attribute(:attribute_name, value)
    # this is same as self[:attribute_name] = value
  end

end

参照 デフォルトのアクセサをオーバーライドする をRailsのドキュメントに追加しました。

つまり、最初の方法がRuby on RailsのModelでカラムのセッターをオーバーライドする正しい方法です。これらのアクセサは、テーブルのカラムをモデルの属性としてアクセスするために、Railsがすでに提供しているものです。これがActiveRecordのORMマッピングと呼ばれるものです。

また attr_accessible はアクセッサとは関係ありません。 これは全く別の機能です( この質問 )

しかし、純粋なRubyでは、あるクラスのアクセサを定義して、そのセッターをオーバーライドしたい場合、このようにインスタンス変数を利用する必要があるのです。

class Person
  attr_accessor :name
end

class NewPerson < Person
  def name=(value)
    # do something
    @name = value
  end
end

の意味が分かれば、より理解しやすくなります。 attr_accessor を実行します。コード attr_accessor :name は、この2つのメソッド(ゲッターとセッター)と同等です。

def name # getter
  @name
end

def name=(value) #  setter
  @name = value
end

また、2番目の方法は、同じメソッドを呼び出しているため、無限ループを引き起こし、失敗します。 attribute_name= の中にあるメソッドです。