Trouble on updating attributes when default access

2019-09-14 22:16发布

I am using Ruby on Rails 4 and I have overwritten some default accessor method this way:

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

  def content
    self.get_content
  end
end

self.get_title and self.get_content methods return some computed value and look like the following (note: has_one_association is a :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

When I find and read @article instances from the database all works as expected: title and content values are respectively outputted with self.has_one_association.title and self.has_one_association.content.

However, I found that when attributes are assigned to an @article then the @article object is not updated as expected. That is, given in my controller I have:

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

Even if the @article is valid it has not been updated in the database (!), I think because the way I overwrite accessors and/or the way Rails would assign_attributes. Of course, if I remove the getter methods then all works as expected.

Is it a bug? How can I solve the problem? Or, should I adopt another approach in order to make what I would like to accomplish?


See also https://github.com/rails/rails/issues/14307

1条回答
家丑人穷心不美
2楼-- · 2019-09-14 22:29

update_attributes in this case is just a shortcut for calling title=, content=, and save. If you're not overwriting the setters, just the getters, it is not related.

You're updating the values correctly, but Rails isn't reading the values you're setting, due to overwriting the getters to read from the association instead. You could verify this by checking @article.attributes, or looking at the article record in the database.

Also, your get_content is trying to read_attribute(:title) instead of :content.

查看更多
登录 后发表回答