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

Aar*_*ell 355 ruby-on-rails rails-routing helpermethods

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

<% if thing.url.blank? %>
<%= link_to('Text', thing_path(thing)) %>
<% else %>
<%= link_to('Text', thing.url) %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

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

<%= thing_link('Text', thing) %>
Run Code Online (Sandbox Code Playgroud)

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

<%= link_to('Text', thing.link) %>
Run Code Online (Sandbox Code Playgroud)

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

def link
  (self.url.blank?) ? thing_path(self) : self.url
end
Run Code Online (Sandbox Code Playgroud)

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

小智 676

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

Rails.application.routes.url_helpers
Run Code Online (Sandbox Code Playgroud)

例如

Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:host => "example.com")
Run Code Online (Sandbox Code Playgroud)

  • 避免在任何地方复制`:host`选项并在环境配置文件中设置一次:`Rails.application.routes.default_url_options [:host] ='localhost:3000'` (38认同)
  • Ypu可以将它包含在任何模块中,之后你可以在那里访问url-helpers.谢谢 (14认同)
  • 这在Rails 4中有用吗?我无法让它发挥作用. (10认同)
  • 我也无法让它在rails 4中工作.:( (6认同)
  • `include Rails.application.routes.url_helpers`在Rails 4.1中适合我 (5认同)

Aar*_*ell 179

我自己找到了关于如何做到这一点的答案.在模型代码中,只需:

对于Rails <= 2:

include ActionController::UrlWriter
Run Code Online (Sandbox Code Playgroud)

对于Rails 3:

include Rails.application.routes.url_helpers
Run Code Online (Sandbox Code Playgroud)

这奇怪地thing_path(self)返回当前事物的URL,或other_model_path(self.association_to_other_model)返回一些其他URL.

  • 只是一个更新,因为上面的内容已被弃用.这是当前的包括:`include Rails.application.routes.url_helpers` (27认同)
  • 我尝试这个时得到NoM​​ethodError(## ActionView :: Base:0x007fe8c0eecbd0>的未定义方法`optimize_routes_generation?') (2认同)

mat*_*ins 114

您可能还会发现以下方法比包含每种方法更清晰:

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

  def url
    url_helpers.thing_path(self)
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 关于这方面的文档似乎很难找到,所以这里有关于在ActiveSupport中使用委托的一个不错的链接.http://www.simonecarletti.com/blog/2009/12/inside-ruby-on-rails-delegate/ (7认同)
  • 我得到一个`undefined局部变量或方法'url_helpers'用于Event:Class`错误...... :( (2认同)

Jos*_*man 13

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

这是你可以做的:

# 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) %>
Run Code Online (Sandbox Code Playgroud)

  • 随着Web服务API不断增长,模型通常需要使用自己的数据联系外部资源并提供回调URL.例如,照片对象需要将自己发布到Socialmod,后者会在执行审核时回调该照片的URL.post_create()挂钩有意义发布到Socialmod,但你怎么知道回调URL?我认为作者自己的答案很有道理. (12认同)
  • 虽然你在严格的技术意义上是正确的,但有时人们只需要工作而不必剃掉每一只牦牛,以避免违反一些神圣的设计模式或者你有什么,也许他们需要得到网址,并且实际存储它在数据库中会很方便,然后模型才能知道如何做而不是来回传递事物,有时规则可以被打破. (3认同)

Swa*_*hah 6

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

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
Run Code Online (Sandbox Code Playgroud)

它来自http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/