私はRuby on Rails 3.2.2を使用しており、以下がセッターメソッドをオーバーライドする「適切な」/「正しい」/「確実な」方法であるかどうかを知りたいクラス属性。
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のモデルの列セッターをオーバーライドする正しい方法です。これらのアクセサーは、モデルの属性としてテーブルの列にアクセスするために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つのメソッド(getterおよびsetter)と同等です
def name # getter
@name
end
def name=(value) # setter
@name = value
end
また、2番目のメソッドは、同じメソッドattribute_name=
を呼び出しているときに無限ループを引き起こすため、失敗します。
super
キーワードを使用します。
def attribute_name=(value)
super(value.some_custom_encode)
end
逆に、リーダーをオーバーライドするには:
def attribute_name
super.some_custom_decode
end
In Rails 4
テーブルにage属性があるとしましょう
def age=(dob)
now = Time.now.utc.to_date
age = now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
super(age) #must add this otherwise you need to add this thing and place the value which you want to save.
end
注:Rails 4の新しいコーナーでは、モデルでattr_accessibleを指定する必要はありません。代わりに、permitメソッドを使用して、コントローラーレベルで属性をホワイトリストに登録する必要があります。
(少なくともActiveRecord関係コレクションの場合)次のパターンが機能することがわかりました。
has_many :specialties
def specialty_ids=(values)
super values.uniq.first(3)
end
(これにより、渡された配列内の重複していない最初の3つのエントリが取得されます。)
attr_writer
を使用してセッターattr_writer:attribute_nameを上書きする
def attribute_name=(value)
# manipulate value
# then send result to the default setter
super(result)
end