Say I have a Rails Model called Thing. Thing has a url attribute that can optionally be set to a URL somewhere on the Internet. In view code, I need logic that does the following:
<% if thing.url.blank? %>
<%= link_to('Text', thing_path(thing)) %>
<% else %>
<%= link_to('Text', thing.url) %>
<% end %>
This conditional logic in the view is ugly. Of course, I could build a helper function, which would change the view to this:
<%= thing_link('Text', thing) %>
That solves the verbosity problem, but I would really prefer having the functionality in the model itself. In which case, the view code would be:
<%= link_to('Text', thing.link) %>
This, obviously, would require a link method on the model. Here's what it would need to contain:
def link
(self.url.blank?) ? thing_path(self) : self.url
end
To the point of the question, thing_path() is an undefined method inside Model code. I'm assuming it's possible to "pull in" some helper methods into the model, but how? And is there a real reason that routing only operates at the controller and view layers of the app? I can think of lots of cases where model code may need to deal with URLs (integrating with external systems, etc).
You may also find the following approach cleaner than including every method:
Any logic having to do with what is displayed in the view should be delegated to a helper method, as methods in the model are strictly for handling data.
Here is what you could do:
I've found the answer regarding how to do this myself. Inside the model code, just put:
For Rails <= 2:
For Rails 3:
This magically makes
thing_path(self)
return the URL for the current thing, orother_model_path(self.association_to_other_model)
return some other URL.I really like following clean solution.
It's from http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/
In Rails 3, 4, and 5 you can use:
e.g.
While there might be a way I would tend to keep that kind of logic out of the Model. I agree that you shouldn't put that in the view (keep it skinny) but unless the model is returning a url as a piece of data to the controller, the routing stuff should be in the controller.