Как правильно переопределить метод сеттера в 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
694   5  

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_name

  def attribute_name=(value)
    # manipulate value
    # then send result to the default setter
    super(result)
  end

Comments

    Ничего не найдено.