【发布时间】:2011-01-17 13:18:56
【问题描述】:
使用 Rails 3,有没有办法在模型内部使用 link_to 帮助器或任何帮助器?
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-3
使用 Rails 3,有没有办法在模型内部使用 link_to 帮助器或任何帮助器?
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-3
出于某些原因,您可能需要在模型中使用 link_to。是的,@andy,这违反了 MVC,但这并不意味着您应该因为不回答问题而获得积分。
@schwabsauce,比这更容易。如果您在初始化程序或其他东西中执行第一行,则甚至不是绝对必要的。同样的事情适用于 .sanitize 和 .raw 以及一大堆其他很棒的功能。
ActionView::Base.send(:include, Rails.application.routes.url_helpers)
ActionController::Base.helpers.link_to(whatever)
如果您想使用自动路径,您可能必须在您的 link_to 中执行此操作:
Rails.application.routes.url_helpers.page_path(@page)
【讨论】:
如果您在 Rails 3.2.1 中执行此操作,请务必遵循 Chuck 帖子中概述的建议。在 Rails 3.2.1 的非视图类中包含 link_to 帮助器似乎不是一种安全的方法。下面概述了一种更安全的方法(无论如何都对我们有用)。
当我们在其中一个课程中使用 Chuck 的帖子中的方法时,它最终会产生非常麻烦且难以调试的后果。它最终导致了仅在非常特定(且罕见)的情况下出现的副作用/错误。
据我们所知,问题在于这一行:
ActionView::Base.send(:include, Rails.application.routes.url_helpers)
告诉ActionView::Base 包括Rails.application.routes.url_helpers,ActionView::Base 显然已经自己做了。让它再次包含url_helpers,似乎会导致重新初始化路由状态(@_routes 在包含 ActionDispatch::Routing::UrlFor 模块的类中)。
这会导致视图中出现看似随机且无法解释的“nil:NilClass 的未定义方法 'url_for'”异常,这些异常会在尝试直接或间接调用 url_for 方法的视图之后 ActionView::Base 包含url_helpers第二次。
对我们有用的解决方案不是告诉ActionView::Base 再次包含url_helpers,只需将UrlHelper 模块自己包含在您可能需要的任何地方。
然后,当您需要使用 link_to 并有权访问路径时,您可以简单地执行此操作(假设 login_path 对您的应用有效):
include ActionView::Helpers::UrlHelper
...
link = link_to('here', Rails.application.routes.url_helpers.login_path)
我们花了很长时间和相当多的头来追查由双重包含引起的错误,我只是想警告其他人在调整 Rails 基类的行为时要小心。
【讨论】:
include ActionView::Helpers::UrlHelper
Rails.application.routes... 的引用会导致消息“无法处理传递给 url_for 的参数。请要求路由或提供您自己的实现”
我让它与以下内含物一起使用:
include ActionView::Helpers::UrlHelper
include ActionController::UrlFor
include Rails.application.routes.url_helpers
cattr_accessor :controller
def controller; self.class.controller; end
def request; controller.request; end
然后在我的控制器中填充属性(从头开始创建控制器需要参数哈希中的大量数据)。
Lead.controller = self
【讨论】:
link_to helper,违反 MVC
安迪说的,
如果您在模型中生成 HTML,您可能需要仔细查看您在做什么以及为什么这样做。
网址助手
另一方面,URL 通常在视图控制器代码之外派上用场,例如在各种 service/form/api/... 类中,甚至在必要时在模型中也是如此。
是的,Rails.application.routes.url_helpers 是一个模块,但这并不意味着你应该在任何地方都包含它,否则有趣的事情会开始发生,正如 Gary 所说:
https://www.destroyallsoftware.com/blog/2011/one-base-class-to-rule-them-all
你可以做的是:
delegate :url_helpers, :to => 'Rails.application.routes'
然后使用,例如
url_helpers.home_url
【讨论】:
如果您想在任何地方使用任何模块的东西并且不介意违反所有 Ruby 规范,请将这个骇客扔到服务中:
module View
extend self
class HelperIncluder
include ActionView::Helpers::UrlHelper
end
def link_to(*args)
HelperIncluder.new.link_to(*args)
end
end
现在:
View.link_to('a', 'b') => "<a href=\"b\">a</a>"
【讨论】:
并非没有骇客。
如果您认为在模型中需要link_to,您可能违反了Model-View-Controller architecture 的某些原则。
模型应该是数据和业务逻辑的地方,但生成链接几乎肯定是控制器或视图的工作(或者,特别是 Rails,在帮助器类中)。
【讨论】: