Как правильно переопределить метод установки в Ruby on Rails?

148

Я использую 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
  • 4
    Мне нравится применяемая терминология «правильно» / «правильно» / «точно». Когда вы даете ему 3 способа, это действительно гарантирует, что нет неправильного толкования. Хорошая работа!
  • 5
    @Jay - «Тонкость итальянизма»; -)
Показать ещё 1 комментарий
Теги:
override
setter
ruby-on-rails-3

5 ответов

234
Лучший ответ

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

Теперь Документация Rails также предлагает использовать super следующим образом:

class Model < ActiveRecord::Base

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

end

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

Оригинальный ответ

Если вы хотите переопределить методы setter для столбцов таблицы при доступе через модели, это способ сделать это.

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 см. Переопределение прецедентов по умолчанию в документации Rails.

Итак, ваш первый метод - это правильный способ переопределить установщики столбцов в моделях Ruby on Rails. Эти аксессоры уже предоставлены Rails для доступа к столбцам таблицы в качестве атрибутов модели. Это то, что мы называем отображением ORR ActiveRecord.

Также имейте в виду, что attr_accessible в верхней части модели не имеет ничего общего с аксессуарами. Он имеет совершенно другую функцию (см. этот вопрос)

Но в чистом Ruby, если вы определили accessors для класса и хотите переопределить setter, вам нужно использовать переменную экземпляра, как это:

class Person
  attr_accessor :name
end

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

Это будет легче понять, если вы знаете, что делает attr_accessor. Код attr_accessor :name эквивалентен этим двум методам (getter и setter)

def name # getter
  @name
end

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

Также ваш второй метод выходит из строя, потому что он вызовет бесконечный цикл, когда вы вызываете тот же метод attribute_name= внутри этого метода.

  • 9
    Для Rails 4 просто пропустите attr_accessible так как его там больше нет, и он должен работать
  • 10
    Почему бы не позвонить super ?
Показать ещё 5 комментариев
37

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

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

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

def attribute_name
  super.some_custom_decode
end
  • 1
    Лучший ответ, чем принятый IMO, поскольку он ограничивает вызов метода тем же именем. Это сохраняет унаследованное переопределенное поведение для attribute_name =
  • 0
    Переопределение метода get стало опасным в Rails 4.2 из-за этого изменения: github.com/rails/rails/commit/… Ранее помощники формы вызывали значение поля unntypecast и не вызывали ваш пользовательский метод get. Теперь они вызывают ваш метод, и поэтому в ваших формах получаются непонятные результаты в зависимости от того, как вы переопределяете значение.
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: attribute_name

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню