I am trying to display a model attribute only if it is present. If it is not, then a placeholder should be displayed. This is what I've got:
class Person < ActiveRecord::Base
def name
if self.name.blank?
"[You have no name yet]"
else
read_attribute(:name)
end
end
end
However, I am getting a stack level too deep
error.
How can this be done?
Thanks for any help.
I agree with Ishank but you can call super
to use Rails' getter and then use ActiveSupport's presence
method which will return the value if it is present?
or otherwise return nil
(which will trigger the statement after the ||
).
def name
super.presence || "[You have no name yet]"
end
To be clear, stack level too deep is happening because you are checking self.name.blank?
- when you use self.name
here, that is calling the name
method on self (which is the method you are currently in) - so that results in an infinite loop.
This should not be a part of Model. You should write this method in your views. You can have something like @person.name || "You have no name yet"
@person.name || "You have no name yet"
You are getting exception stack level too deep
because read_attribute[:name]
again calls the name
method.
Also a thing to keep in mind for using self
. According to Ruby style guide :
Avoid
self
where not required. (It is only required when calling a self write accessor.)
# bad
def ready?
if self.last_reviewed_at > self.last_updated_at
self.worker.update(self.content, self.options)
self.status = :in_progress
end
self.status == :verified
end
# good
def ready?
if last_reviewed_at > last_updated_at
worker.update(content, options)
self.status = :in_progress
end
status == :verified
end
Can you try this for stack too deep?
def name
if self.first.name.blank?
"[You have no name yet]"
else
read_attribute[:name]
end
end
Personally, i always do something like this, using self[:name] as a way of accessing the database rather than the .name method:
def name
if self[:name].blank?
"[You have no name yet]"
else
self[:name]
end
end
I am still using rails 2.2, so this may function differently for you.
Having said that, a cleaner and more transparent way to do it is to set "[You have no name yet]" as the default value for the name column in the database. Then you don't need to override the accessor method, which always feels a bit dirty to me.
It is not a good practise to include presentation logic in data models.
You should instead use decorators, view objects, or similar, or just do it in the view, but not in the model.
Examples using the Draper gem:
class PersonDecorator < Draper::Decorator
delegate_all
def name
object.name.presence || I18n.t('warnings.no_name_yet')
end
end
In the view:
<%= @person.name.presence || I18n.t('warnings.no_name_yet') %>
See the "Introduce View Objects" section in http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.