Проблема с переопределением сеттера на ActiveRecord

Это не совсем вопрос, этоскорее отчет о том, как я решил проблему сwrite_attribute когда атрибут является объектом, на Rails Active Record, Я надеюсь, что это может быть полезно для других, сталкивающихся с той же проблемой.

Позвольте мне объяснить на примере. Предположим, у вас есть два класса,Book а также :Author

class Book < ActiveRecord::Base
  belongs_to :author
end

class Author < ActiveRecord::Base
  has_many :books
end

Очень просто. Но по какой-то причине вам нужно переопределитьauthor= метод включенBook, Насколько я'я новичок в Rails, ямы последовали за Сэмом РубиПредложение по Agile Web Development с Rails: используйтеattribute_writer приватный метод. Итак, моя первая попытка была:

class Book < ActiveRecord::Base
  belongs_to :author

  def author=(author)
    author = Author.find_or_initialize_by_name(author) if author.is_a? String
    self.write_attribute(:author, author)
  end
end

К сожалению, это не работает. Тот'Что я получаю из консоли:

>> book = Book.new(:name => "Alice's Adventures in Wonderland", :pub_year => 1865)
=> #
>> book.author = "Lewis Carroll"
=> "Lewis Carroll"
>> book
=> #
>> book.author
=> nil

Похоже, что Rails не распознает его как объект и ничего не делает: после присвоения автор по-прежнему равен нулю! Конечно, я мог бы попробоватьwrite_attribute(:author_id, author.id), но это не помогает, когда автор еще не сохранен (у него все еще нет идентификатора!), и мне нужно сохранить объекты вместе (автор должен быть сохранен, только если книга действительна).

После многих поисков решения (и тщетных попыток) я нашел это сообщение:http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/4fe057494c6e23e8Итак, наконец, у меня мог быть некоторый рабочий код:

class Book < ActiveRecord::Base
  belongs_to :author

  def author_with_lookup=(author)
    author = Author.find_or_initialize_by_name(author) if author.is_a? String
    self.author_without_lookup = author
  end
  alias_method_chain :author=, :lookup
end

На этот раз мне понравилась консоль:

>> book = Book.new(:name => "Alice's Adventures in Wonderland", :pub_year => 1865)
=> #
>> book.author = "Lewis Carroll"=> "Lewis Carroll"
>> book
=> #
>> book.author
=> #

Хитрость здесь в том,alias_method_chain, что создает перехватчик (в этом случаеauthor_with_lookup) и альтернативное имя для старого сеттера (author_without_lookup). Признаюсь, потребовалось некоторое время, чтобы понять эту договоренность, и яБуду рад, если кто-то захочет объяснить это подробно, но меня удивило отсутствие информации об этой проблеме. Мне приходится много гуглить, чтобы найти только один пост, который по названию изначально не имел отношения к проблеме. Я'Я новичок в Rails, так что вы думаете, ребята: это плохая практика?

Ответы на вопрос(3)

Ваш ответ на вопрос