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

假设我有一个叫Thing的Rails模型。Thing有一个url属性,可以将(可选)设置为Internet上某个地方的url。在视图代码中,我需要这样做的逻辑:

<% if thing.url.blank? %>
<%= link_to('Text', thing_path(thing)) %>
<% else %>
<%= link_to('Text', thing.url) %>
<% end %>

视图中的条件逻辑是丑陋的。当然,我可以构建一个helper函数,它会将视图更改为:

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

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

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

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

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

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

179518 次浏览

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

以下是你可以做的:

# 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) %>

虽然可能有一种方法,但我倾向于将这种逻辑排除在模型之外。我同意你不应该把它放在视图(保持苗条),但除非模型返回一个url作为一个数据块到控制器,路由的东西应该在控制器。

(编辑:忘了我之前的废话…)

可能在某些情况下你会去到模型或者其他url。但我真的不认为这属于模型,视图(或者模型)听起来更合适。

关于路由,据我所知,路由是为控制器中的动作(通常“神奇地”使用一个视图),而不是直接到视图。控制器应处理所有请求,视图应呈现结果,模型应处理数据并将其提供给视图或控制器。我在这里听到很多人在谈论通往模型的路径(我几乎开始相信它了),但我的理解是:路径通往控制器。当然,许多控制器是一个模型的控制器,通常被称为<modelname>sController(例如。“UsersController”是模型“User”的控制器)。

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

关于如何自己做这件事,我已经找到了答案。在模型代码中,只需放入:

对于Rails <= 2:

include ActionController::UrlWriter

对于Rails 3:

include Rails.application.routes.url_helpers

这将神奇地使thing_path(self)返回当前事物的URL,或other_model_path(self.association_to_other_model)返回其他URL。

在Rails 3及更高版本中:

Rails.application.routes.url_helpers

如。

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

你可能还会发现以下方法比包含所有方法更简洁:

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


def url
url_helpers.thing_path(self)
end
end

我真的很喜欢清洁解决方案。

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_whenever_and_wherever_you_want/