【问题标题】:View helper link_to in Model class在 Model 类中查看 helper link_to
【发布时间】:2011-01-17 13:18:56
【问题描述】:

使用 Rails 3,有没有办法在模型内部使用 link_to 帮助器或任何帮助器?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    出于某些原因,您可能需要在模型中使用 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)
    

    【讨论】:

    • 这个问题是不久前提出的,当时@andy 的建议帮助我解决了这个问题。但是,从某种意义上说,您是对的,但并未回答实际问题。
    【解决方案2】:

    如果您在 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_helpersActionView::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
    • @karlingen - 省略对 Rails.application.routes... 的引用会导致消息“无法处理传递给 url_for 的参数。请要求路由或提供您自己的实现”
    【解决方案3】:

    我让它与以下内含物一起使用:

    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
    

    【讨论】:

    • fwiw,Rails 文档确实引领了这个解决方案。 ActionDispatch::Routing::UrlFor 的文档指出“提示:如果您需要从模型或其他地方生成 URL,那么 ActionController::UrlFor 就是您要寻找的。”然后,当您包含它作为错误消息提供的该文件时:引发“为了使用#url_for,您必须明确包含路由助手。”“例如,`include Rails.application.routes.url_helpers”所以我认为这是可以接受的按照 Rails 约定 - 有时这是生成链接的最佳方式/最佳位置:)
    • 是的,例如,如果您的模型正在处理对第三方、场外网关的付款授权,并且需要生成返回/取消 URL 回应用程序。
    【解决方案4】:

    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
    

    【讨论】:

      【解决方案5】:

      如果您想在任何地方使用任何模块的东西并且不介意违反所有 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>"
      

      【讨论】:

        【解决方案6】:

        并非没有骇客。

        如果您认为在模型中需要link_to,您可能违反了Model-View-Controller architecture 的某些原则。

        模型应该是数据和业务逻辑的地方,但生成链接几乎肯定是控制器或视图的工作(或者,特别是 Rails,在帮助器类中)。

        【讨论】:

        • 谢谢。将东西移动到查看助手。现在一切都适合。
        • 在模型中使用助手是有充分理由的。但更重要的是,如果你要提出意见,至少要提供一个解决方案,以防他们考虑透彻。有 2k rep 的人有可能头朝下。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-24
        • 2012-03-26
        • 1970-01-01
        • 1970-01-01
        • 2012-11-09
        • 1970-01-01
        相关资源
        最近更新 更多