【问题标题】:conditional to_param method条件 to_param 方法
【发布时间】:2011-01-10 13:56:38
【问题描述】:

我正在使用模型实例方法 t_param 来生成一个 SEO 风格的 URL

def to_param
  url
end

这样我可以使用 path_to_model(model) 生成指向模型的链接,并使用 Model.find_by_url(url) 查询模型。到目前为止,这工作正常。

我的问题:我有后端的 RESTFUL 管理路由。我可以以某种方式使 to_param 方法对调用它的路由做出反应吗?因为我想在后端使用 ID 参数而不是 URL 参数创建链接。或者这里的正确方法是什么?

【问题讨论】:

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


    【解决方案1】:

    我有同样的问题。模型真的不能/不应该对控制器一无所知。控制器的工作是确定正在请求什么资源,并调用模型来访问它。如果您的 AdminController 需要使用标准数字 ID,则您不会想要触摸 to_param

    事实证明,解决方案非常简单,我在生产中使用它。

    假设您已为控制器命名空间,您将拥有一个 MyModelController 和一个 Admin::MyModelController 以及它们的助手。在 Admin 中,以标准方式做事。在 MyModelController 中,执行以下操作:

    在您的资源操作中,请参阅params[:id],但将其视为永久链接 (URL)。例如

    def get
      @my_model = MyModel.find_by_url(params[:id])
      ...
    end
    

    在您的 MyModelHelper 中

    def my_model_path my_model
      super my_model.url
    end
    
    def my_model_url my_model
      super my_model.url
    end
    

    对我来说,这是“不打”铁轨并完成我需要做的事情的最佳方式。

    可能有一种更聪明的方法来覆盖命名路由。另外我认为你不能在这种方法中使用helper :all,除非你在生成路径/url之前检查你是否处于管理员状态。

    【讨论】:

      【解决方案2】:

      您是否完全反对在 url 中包含 ID?如果没有,我过去所做的(也实现了“seo 友好”网址的目标是这样的:

      class Person
        def to_param
          "#{id}-#{name.parameterize}"
        end
      end
      

      因此,而不是:

      http://www.example.com/users/1

      你得到

      http://www.example.com/users/1-jerry-seinfeld

      由于String::to_i方法会在遇到非整数字符时停止(即"1".to_i"1-jerry-seinfeld".to_i都返回1),这意味着你也可以这样做:

      person = Person.find(params[:id])
      

      无需覆盖您的任何查找器(还有在前端和管理后端工作的额外好处)。

      【讨论】:

      • 这是一个很好的解决方法,但实际上我真的反对在 URL 中包含 ID,因为我想通过 URL 将模型的内部与外部表示严格分开。我仍在寻找如果可能的话,我可以让 to_param 方法对上下文做出反应的解决方案..
      【解决方案3】:

      在您的模型类变量@@to_param 和控制它的类方法中使用。

      例如在模型中:

      class ProductCategory < ActiveRecord::Base
        @@to_param = true
      
        attr_accessible :description, :name, :parent_id
        has_ancestry
        has_many :products
        validates :slug, :uniqueness => true, :presence => true
      
        before_validation :generate_slug
      
        #Trigger fo 'to_param' method
        def self.to_param_trigger(test)
          if (test)
            @@to_param = true
          else
            @@to_param = false
          end
        end
      
        def to_param
          if @@to_param
            slug
          else
            id
          end
        end
      
        def generate_slug
          self.slug ||= self.ancestors.map {|item| item.name.parameterize}.push(self.name.parameterize).join('/')
        end
      end
      

      在控制器中:

      class Backend::ProductCategoriesController < Backend::BaseController
        def index
          # Disable 'to_param'
          ProductCategory.to_param_trigger false
          @categories = ProductCategory
            .select([:id, :name, :slug])
            .select("COALESCE(ancestry, '0') as anctr")
            .order :anctr, :name
        end
      
        def new
        end
      
        def edit
        end
      end
      

      before_filter 和 help 中的其他技巧 =)

      【讨论】:

      • 你确定这不会搞砸吗?如果您正在设置一个类变量,该值也将存在于所有类中,因此如果您在生产环境中运行它,一旦启用 to_param_filter,所有请求都将具有该值,而与命名空间无关
      • 另外,对于多线程的情况还有疑问,但是对于我这个比较简单的情况,这个方案是合适的
      【解决方案4】:

      这是一种方法......

      class BlogPost
        def to_param
          url
        end
      
        # BlogPost.find_by_param("14") => looks for ID 14
        # BlogPost.find_by_param("foobar") => looks for url "foobar"
        # BlogPost.find_by_param("14-foobar") => looks for ID 14 (ignores the "-foobar" part)
        def self.find_by_param(param)
          if param.to_s =~ /^[0-9]+/
            find_by_id param.to_i
          else
            find_by_url param.to_s
          end
        end
      end
      

      【讨论】:

      • 这里也一样,我不想在 URL 中使用 ID,因为我想通过 URL 将模型的内部与外部表示严格分开......可能......
      • 这不会将 ID 放在 URL 中。它所做的只是为您提供另一个类方法 BlogPost.find_by_param,您可以使用它代替 BlogPost.find_by_url,无论您给它一个 ID 还是 URL,它都有效。
      【解决方案5】:

      获取 gemfriendly_id 并查看他们是如何做到的 -- http://rubygems.org/gems/friendly_id

      他们有

        def to_param
          (friendly_id || id).to_s
        end
      

      在他们的模型支持中——https://github.com/norman/friendly_id/blob/master/lib/friendly_id/active_record_adapter/simple_model.rb——但事情似乎通常如你所愿,所以如果不重用 gem,你可能会调整他们的代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-26
        • 2013-07-13
        • 2010-10-21
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        相关资源
        最近更新 更多