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?
update_attributes
in this case is just a shortcut for callingtitle=
,content=
, andsave
. 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 toread_attribute(:title)
instead of:content
.