Переопределить методы атрибута ActiveRecord

Пример того, о чем я говорю:

class Person < ActiveRecord::Base
  def name=(name)
    super(name.capitalize)
  end
  def name
    super().downcase  # not sure why you'd do this; this is just an example
  end
end

Это похоже на работу, но я просто прочитал раздел об переопределении методов атрибутов в ActiveRecord:: Base docs, и он предлагает использовать методы read_attribute и write_attribute. Я думал, что что-то не так с тем, что я делаю в приведенном выше примере; в противном случае, почему они благословляют эти методы как "правильный путь" для переопределения методов атрибутов? Они также вызывают гораздо более уродливую идиому, поэтому должна быть веская причина...

Мой реальный вопрос: что-то не так с этим примером?

Ответ 1

Повторяя комментарии Гарета... ваш код не будет работать так, как написано. Его следует переписать следующим образом:

def name=(name)
  write_attribute(:name, name.capitalize)
end

def name
  read_attribute(:name).downcase  # No test for nil?
end

Ответ 2

В качестве расширения для ответа Аарона Лонгвелла вы также можете использовать "хэш-нотацию" для доступа к атрибутам с переопределенными аксессуарами и мутаторами:

def name=(name)
  self[:name] = name.capitalize
end

def name
  self[:name].downcase
end

Ответ 3

В этой теме есть большая информация по http://errtheblog.com/posts/18-accessor-missing.

Длинным и коротким является то, что ActiveRecord корректно обрабатывает супервызов для аксессуаров атрибутов ActiveRecord.

Ответ 4

У меня есть плагин rails, который заставляет атрибут overriding работать с супер, как и следовало ожидать. Вы можете найти его на github.

Для установки:

./script/plugin install git://github.com/chriseppstein/has_overrides.git

Для использования:

class Post < ActiveRecord::Base

  has_overrides

  module Overrides
    # put your getter and setter overrides in this module.
    def title=(t)
      super(t.titleize)
    end
  end
end

Как только вы это сделали, просто выполните:

$ ./script/console 
Loading development environment (Rails 2.3.2)
>> post = Post.new(:title => "a simple title")
=> #<Post id: nil, title: "A Simple Title", body: nil, created_at: nil, updated_at: nil>
>> post.title = "another simple title"
=> "another simple title"
>> post.title
=> "Another Simple Title"
>> post.update_attributes(:title => "updated title")
=> true
>> post.title
=> "Updated Title"
>> post.update_attribute(:title, "singly updated title")
=> true
>> post.title
=> "Singly Updated Title"