I need to add some collection routes for a nested resource. I have a subscription controller and I need two new methods to add here. change_plan and update_plan
Basically I need the urls looks like;
http://localhost:3007/admin/accounts/1/subscriptions/7/change_plan
http://localhost:3007/admin/accounts/1/subscriptions/7/update_plan
So where to add change_plan and update_plan? this is what I have so far.
map.namespace :admin do |admin|
admin.resources :payments
admin.resources :accounts, :collection=>{:profile=>:get}, :has_many => [:payments,:subscriptions]
end
Thanks for any help.
Use the alternative syntax for has_many:
admin.resources :accounts, :collection=>{:profile=>:get} do |account|
account.resources :subscriptions, :member => { :change_plan => :get, ... }
...
end
Related
map.resource :basket, :collection => { :checkout => :post }
The above does not work for a resource, as you would expect since basket is a resource (ie. singular) not resources, so there is no concept of a collection, everything should be scoped to the current_user. In this case User has_one Basket.
However I would like to specify a custom route without having to resort to adding another line in routes, eg:
map.checkout 'basket/checkout', :controller => 'baskets', :action => 'checkout'
Is this possible?
Of course my other option is to add a checkouts controller.
Just use :member option instead of :collection:
map.resource :basket, :member => {:checkout => :post}
If the basket is scoped to the user I'd make it a nested resource:
map.resources :users do |users|
users.resource :basket, :member => { :checkout => :post }
end
... or in Rails 3 ...
resources :users do
resource :basket do
post :checkout, :on => :member
end
end
This way you'll be able to scope the basket to the user who's checking out. The URL will end up looking like this:
/users/5/basket/checkout
You also get the nicely worded named route 'checkout_user_basket'.
The following code:
map.resources :users, :has_many => :items
Could be written like this in a block:
map.resources :users do |user|
user.resources :items
end
How could I write the following code in a block?
map.resources :users, :member => { :start => :post }
Also, where could I find documentation on writing routes in blocks?
The Routes Documentation does not seem to show it.
Thank you!
Rails 2.x doesn't allow you to use blocks for member definition.
With Rails 3.x you can write
resources :users do
member do
post :start
end
end
You can do it like so in Rails 2 (2.3.5 is the version I tested it on):
map.resources :users, :member => { :start => :post } do |user|
user.resources :items
end
From here: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/
I have this in routes.rb
map.namespace :admin do |admin|
admin.resources :projects, :has_many => :products
end
What I would like to is to be able to set the something in the routes.rb file in order for me to use new action in the products controller. Actions added by hand after scaffolding.
I tried something like this
map.namespace :admin do |admin|
admin.resources :projects, :has_many => :products , :collection => {:plan => :get}
end
plan being my new action in the products controller
Did not work and I have not find any good solutions anywhere. Please help.
As klew already pointed out you probably want a member action and not a collection action.
But before you go this route think if you really needed. adding custom actions is discouraged. You better stay within the constrains of the 7 CRUD operations. The way to do it is to add more controllers :)
For example if you have users controller and groups controller, then adding person into the group is not join_group action in the users controller, and not add_user action in the group controller, its a regular create action in memberships controller :).
and remember that controllers do not always correspond to models, and models not necessarily correspond to database tables, you can be more flexible.
Back to your case, I think you might want to just add a singleton resource nested inside the project resource like this
map.namespace :admin do |admin|
admin.resources :projects, :has_many_products, :has_one => :plan
end
and implement :show action in the plans_controller, which should be mapped to /admin/projects/:project_id/plan
Change
map.namespace :admin do |admin|
admin.resources :projects, :has_many => :products
end
in
map.namespace :admin do |admin|
admin.resources :projects do |project|
project.resources :products, :member => { :new_action => :get }
end
end
Here you have some examples.
Your example should generate urls like: /admin/projects/plan. If you want to have url like /admin/projects/2/plan then use:
map.namespace :admin do |admin|
admin.resources :projects, :has_many => :products , :member => {:plan => :get}
end
And don't forget to add plan method in your admin/products_controller.rb:
def plan
...
end
I'm not sure, but probably you will need to restart your server after changing routes to get it working.
So In my rails app I have two resources (rentals, and reservations) which belong to a user. This is the code in my routes.rb to set up the nested routes.
map.resources :users, :has_many => :reservations, :shallow => true
map.resources :users, :has_many => :rentals, :shallow => true
map.resources :rentals, :only => [:index]
map.resources :reservations, :only => [:index]
Is there a more perferred way to do this. I've done some googling but I can't find a clear answer.
Thanks in advance.
-ray
Your method duplicates the routes for users, as you can see by running rake routes. You can fix that by passing a block to map.resources:
map.resources :users, :shallow => true do |user|
user.resources :reservations
user.resources :rentals
end
The nested routes created will assume that you always want to access those resources in a nested fashion.
If you really need all the routes you've defined (including the non-nested rentals and reservations index) then you will need to add:
map.resources :rentals, :only => [:index]
map.resources :reservations, :only => [:index]
And I don't know of a DRYer way to do that.
Nests the two resources under users:
map.resources :users, :shallow => true do |users|
users.resources :reservations, :only => :index
users.resources :rentals, :only => :index
end
Edit: Sorry, forgot the :shallow option.
You can define nested routes with blocks
map.resources :users, :shallow => true do |user|
user.resources :reservations, :only => [:index]
user.resources :rentals, :only => [:index]
end
I feel that this way is a bit more clear and can more easily be adjusted later when you need additional options on one of the nested resources.
The different options and the details are at the ActionController Resources API page
This is an excerpt from my config/routes.rb file:
resources :accounts do |account|
account.resource :profile, :except => [:new, :create, :destroy]
account.resources :posts,
:collection => { :fragment => :get },
:has_many => [:comments, :likes]
# even more code
end
I would like that each nested resource to be loaded from from the account namespace such as Account::PostsController instead of PostsController.
Using resources :accounts, :namespace => 'account' tries to load AccountPostsController.
Trying to nest the structure doesn't really work all that well:
map.namespace :account do |account|
..
end
The previous code will load the files from the locations I want, however it does add the namespace to the url and the generated paths so I'll have methods such as account_account_posts_url and similar paths.
Another alternative is to use something like:
account.resource :profile, :controller => 'account/profile'
I really don't like this as it involves both code duplication and forces me to remove some of the rails magic helpers.
Any thoughts and suggestions?
Changing my routes.rb and running rake routes I came up with the following:
map.resources :accounts do |accounts|
accounts.namespace :account do |account|
account.resource :profile, :except => [:new, :create, :destroy]
end
end
This gets you what you want. The correct url and pointing to account/... controller.
See Rails Routing for more detailed info and options on what can be done with Rails Routes.
So what's specifically wrong with namespacing? I think this is what you're trying to do:
map.namespace :account do |account|
account.resource :profile
end
This will try to load the controller at app/controllers/account/profiles_controller.rb and will generate routes such as account_profile_path.
Updated based on comment:
map.resources :accounts do |account|
account.resource :profile
end
Will give you /accounts/22/profile.