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

Posted

技术标签:

【中文标题】Rails 路由助手(即 mymodel_path(model))可以在模型中使用吗?【英文标题】:Can Rails Routing Helpers (i.e. mymodel_path(model)) be Used in Models? 【发布时间】:2010-09-25 08:43:57 【问题描述】:

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

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

视图中的这种条件逻辑很难看。当然,我可以构建一个辅助函数,它将视图更改为:

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

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

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

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

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

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

【问题讨论】:

一个用例是:在 aftersave 中从 goo.gl 生成缩短的 url, 如果您想添加视图逻辑,您可能应该将模型包装在演示器中,这将使 MVC 层保持分离。请参阅 Draper(github.com/jcasimir/draper)。 另请参阅api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html文档中的“命名路由的 URL 生成”部分 【参考方案1】:

在 Rails 3 及更高版本中:

Rails.application.routes.url_helpers

例如

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

【讨论】:

Ypu 可以将它包含到任何模块中,之后您可以在那里访问 url-helpers。谢谢 避免在任何地方复制您的:host 选项并在您的环境配置文件中设置一次:Rails.application.routes.default_url_options[:host] = 'localhost:3000' include Rails.application.routes.url_helpers 在 Rails 4.1 中为我工作 如果您只需要路径,您可以使用 :only_path => true 作为选项,而无需传递主机参数。 这似乎是个不错的选择:hawkins.io/2012/03/…【参考方案2】:

我自己找到了有关如何执行此操作的答案。在模型代码中,只需输入:

对于 Rails

include ActionController::UrlWriter

对于 Rails 3:

include Rails.application.routes.url_helpers

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

【讨论】:

只是一个更新,因为上述内容已被弃用。这是当前包括:include Rails.application.routes.url_helpers 当我尝试这个时,我得到 NoMethodError (undefined method `optimize_routes_generation?' for #<:base:0x007fe8c0eecbd0>)【参考方案3】:

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

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

  def url
    url_helpers.thing_path(self)
  end
end

【讨论】:

这方面的文档似乎很难找到,所以这里有一个关于在 ActiveSupport 中使用委托的不错的链接。 simonecarletti.com/blog/2009/12/inside-ruby-on-rails-delegate 我收到undefined local variable or method 'url_helpers' for Event:Class 错误... :( 我收到undefined method url_helpers。我要做什么? @asiniy,你确定你已经使用了在类声明之后编写的 url_helpers 的委托选项吗? 不起作用,但这可能只有在您创建自己的class 时才有效,如答案所示。如果您的 Model 类已经扩展 &lt; ApplicationRecord 这将不起作用?【参考方案4】:

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

你可以这样做:

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

【讨论】:

在这种情况下我不喜欢辅助方法的地方:当我查看 link_to_thing() 时,我必须确定它是特定于事物还是应用程序范围的辅助方法(它很容易是)。我需要考虑为源检查 2 个文件。 thing.link 对源文件毫无疑问。 另外,如果我需要在 Rake 任务中使用此功能(可能导出事物 URL 的 CSV 文件)怎么办……在这种情况下,直接进入模型也会好得多. 但不同之处在于模型中的 link_to 不可用,因为它是一个 ActionView 助手。所以,这行不通。你可以修改模型中的一些属性默认值,所以如果没有设置,它会默认为某个值,但这取决于你。 随着 Web 服务 API 的增长,模型通常需要使用自己的数据联系外部资源并提供回调 URL。例如,照片对象需要将自己发布到 Socialmod,Socialmod 会在执行审核时回调该照片的 URL。一个 after_create() 钩子发布到 Socialmod 是有意义的,但是你怎么知道回调 URL 呢?我认为作者自己的回答很有道理。 虽然您在严格的技术意义上是对的,但有时人们只需要工作即可,而不必为每只牦牛刮毛,以避免违反某些神圣的设计模式或您拥有的东西,也许他们需要获取 url 并将其实际存储在数据库中会很方便,因为模型只知道如何做到这一点而不是来回传递东西,有时规则可能会被打破。【参考方案5】:

我真的很喜欢遵循干净的解决方案。

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/

【讨论】:

【参考方案6】:

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

【讨论】:

回复:“除非模型将 URL 作为一条数据返回”。这正是这里发生的事情......模型“拥有”这条数据,它是指向现场或非现场 URL 的链接。在某些情况下,URL 是从 Rails 路由生成的。在其他情况下,URL 是用户提供的数据。【参考方案7】:

(编辑:忘记我之前的唠叨...)

好的,在某些情况下,您可能会转到模型或其他一些网址...但我真的不认为这属于模型,视图(或者可能是模型)听起来更合适。

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

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

【讨论】:

假设你有一个 Image 模型。如果 Image 有与之关联的外部 URL,则指向该 URL。否则,指向Image的show page上传图片?只是一个想法。 这个不太通用的例子怎么样:link_to "Full Size Image", image.link 模型中的链接方法要么链接到现场 URL (image_path),要么链接到一个如果用户提供了 Flickr URL,并且在图像上设置了 .url。

以上是关于Rails 路由助手(即 mymodel_path(model))可以在模型中使用吗?的主要内容,如果未能解决你的问题,请参考以下文章

Rails:如何访问 RESTful 助手?

资产管道中的路由助手

如何从控制器路由 Rails 4 获得不同的和多个视图

命名路由 _path 与 _url

实现 Rails 视图助手

如何将 Rails 视图助手提取到 gem 中?