可以在模型中使用Rails路由助手(即mymodel_path(模型))吗?

Can Rails Routing Helpers (i.e. mymodel_path(model)) be Used in Models?

假设我有一个叫Thing的Rails模型。它有一个URL属性,可以选择设置为Internet上的某个URL。在视图代码中,我需要执行以下操作的逻辑:

1
2
3
4
5
<% if thing.url.blank? %>
<%= link_to('Text', thing_path(thing)) %>
<% else %>
<%= link_to('Text', thing.url) %>
<% end %>

这种观点中的条件逻辑是丑陋的。当然,我可以构建一个助手函数,它将视图更改为:

1
<%= thing_link('Text', thing) %>

这解决了冗长的问题,但我更喜欢在模型本身中拥有功能。在这种情况下,视图代码为:

1
<%= link_to('Text', thing.link) %>

显然,这需要模型上的链接方法。它需要包含以下内容:

1
2
3
def link
  (self.url.blank?) ? thing_path(self) : self.url
end

就问题而言,thing_path()是模型代码中未定义的方法。我假设有可能将一些辅助方法"拉入"到模型中,但是怎么做呢?路由只在应用程序的控制器和视图层上运行,这有什么真正的原因吗?我可以考虑很多情况,模型代码可能需要处理URL(与外部系统集成等)。


在Rails 3、4和5中,可以使用:

1
Rails.application.routes.url_helpers

例如

1
2
Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:host =>"example.com")


我自己就找到了解决办法。在模型代码中,只需输入:

对于轨道<=2:

1
include ActionController::UrlWriter

对于轨道3:

1
include Rails.application.routes.url_helpers

这神奇地使thing_path(self)返回当前内容的URL,或者other_model_path(self.association_to_other_model)返回其他URL。


您还可能发现以下方法比包括每种方法更干净:

1
2
3
4
5
6
7
class Thing
  delegate :url_helpers, to: 'Rails.application.routes'

  def url
    url_helpers.thing_path(self)
  end
end


任何与视图中显示内容有关的逻辑都应该委托给一个助手方法,因为模型中的方法严格用于处理数据。

以下是您可以做的:

1
2
3
4
5
6
7
8
9
# 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) %>


我真的很喜欢用干净的溶液。

1
2
3
4
5
6
7
8
9
10
11
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

它来自http://hawkins.io/2012/03/generating_urls_when_and_wherewhere_you want/


虽然可能有一种方法,但我倾向于将这种逻辑排除在模型之外。我同意您不应该将其放在视图中(保持精简),但是除非模型将URL作为一段数据返回给控制器,否则路由资料应该在控制器中。


(编辑:忘记我以前的胡言乱语…)

好吧,在某些情况下,您可能会转到模型或其他URL…但我并不认为这属于模型,视图(或者模型)听起来更合适。

关于路由,据我所知,路由是用于控制器中的操作(wich通常"神奇地"使用视图),而不是直接用于视图。控制器应处理所有请求,视图应显示结果,模型应处理数据并将其提供给视图或控制器。我听过很多人在这里谈论通往模型的路线(到目前为止,我都开始谈论它),但据我所知,路线是通向控制器的。当然,许多控制器都是一个模型的控制器,通常称为sController(例如,"用户控制器"是模型"用户"的控制器)。

如果您发现自己在视图中编写了大量的逻辑,请尝试将逻辑移动到更合适的地方;请求和内部通信逻辑可能属于控制器,与数据相关的逻辑可能被放置在模型中(但不包括显示逻辑,其中包括链接标记等),而与显示相关的逻辑将被放置在一个助手。