开发者

conditional to_param method

I am using the model instance method t_param to generate a SEO-style URL

def to_param
  url
end

that way I can generate links to the model with path_to_model(model) and query the model with Model.find_by_url(url). This works fine so far.

My question: I have RESTFUL admin routes for the backend. Can I somehow make the to_param me开发者_开发知识库thod react to the route it is called by? Because I want to create links in the backend with the ID parameter and not the URL parameter. Or what is the correct approach here?


I had the same issue. A model really can't/shouldn't know anything about controllers. It's the controller's job to determine what resource is being requested, and to call the model to access it. If your AdminController needs to use the standard numeric ID, you're not going to want to touch to_param.

As it turns out, the solution is quite simple, and I use it in production.

Assuming you've namespaced your controllers, you'll have a MyModelController and a Admin::MyModelController, along with their helpers. In Admin, do things the standard way. In MyModelController, do the following:

In your resource actions, refer to params[:id] but treat it like a permalink (URL). For example

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

In your MyModelHelper

def my_model_path my_model
  super my_model.url
end

def my_model_url my_model
  super my_model.url
end

To me it felt this was the best way to "not fight" rails and get what I needed done.

There might be a more clever way to override the named routes. Also I think you can't use helper :all with this approach, unless you check state of whether you're in admin or not before generating paths/url's.


Are you completely opposed to having the ID in the url? If not, what I've done in the past (that also accomplishes the goal of 'seo friendly' urls is this:

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

Thus, instead of:

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

you get

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

Since the String::to_i method will stop once it encounters a non-integer character (i.e. "1".to_i and "1-jerry-seinfeld".to_i both return 1), this means you can also do:

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

without having to override any of your finders (with the added benefit of working on your frontend and your admin backend).


Use in your model class variable @@to_param and class method for control it.

For example in model:

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

In controller:

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 and other tricks in help =)


Here's one way to do it...

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


grab the gem friendly_id and check out how they do it -- http://rubygems.org/gems/friendly_id

They have

  def to_param
    (friendly_id || id).to_s
  end

in their model support -- https://github.com/norman/friendly_id/blob/master/lib/friendly_id/active_record_adapter/simple_model.rb -- but things seem to work generally like you want so you could probably adapt their code if not reuse the gem.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜