Вопрос по ruby-on-rails, ruby, ruby-on-rails-3 – Как правильно переопределить метод установки в Ruby on Rails?

165

Я использую Ruby on Rails 3.2.2, и я хотел бы знать, является ли следующее «правильным» / «правильным» / «верным»; способ переопределить метод set для атрибута my class.

<code>attr_accessible :attribute_name

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

  self[:attribute_name] = value
end
</code>

Код выше, кажется, работает как ожидалось. Тем не мение,I would like to know if, by using the above code, in future I will have problems or, at least, what problems "should I expect"/"could happen" with Ruby on Rails, Если это неправильный способ переопределить метод установки, то каков правильный путь?

Note: Если я использую код

<code>attr_accessible :attribute_name

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

  self.attribute_name = value
end
</code>

Я получаю следующую ошибку:

<code>SystemStackError (stack level too deep):
  actionpack (3.2.2) lib/action_dispatch/middleware/reloader.rb:70
</code>
Я люблю применяемую терминологию «правильно» / «правильно» / «обязательно». Когда вы даете ему 3 способа, это действительно гарантирует, что нет неправильного толкования. Отличная работа Jay
Просто чтобы прояснить, "слишком большой уровень стека" относится к тому факту, что это рекурсивный вызов ... сам вызов. Nippysaurus
@ Jay - «Тонкость итальянизма»; -) Backo

Ваш Ответ

5   ответов
266

================================================= ========================== Обновление: 19 июля 2017 года

Сейчас Техническая документация также предлагает использовать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= внутри этого метода.

Для Rails 4 просто пропуститеattr_accessible так как его там больше нет, и оно должно работать zigomir
Почему бы не позвонитьsuper? Nathan Lilienthal
У меня сложилось впечатление, что поскольку авторы и авторы создаются динамически,super может не работать. Но, похоже, дело не в этом. Я только что проверил, и это работает для меня. Кроме того, этовопро спроси то же самое rubyprince
Есть огромная ошибка сwrite_attribute. Конверсии будут пропущены. Быть в курсе, чтоwrite_attribute будет пропускать переходы часовых поясов с датами, что почти всегда нежелательно. Tim Scott
super также будет работать, но есть некоторые причины, по которым вы не захотите его нам. Например, в mongoid gem есть ошибка, из-за которой вы не можете передать массив, если вы используете метод getter. Это ошибка из-за способа управления массивом в памяти. Также @name будет также возвращать установленное значение, а не вызывать метод, который вы перезаписываете. Однако в приведенном выше решении оба будут работать очень хорошо. Brandt
42

Использоватьsuper ключевое слово:

def attribute_name=(value)
  super(value.some_custom_encode)
end

Наоборот, чтобы переопределить читателя:

def attribute_name
  super.some_custom_decode
end
Лучший ответ, чем принятый IMO, поскольку он ограничивает вызов метода одним и тем же именем. Это сохраняет унаследованное переопределенное поведение для attribute_name = Andrew Schwartz
Переопределение метода get стало опасным в Rails 4.2 из-за этого изменения: Github.com / рельсы / рельсы / фиксация / ... Ранее помощники по формам вызывали бы нетипичное значение поля и не вызывали ваш пользовательский получатель. Теперь они вызывают ваш метод, и поэтому в ваших формах получаются непонятные результаты в зависимости от того, как вы переопределяете значение. Brendon Muir
15

В рельсах 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

Примечание: для новичков в рельсах 4 не нужно указывать Attr_accessible в модели. Вместо этого вы должны занести в белый список свои атрибуты на уровне контроллера, используяразрешат метод.

3

что (по крайней мере для коллекций отношений ActiveRecord) работает следующий шаблон:

has_many :specialties

def specialty_ids=(values)
  super values.uniq.first(3)
end

(Это захватывает первые 3 не повторяющихся записи в переданном массиве.)

0

С помощьюattr_writer перезаписать сеттер attr_writer: имя_атрибута

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

Похожие вопросы