I have my routes set up as
scope "/admin" do
resources :profiles
end
So I am getting the expected routes with /admin/profiles. I want to exclude the show action from having this prefix. Is there an easy way to do this? Every solution I saw in the docs was around nested resources, I'm sure I overlooked something though. Thanks!
I think
scope "/admin", do
resources :profiles, except: :show
end
is what you need.
see more at http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
Related
Is there a way to use resource routing instead of writing the routes one by one if my methods for which the default expects parameters don't use parameters?
For example, if I had a routes file like below, the expected path for the update method would be like this: /cats/:id (docs)
# routes.rb
Rails.application.routes.draw do
resources :cats, only: [:create, :update]
end
However, I don't require any params for my update method, meaning the path should be /cats.
I know there's a way to rename the params and not use :id, but I didn't find anything on disabling them. I tried adding param: nil to the end of the line but it didn't work.
As I wrote initially, I know this can be done if I write the routes one by one like below. My question is whether I can use resources to do it. Thank you!
# routes.rb
Rails.application.routes.draw do
post 'cats', to: 'cats#create'
put 'cats', to: 'cats#update'
end
This is exactly the use case for singular resources. Quote from the Rails Guides:
Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like /profile to always show the profile of the currently logged in user.
Change our routing to
resource :cats, only: [:create, :update]
And the following routes will be created:
cats PATCH /cats(.:format) cats#update
PUT /cats(.:format) cats#update
POST /cats(.:format) cats#create
As far as I know, there is not, resource is just a helper to create the standard verb-based CRUD routes, if you want custom routes you need to define your update route the way you did in your second example, of course, you can still use resource for your create route and just pass only: :create.
I am trying to place my tasks into my dashboard/admin routes, for example rather than todos/, todos/new, etc. I would like dashboard/todos/, dashboard/todos/new etc. etc.
I have tried to do that here like so;
namespace :dashboard do
resources :todos
end
Though this also changes the controller, which I don't want - I only want to nest the todos inside of the dashboard controller
Can anyone point me in the right direction please?
You can use scope or path as described in the Rails Guides
scope '/dashboard' do
resources :todos
end
or
resources :todos, path: '/dashboard/todos'
This will generate the routes with the path /dashboard/todos which maps to todos_controller
If you want to route /admin/todos to TodosController you can use scopeinstead of namespace:
scope '/admin' do
resources :todos
end
You could check the rails documentations about this point : http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing
I am playing with Rails 4 in a test application. I have an arbitrary URL that isn't standard like a resources :foo type URL. Ideally the end result I'd like is to be able to go to:
/contests/:id/enter
In views, it would be great if I can then set a link using a named helper such as:
edit_contests_enter(:id)?
What would be the best way to define the route above so I can use the helper path with an arbitrary URL like the one above? It doesn't necessarily have to be edit_contests_enter(:id) but as long as the helper path leads to the URL as suggested above, that would be fantastic.
I assume that your contest is a resource, and when your visitor goes to /contests/:id/enter you want them to create an object user <=> contest. Let's call it participation.
Now participation is exactly like any other resource in your Rails app, so you'd have a routes.rb file looking like
resources :contests do
resources :participations
end
You don't want people to do anything other than create a participation, like edit or destroy them. And perhaps you want a nice URI like /contests/:id/enter. All you have to do is
resources :contests do
resources :participations, :only => [:new, :create]
get "enter" => "participations#new"
end
Doing such will give you a routes helper named contest_enter. In your participations#new form, you'll POST as usual to /contests/:id/participations.
If you have a resources block for :contests, you could just define a new "member" route on the ContestsController using:
resources :contests do
member do
get :enter
end
end
And that would automatically generate you a named member route, the name of which you could find by running rake routes.
So far I have my routes like this: ( out of learning purposes I am curious to get it working with nested resources technique, but if you think this will get too complicated please feel free to suggest any other way of routing technique too)
resources :management, only: [:show] do
resources :report, only: [:show], controller: 'report' do
member do
# hmm what to write in here?!
end
end
end
my GOAL is to have a URL like this:
/managment/SOME_ID_WE_PASS_/report
/managment/1/report
But still can't figure out how exactly to write that route? Can you please take a look?
You don't need nested resources.
resources :crowd_management, only: [:show] do
get :exec_report, on: :member
end
That will produce:
/crowd_management/:id mapped to CrowdManagementController#show
/crowd_management/:id/exec_report mapped to CrowdManagementController#exec_report
The helper methods will be:
crowd_management_path
exec_report_crowd_management_path
You can run rake routes for a detailed list of all your routes.
I have a pretty common case for nested routes, I feel like, that looks something like this (in some sort of pseudonotation):
'/:username/photos' => Show photos for User.find_by_username
'/photos' => Show photos for User.all
In a nutshell: I have users. They have photos. I want to be able to show their photos on their page. I also want to be able to show all photos, regardless of the user. I'd like to keep my routes RESTful and using the built-in resource methods feels like the right way to do it.
Option 1 for doing this is to have PhotosController#index use a conditional to check which params are given and get the list of photos and set the view (different for a user's photos than for all photos). It's even easy to route it:
resources :photos, :only => [:index]
scope ':/username' do
resources :photos
end
Boom. It'd seem like Rails was setup for this. After the routes, though, things get more complicated. That conditional back in the PhotosController#index action is just getting more and more bloated and is doing an awful lot of delgation. As the application grows and so do the number of ways I want to show photos, it is only going to get worse.
Option 2 might be to have a User::PhotosController to handle user photos, and a PhotosController to handle showing all photos.
resources :photos, :only => [:index]
namespace :user, :path => '/:username' do
resources :photos
end
That generates the following routes:
photos GET /photos(.:format) {:action=>"index", :controller=>"photos"}
user_photos GET /:username/photos(.:format) {:action=>"index", :controller=>"user/photos"}
POST /:username/photos(.:format) {:action=>"create", :controller=>"user/photos"}
new_user_photo GET /:username/photos/new(.:format) {:action=>"new", :controller=>"user/photos"}
edit_user_photo GET /:username/photos/:id/edit(.:format) {:action=>"edit", :controller=>"user/photos"}
user_photo GET /:username/photos/:id(.:format) {:action=>"show", :controller=>"user/photos"}
PUT /:username/photos/:id(.:format) {:action=>"update", :controller=>"user/photos"}
DELETE /:username/photos/:id(.:format) {:action=>"destroy", :controller=>"user/photos"}
This works pretty well, I think, but everything is under a User module and I feel like that might end up causing problems when I integrate it with other things.
Questions
Does anybody have experience with something like this?
Can anybody share a better way of handling this?
Any additional pros and cons to consider with either of these options?
Update: I've gone ahead implementing Option 2 because it feels cleaner allowing Rails' logic to work rather than overriding it. So far things are going well, but I also needed to rename my namespace to :users and add an :as => :user to keep it from clashing with my User model. I've also overridden the to_param method on the User model to return the username. Path helpers still work this way, too.
I'd still appreciate feedback on this method. Am I doing things the expected way, or am I misusing this functionality?
Have you considered using a shallow nested route in this case?
Shallow Route Nesting
At times, nested resources can produce cumbersome URLs. A solution to this
is to use shallow route nesting:
resources :products, :shallow => true do
resources :reviews
end
This will enable the recognition of the following routes:
/products/1 => product_path(1)
/products/1/reviews => product_reviews_index_path(1)
/reviews/2 => reviews_path(2)
The best way to do this depends on the application, but in my case it is certainly Option B. Using namespaced routes I'm able to use a module to keep different concerns separated out into different controllers in a very clean way. I'm also using a namespace-specific controller to add shared functionality to all controllers in a particular namespace (adding, for example, a before_filter to check for authentication and permission for all resources in the namespace).
I did something similar to this in one of my apps. You're on the right track. What I did was declare nested resources, and build the query using the flexible arel-based syntax of Active Record in Rails 3. In your case it might look something like this:
# config/routes.rb
resources :photos, :only => :index
resources :users do
resources :photos
end
# app/controllers/photos_controller.rb
def index
#photos = Photo.scoped
#photos = #photos.by_user(params[:user_id]) if params[:user_id]
# ...
end
You could define a seperate route for getting the photos for one user like so:
get '(:username)/photos', :to => 'photos#index'
But I would advise just using the nested resource that Jimmy posted above since that is the most flexible solution.
Example::Application.routes.draw do
resources :accounts, :path => '' do
resources :projects, :path => '', :except => [:index]
end
end
Got the example from:
http://jasoncodes.com/posts/rails-3-nested-resource-slugs
Just applied that in my current project.