views:

363

answers:

3

I have a site listing many jobs, but I also want each account to be able to access its jobs in one place. Thus, I am using these routes:

map.resources :jobs
map.resource :account, :has_many => :jobs

This gets me URLs like localhost/jobs/ and localhost/account/jobs. However, both seem to render JobsController::index. How can I either make a conditional in the index action (how do I access whether account/jobs or just jobs was specified in the URL?) or change the account route to render a different action? What's the proper way to do this?

A: 

If you run "rake routes" you should see something like this

account_jobs  GET    /accounts/:account_id/jobs/:job_id    {:controller => 'jobs', :action => 'index'}

This means when your action is called via the /account/jobs route you should have an :account_id parameter. You can then do your logic switch based on the existence of this param:

if params[:account_id].nil?
   ...
else
   ...
end
avaynshtok
map.resource doesn't work this way.
EmFi
I just did this on a clean rails project to validate, and yes, it does work this way.routes.rb: ActionController::Routing::Routes.draw do |map| map.resources :jobs map.resources :accounts, :has_many => :jobs"rake routes" account_jobs GET /accounts/:account_id/jobs(.:format) {:controller=>"jobs", :action=>"index"}get http://localhost:3000/accounts/123/jobsfrom log: Processing JobsController#index (for 127.0.0.1 at 2009-11-18 11:24:22) [GET] Parameters: {"account_id"=>"123"}
avaynshtok
Yikes, sorry for the (non) formatting. My point being... what is the meaning of "this way" in your comment?
avaynshtok
The question specifies account as a resource with map.resource. Meaning there is only one of them. The route you mention is not created for resource that has many resources. But it would have been if account was defined with map.resources.
EmFi
Ah! You're absolutely right; I totally missed that it was the singular form of resource in the question. The "each account" bit threw me off.
avaynshtok
+2  A: 

Adding a requirement to the resource definition allows you to pass extra parameters

map.resources :jobs
map.resource :account, :has_many => :jobs, :requirements => {:account => true}

Then params[:account] will be set if the routing url was 'http://www.mysite.tld/account/jobs' and unset if it it was 'http://www.mysite.tld/jobs'

As with all other restful routing the action depends on the context.

  • GET requests without an id route to index.
  • GET requests with an id route to show
  • POST requests route to create
  • PUT requests route to update
  • DELETE requests route to destroy.
EmFi
+3  A: 

You can use a block when creating your routes, and then pass a :controller parameter, like so

map.resource :account do |account|
  # If you have a special controller 'AccountJobsController'
  account.resources :jobs, :controller => "account_jobs"
end

It may be cleaner for you to put your controllers into a directory structure, and then you can reference them in a nested way. For example:

map.resource :account do |account|
  account.resources :jobs, :controller => "accounts/jobs"
end

If you use the above snippet, you should then create a controller in app/controllers/accounts/jobs_controller.rb, which is defined like so:

class Account::JobsController < ApplicationController
  ##
  ## etc.
  ##
end

You can always use rake routes to check which routes have been generated and which controllers they'll use.

bantic
This is a good answer!
Andres Jaan Tack