条件to_param方法

时间:2011-01-10 13:56:38

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

我正在使用模型实例方法t_param来生成SEO样式的URL

def to_param
  url
end

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

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

5 个答案:

答案 0 :(得分:2)

您是否完全反对在网址中提供ID?如果没有,我过去所做的事情(也实现了'seo friendly'网址的目标是:

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])

无需覆盖任何发现者(还有在前端和管理员后端工作的额外好处)。

答案 1 :(得分:2)

我有同样的问题。模型真的不能/不应该知道控制器的任何信息。控制器的工作是确定正在请求的资源,并调用模型来访问它。如果您的AdminController需要使用标准数字ID,则您不想触及to_param

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

假设您已将命名空间命名为,您将拥有MyModelController和Admin :: MyModelController以及他们的帮助程序。在管理员中,以标准方式执行操作。在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这种方法,除非你在生成路径/网址之前检查你是否在管理员的状态。

答案 2 :(得分:2)

在模型类变量@@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中的其他技巧=)

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

抓住gem friendly_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 - 但事情似乎通常像你想要的那样工作,所以如果不重用宝石,你可能会调整他们的代码。