Проблемы с обновлением атрибутов, когда методы доступа по умолчанию перезаписываются

Я использую Ruby on Rails 4 и перезаписал некоторый метод доступа по умолчанию следующим образом:

class Article < ActiveRecord::Base
  def title
    self.get_title
  end

  def content
    self.get_content
  end
end

Методы self.get_title и self.get_content возвращают некоторое вычисленное значение и выглядят следующим образом (примечание: has_one_association — это :has_one ActiveRecord::Association)

def get_title
  self.has_one_association.title.presence || read_attribute(:title)
end

def get_content
  self.has_one_association.content.presence || read_attribute(:content)
end

Когда я нахожу и читаю экземпляры @article из базы данных, все работает так, как ожидалось: значения title и content выводятся соответственно с self.has_one_association.title и self.has_one_association.content.

Однако я обнаружил, что когда атрибуты назначаются объекту @article, объект @article не обновляется должным образом. То есть, учитывая в моем контроллере у меня есть:

def update
  # params # => {:article => {:title => "New title", :content => "New content"})}

  ...

  # BEFORE UPDATING
  # @article.title   # => "Old title"   # Note: "Old title" come from the 'get_title' method since the 'title' accessor implementation
  # @article.content # => "Old content" # Note: "Old content" come from the 'get_content' method since the 'content' accessor implementation

  if @article.update_attributes(article_params)

    # AFTER UPDATING
    # @article.title   # => "Old title"
    # @article.content # => "Old content"

    ...
  end
end

def article_params
  params.require(:article).permit(:title, :content)
end

Даже если @article действителен, он не был обновлен в базе данных (!), я думаю, потому что я перезаписываю методы доступа и/или способ, которым Rails assign_attributes. Конечно, если я удалю методы получения, все будет работать как положено.

Это ошибка? Как я могу решить проблему? Или я должен использовать другой подход, чтобы сделать то, что я хотел бы сделать?


См. также https://github.com/rails/rails/issues/14307.


person user502052    schedule 07.03.2014    source источник


Ответы (1)


update_attributes в данном случае — это просто ярлык для вызова title=, content= и save. Если вы не перезаписываете сеттеры, а только геттеры, это не связано.

Вы правильно обновляете значения, но Rails не считывает значения, которые вы устанавливаете, из-за перезаписи геттеров для чтения из ассоциации. Вы можете убедиться в этом, проверив @article.attributes или просмотрев запись статьи в базе данных.

Кроме того, ваш get_content пытается read_attribute(:title) вместо :content.

person sevenseacat    schedule 07.03.2014
comment
[...] ваш get_content пытается read_attribute(:title) вместо :content. была моя опечатка, поэтому я обновил вопрос. Однако, если я перезапишу методы установки таким образом def title=(value); write_attribute(:title, value); end и def content=(value); write_attribute(:content, value); end, то он все еще не будет работать должным образом. P.S.: Возможно, я не понял, в чем смысл вашего ответа. - person user502052; 07.03.2014
comment
Я не думаю, что вы сделали. Не перезаписывайте сеттеры. Обновление атрибутов работает нормально, их обратное чтение (из-за того, что вы перезаписываете геттеры) - вот где ошибка. - person sevenseacat; 07.03.2014
comment
Я дважды проверяю @article.attributes (# => #<Article id: 1 :title => "Old title" :content => "Old content">) и базу данных, после обновления ничего не изменилось. Кажется, что задание работает не так, как ожидалось. - person user502052; 07.03.2014