Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to chain try() and scoped to_s() in Rails?

In a Rails view, one can use try to output only if there is a value in the database, e.g

@model.try(:date)

And one can chain trys if, for example, the output is needed as a string

@model.try(:date).try(:to_s)

But what if I need to call a scoped format? I've tried

@model.try(:date).try(:to_s(:long))
@model.try(:date).try(:to_s).try(:long)

What is the correct syntax for this? And what is a good reference for more explanation?

Thanks

like image 983
Andy Harvey Avatar asked Apr 28 '12 03:04

Andy Harvey


3 Answers

From the fine manual:

try(*a, &b)
[...]
try also accepts arguments and/or a block, for the method it is trying

Person.try(:find, 1)

So I think you want:

@model.try(:date).try(:to_s, :long)

This one won't work:

@model.try(:date).try(:to_s(:long))

because you're trying to access the :to_s symbol as a method (:to_s(:long)). This one won't work:

@model.try(:date).try(:to_s).try(:long)

because you're trying to call the long method on what to_s returns and you probably don't have a String#long method defined.

like image 167
mu is too short Avatar answered Nov 16 '22 06:11

mu is too short


mu is too short's answer shows the correct usage for the try method with parameters:

@model.try(:date).try(:to_s, :long)

However, if you are using Ruby 2.3 or later, you should stop using try and give the safe navigation operator a try (no pun intended):

@model&.date&.to_s(:long)

The following answer is here for historical purposes – adding a rescue nil to the end of statements is considered bad practice, since it suppresses all exceptions:

For long chains that can fail, I'd rather use:

@model.date.to_s(:long) rescue nil

Instead of filling up my view with try(...) calls.

Also, try to use I18n.localize for date formatting, like this:

l @model.date, format: :long rescue nil

See: http://rails-bestpractices.com/posts/42-use-i18n-localize-for-date-time-formating

like image 34
Fábio Batista Avatar answered Nov 16 '22 05:11

Fábio Batista


In case you often use try chains without blocks, an option is to extend the Object class:

class Object
  def try_chain(*args) 
    args.inject(self) do |result, method| 
      result.try(method)
    end
  end
end

And then simply use @model.try_chain(:date, :to_s)

like image 2
Greg Funtusov Avatar answered Nov 16 '22 05:11

Greg Funtusov