Can Rails Routing Helpers (i.e. mymodel_path(model

2020-01-22 13:26发布

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).

7条回答
放荡不羁爱自由
2楼-- · 2020-01-22 13:53

You may also find the following approach cleaner than including every method:

class Thing
  delegate :url_helpers, to: 'Rails.application.routes' 

  def url
    url_helpers.thing_path(self)
  end
end
查看更多
We Are One
3楼-- · 2020-01-22 13:55

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:

# In the helper...

def link_to_thing(text, thing)
  (thing.url?) ? link_to(text, thing_path(thing)) : link_to(text, thing.url)
end

# In the view...

<%= link_to_thing("text", @thing) %>
查看更多
在下西门庆
4楼-- · 2020-01-22 13:59

I've found the answer regarding how to do this myself. Inside the model code, just put:

For Rails <= 2:

include ActionController::UrlWriter

For Rails 3:

include Rails.application.routes.url_helpers

This magically makes thing_path(self) return the URL for the current thing, or other_model_path(self.association_to_other_model) return some other URL.

查看更多
姐就是有狂的资本
5楼-- · 2020-01-22 13:59

I really like following clean solution.

class Router
  include Rails.application.routes.url_helpers

  def self.default_url_options
    ActionMailer::Base.default_url_options
  end
end

router = Router.new
router.posts_url  # http://localhost:3000/posts
router.posts_path # /posts

It's from http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/

查看更多
Lonely孤独者°
6楼-- · 2020-01-22 14:05

In Rails 3, 4, and 5 you can use:

Rails.application.routes.url_helpers

e.g.

Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:host => "example.com")
查看更多
做个烂人
7楼-- · 2020-01-22 14:08

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.

查看更多
登录 后发表回答