开发者

making a pretty url via ruby

Ok so i want the title of an event to be in the url like

/events/party-at-mikes

so here is how i am doing it

Event.find_by_title(params[:title])

my link

 <%= link_to('<span>EVENTS</span>', course_event_path(obj.golf_course.city.permalink, obj.golf_course.permalink, obj.title), :class => 'right eve_bnt') %>

the obj.title is the event

the problem is t开发者_如何学Chat the url looks like this

events/Party at mikes

what do i need to do to make is put the - in space of spaces and on the find capture that


You should really look at the friendly_id gem. It purports to do exactly what you're intending, and takes care of a number of edge cases. The main edge case that makes this a bit of a pain is: what if two events have the exact same title?

Ignoring the corner cases, the correct way to do this is to overload two methods of your class:

class Event < ActiveRecord::Base
    ...

    # This is used automatically to build the :id component of the url
    # in the form /models/:id
    def to_param
        self.title
    end

    # Now assuming that you just use Event.find(params[:id]),
    # you probably want Event.find to work differently.
    def self.find(identifier)
        self.find_by_title(identifier)
    end

    ...
end


Andres suggests overriding to_param to use title, but this isn't acceptable as you don't want spaces etc. What you need is a permalink, or slug, for the model, stored in a string field called 'slug' in the example below. This gets created when the record is saved, and subsequently never changes: this is used as the replacement for id in urls. The slug has only letters, numbers and hyphens, and can be forced to be unique by the addition of numbers to the end. Then, you change to_param to use the slug, and you find by slug in your controller. eg

before_create :set_slug

def set_slug
  slug = self.title.downcase.gsub(/[^a-z0-9]/,"-")
  suffix = ""
  while self.class.find_by_slug(slug)
    slug.gsub!(/#{suffix}$/,(suffix == "" ? 1 : suffix+=1).to_s) 
  end
  self.slug = slug
end

def to_param
  self.slug
end

In your events controller

  before_filter :load_event, :except => [:index, :new]
...
protected
  def load_event
    @event = Event.find_by_slug(params[:id])
  end


Have a look at http://railscasts.com/episodes/63-model-name-in-url


I would definitely go the route of keeping the id in the url along with a friendly name attached to it. This makes debugging easier if you have a bad record, and is trivial to implement. Not to mention sql can find an int far faster than a varchar.

Just drop this in your model. No need to define the slugging method, since this is provided in rails already via parameterize. It also has the advantage of requiring 0 changes to your other code. This will work in almost all situations out of the box.


  # Slug the url.
  def to_param
    "#{id}-#{title.parameterize}"
  end
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜