How to DRY up a ruby conditional structure needed for Rails - ruby-on-rails

I'm finding I often have to use a structure to avoid a Rails error of undefined method 'name' for nil:NilClass.
The structure looks like this:
if country.state
country.state.name
end
It seems like a classic case of repeating oneself with country.state appearing twice in one simple block. Is there any way to DRY this up?

Rails adds a try method to object that mimics object#send but does not raise an exception if the object returns nil.
I think the syntax is
country.try(:state).name

Well not really. One option is to install the andand gem, but introducing a dependency for this may be a little much.

Other than using the slightly more concise syntax of:
country.state.name unless country.state.nil?
I don't think there's a DRY way to do this with the information given. I would argue that if you can't be sure whether country.state is nil or not, you may want to look at the code responsible for setting that value and determine whether that's a normal case or whether a validator upstream should be catching that.

Related

Is there any way to define a model's attribute as always html_safe?

I have a model called Feature with a variable called body_string, which contains HTML markup I'd like to render, rather than escape.
Every time I reference body_string in my views, I need to use <%=raw or .html_safe. This seems redundant and not-so-DRY.
Is there any way that I can establish once-and-for-all the body_string variable as html_safe?
I'm assuming this would happen in the app/models/feature.rb file, but I can't figure out what the right syntax would be, exactly. I've thought of this:
def body_string
return self.body_string.html_safe
end
But Rails doesn't like it; it raises a stack level too deep exception.
Naturally I could define a variable/method with a different name:
def safe_body_string
return self.body_string.html_safe
end
And then just change all references in the views from body_string to safe_body_string. But somehow this seems almost as un-DRY as simply using raw or .html_safe in the first place.
Any insights to how best to handle this? I feel like there must be something really elegant that I'm just not seeing.
Just use read_attribute to avoid the recursive call to body_string:
def body_string
read_attribute(:body_string).html_safe
end
read_attribute is complemented by write_attribute for setting attributes from within your model.
A note on style: Don't use explicit returns unless you actually need them. The result of the last statement in a method is implicitly the value returned from the method.
While #meager's answer will definitely work, I don't think this logic belongs in a model. Simply because it adds view-level concerns (HTML safeness) to the model layer, which should just include business logic. Instead, I would recommend using a Presenter for this (see http://nithinbekal.com/posts/rails-presenters/ or find a gem for this -- I personally love Display Case). Your presenter can easily override the body_string method and provide the .html_safe designation when displaying in the view. This way you separate your concerns and can continue to get body_string from other models without mixing in the view concern.
Maybe this gem is useful for you. I also wanted to stop repeating html_safe all the time when the content is completely trustable.
http://rubygems.org/gems/html_safe_attribute
Or you can also use this approach,
def body_string
super && super.html_safe
end

Am I abusing "rescue" for nil checks?

I use rescue for everything, not just for "rescuing" exceptions. I mean, I just love the way it spares me verification and double checking data.
By example, lets say I have a model Item what may or may not have a User. Then, when I want to get the owner's name of the item I write:
item.user.name rescue ""
instead of something like
item.user.nil? ? "" : item.user.name
It makes the same think, since nil.name trigger an exception that I rescue with "", but I'm not pretty sure this is good practice. It makes what I want to, and it makes it with less code, but... I don't know, all that rescue words here and there makes me feel insecure.
Is it a bad practice or is it valid abusing of the rescue keyword?
I think you are abusing rescue a bit, though in Rails, there is a specific method for these issues: try. Documentation
In your case, item.user.try(:name) might be a nicer approach.
I would say this is not really a good habit to get into. I've never really used this feature in Ruby since it feels like I'm just hiding error cases. It's also worth noting that you're rescuing any and all exceptions without specifying any type of expected error. It's just always looked like something which is going to make debugging down the road harder than it needs to be, although, like I've said, I've never bothered to use it myself.
Like in most other languages, making the check yourself will run faster than using rescue.
As an alternative to your rescue abuse, check out the andand gem. It's similiar to the try another posted suggested, but nicer. andand lets you say:
item.user.andand.name
The expression will be nil if item.user is nil.

NilClass definitions

I am tired of trapping for nil when looking for a dependent record when most of the time a return of 0 will do nicely. What sort of trouble am I creating for myself by adding "id" to the NilClass thus
class NilClass
def id
0
end
end
What might the unintended consequences be? I know about exists?(), but somehow thought this might be cleaner.
Your thoughts?
If you really have a problem with this, you should use referential integrity inside your database.
If you must call methods on nil which may or may not exist or throw some kind of error, you should use either a check a la
> nil.id if nil
=> nil
or Object#try (which is part of ActiveSupport nowadays I believe?), be warned - I reckon it's kind of a code smell.
> nil.try(:id)
=> nil
That being said, it is less of a smell than modifying NilClass to do something unexpected, think of what a new developer who had to work on your project would expect.
Won't this mean you will need to check for "id == 0" to confirm existence?
Not to mention unintended consequences of overiding base Ruby functionality - it becomes really hard to predict behaviour of other libraries and core Rails APIs when you mess with language internals. Not saying it won't just work, but it's hard to be sure.
I would leave the default - it works quite nicely as Ruby allows "if object.association" expressions.

How do I find where a ruby method is declared?

I have a ruby method (deactivate!) that is on an activeRecord class. However, I can't seem to find where that method is declared.
There have been numerous developers on this project, so it could be anywhere. There is a deactivate! on an unrelated class, but it doesn't seem to get called.
Any ideas how to find all the superclasses for an instace, or where to find the code for deactivate!?
First question would be: is it an actual method? Does obj.method(:deactivate!) raise an error?
If it doesn't, then you can use Method#source_location(in Ruby 1.9 only, and backports can't support it):
obj.method(:deactivate!).source_location
If it does raise a NoMethodError, it is handled via method_missing. This makes it hard to track. If it accepts arguments, I'd try sending the wrong type and using the backtrace of the raised exception.
Are you using state_machine? If you have an event transition called :deactivate, the model will have the method #deactivate! created automatically.
When I need to find where a method is declared on some class, say 'Model', I do
Model.ancestors.find {|c| c.instance_methods(false).include? :deactivate! }
This searches the ancestor tree in the same order that ruby does for the first that has the method in instance_methods(false), which only includes non-inherited methods.
Note: before ruby 1.9, the methods were listed as strings not symbols, so it would be
Model.ancestors.find {|c| c.instance_methods(false).include?('deactivate!') }
As a first stab, try the Jump to Declaration feature of your IDE. Depending on how good your IDE's static type inference is, it should take you right there.
If that doesn't work, set a breakpoint on that call, fire up the debugger and step into the method.

defined? method in Ruby and Rails

I have a quite old templating system written on top of ERB. It relies on ERB templates stored in database. Those are read and rendered. When I want to pass data from one template to another I use the :locals parameter to Rails render method. For setting default variables of those variables in some templates I use the defined? method which simply tells me if local variable has been defined and if not I initialize it with default value like this:
unless defined?(perex)
perex = true
end
I am upgrading the app to latest Rails and I see some weird behavior. Basically this sometimes works (sometimes perex is undefined) and sometimes it does not (perex is defined and set to nil). This happens without anything else changing.
I have two questions:
Is there any better way other than using defined? which is proving unreliable (was reliable for several years on top Rails 1.6)? Such a way should not result in me rewriting all the templates.
I have been going through Ruby docs and was not able to find anything about defined? method. Was it deprecated or am I just plain blind?
Edit: The actual issue was caused by what seems to be a Ruby/eRB bug. Sometimes the unless statement would work, but sometimes not. The weird thing is that even if the second line got executed perex stil stayed nil to the rest of the world. Removing defined? resolved that.
First: actually, defined? is an operator.
Second: if I understand your question correctly, the way to do it is with this Ruby idiom:
perex ||= true
That'll assign true to perex if it's undefined or nil. It's not exactly what your example does, since yours doesn't evaluate the assignment when the value is nil, but if you are relying on that then, in my opinion, without seeing it, you're not writing clear code.
Edit: As Honza noted, the statement above will replace the value of perex when it's false. Then I propose the following to rewrite the minimum number of lines:
perex ||= perex.nil? # Assign true only when perex is undefined or nil
The safest way of testing if a local is defined in a Rails template is:
local_assigns[:perex]
This is documented in the Rails API together with the explanation that defined? cannot be used because of a implementation restriction.
Per mislav's answer, I went looking for that documentation in the Rails API, and found it in Class ActionView::Base (under the heading "Passing local variables to sub templates"). It was hardly worth the search, though, since it barely said anything more than mislav did. Except that it recommends this pattern:
if local_assigns.has_key? :perex
Taking into considerationg mislav's original answer and KenB's elaboration, I think the following is the absolute best approach (though I'm open to opinion). It utilizes Ruby's Hash#fetch method to fallback on an alternate value if the key does not exist in the original hash.
perex = local_assigns.fetch(:perex, true)
This is even better than the ||= method that most users will suggest since sometimes you will want to allow false values. For example, the following code will never allow a false value to be passed in:
perex = local_assigns[:perex] || true

Resources