Как правильно переопределить метод сеттера в Ruby on Rails?
Я использую Ruby on Rails 3.2.2, и я хотел бы знать, является ли следующее "правильным"/"правильным"/"уверенным" способом переопределить метод setter для атрибута моего класса.
attr_accessible :attribute_name
def attribute_name=(value)
... # Some custom operation.
self[:attribute_name] = value
end
приведенный выше код, кажется, работает, как ожидалось. Однако,Я хотел бы знать, если, используя приведенный выше код, в будущем у меня будут проблемы или, по крайней мере, какие проблемы "я должен ожидать"/"может случиться" с Ruby on Rails. Если это не правильный способ переопределить метод setter, что такое правильно?
Примечание: если я использую код
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
5 ответов:
=========================================================================== Обновление: 19 Июля 2017
теперь 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 mapping.
также имейте в виду, что
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эквивалентно этим двум методам (геттер и сеттер)def name # getter @name end def name=(value) # setter @name = value endтакже ваш второй метод терпит неудачу, потому что это вызовет бесконечный цикл, как вы вызываете тот же метод
attribute_name=внутри этого метода.
использовать
superключевые слова:def attribute_name=(value) super(value.some_custom_encode) endнаоборот, чтобы переопределить читателя:
def attribute_name super.some_custom_decode end
в рельсах 4
допустим у вас есть возраст атрибут в таблице
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 в модели. Вместо этого вы должны белый список атрибутов на уровне контроллера с помощью разрешение метод.
Я обнаружил, что (по крайней мере, для коллекций отношений ActiveRecord) работает следующий шаблон:
has_many :specialties def specialty_ids=(values) super values.uniq.first(3) end(это захватывает первые 3 не повторяющиеся записи в массиве передается.)
используя
attr_writerпереписать сеттер attr_writer: attribute_namedef attribute_name=(value) # manipulate value # then send result to the default setter super(result) end
Comments