Topic: Another routing question

Hello guys
This is what I want to do:
I  have a Trip model with a load_on date, I want to make a route like this: trips/year/month/day
Right now I have this is my controller:

 
def index
     @trips = Trip.find(:all, :conditions => ['YEAR(load_on) = ? AND MONTH(load_on) = ? AND DAY(load_on) = ?', params[:year], params[:month], params[:day]])
       
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @trips }
    end
  end

and routes.rb

map.resources :trips

map.connect 'trips/:year/:month/:day', :controller => 'trips',
    :month => nil, :day => nil, :requirements => { :year => /\d{4}/ }
   
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'


But my index action now doesn't display anything, I guess I am not doing something right in routes.rb

Last edited by leTus (2008-04-16 04:56:10)

Re: Another routing question

Hi leTus,

Could you provide some more details on this? What do you mean by "But my index action now doesn't display anything"? Does it give you a blank page and no error messages? What do you see in the development log? Does the request "reach" the index action of your controller? Try inserting something like

def index
  raise self.inspect
end

to see this.

Also, the :action => <action_name> seems to be lacking from your route definition but I might be wrong here.

B

Re: Another routing question

OK, I changed the code based on this post http://railsforum.com/viewtopic.php?id=3741

Now I have this:
Controller -

def index
     @trips = Trip.find_by_date(params[:year], params[:month], params[:day])   
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @trips }
    end
  end

Model
def self.find_by_date(year, month, day)
    if year == nil then
      find(:all)
    else
      conditions = []
      conditions << ["YEAR(load_on) = ?", year] if year
      conditions << ["MONTH(load_on) = ?", month] if month
      conditions << ["DAY(load_on) = ?", day] if day
      find(:all, :conditions => [conditions.transpose.first.join(' AND '), *conditions.transpose.last])
    end
  end

route.rb

map.resources :trips

  map.connect 'trips/:year/:month/:day', :controller => 'trips',
    :month => nil, :day => nil, :requirements => { :year => /\d{4}/,
                                                   :day => /\d{1,2}/,
                                                   :month => /\d{1,2}/ }
   
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'


Now I have a problem when I just put the year on like /trips/2008 I get no trip with such ID, basically it's looking for a trip with that ID not the year. Everything else it's working fine.

Re: Another routing question

That's because the URL will me mapped to the first matched route in your routes.rb file and the map.resources :trips creates a route that will match /trips/2008, see here. You can get around that by swapping the order of the two route definitions:

map.connect 'trips/:year/:month/:day', :controller => 'trips',
     :month => nil, :day => nil, :requirements => { :year => /\d{4}/ }
map.resources :trips

The caveat is that you'll have to find another way to get the show action of your trips with 4-digit ids smile

Also, that code

   ...
   conditions << ["YEAR(load_on) = ?", year] if year
   conditions << ["MONTH(load_on) = ?", month] if month
   conditions << ["DAY(load_on) = ?", day] if day
   ...

will not work in PostgreSQL (not sure about which database you use), so it's not database agnostic, but maybe it is a tradeoff you can assume.

Hope that helps,
B

Re: Another routing question

Thanks erdibalint, switching them around worked. For now I am using mysql and it's not going to change. Also my IDs are not even close to 4 digit numbers but how about later on? Is there a way around that???

Re: Another routing question

Honestly, I am not sure, I am pretty certain that there is no way to know whether the request /trips/2008 refers to the list of trips (#1) in 2008 or the show action of the trip with id 2008 (#2). If you could name your controller/model just 'trip' and not 'trips' there would be no ambiguity since /trips/2008 would refer to #1, and /trip/2008 would refer to #2. However, I am not knowledgeable about REST in rails (yet smile ) so not sure how should one go about it with a restful controller.

B

Re: Another routing question

One more thing, there are very good posts on Jamis Buck's blog about routing, maybe that can help, too.

B

Re: Another routing question

Sorry for posting in tiny bits, another solution is just to rename the prefix which identifies your "archives", let me show how:

map.connect 'archives/:year/:month/:day', :controller => 'trips',
      :month => nil, :day => nil, :requirements => { :year => /\d{4}/ }
map.resources :trips

That removes the ambiguity so the order of the route definitions is no longer relevant either.

B