I’ve got a Rails 3 app where instead of the default destruction mapping:
modelname DELETE /modelname/:id modelname#destroy
I would like a dedicated route with a GET ‘fallback’ so that users without Javascript are sent to a confirmation page:
delete_modelname DELETE /modelname/:id/delete modelname#destroy
delete_modelname GET /modelname/:id/delete modelname#confirm_destruction
I can get the above output in rake routes with the following declaration:
resources :modelname, except: [:destroy] do
member {
get 'delete', to: 'confirm_destruction'
delete 'destroy', as: 'delete'
}
end
However, one of the routes does not match, and it seems to be order-dependent, i.e. whichever is defined first then fails to match in testing. I notice that the default ‘overloaded’ routes Rails generates look a bit different in rake routes:
modelnames GET /modelname/:id/delete modelname#index
POST /modelname/:id/delete modelname#create
The route name is not repeated, and a link to create will become a link to index outside a form or a Javascript-enabled request.
It seems I’ve defined two entirely separate routes sharing the same name, rather than overloaded the path as I intended.
What am I missing? Is there any way to get the effect I’m looking for?
Things I’ve tried
Since it appeared to be the route name which was clashing, I tried this:
member {
get 'delete', to: 'confirm_destruction'
delete 'destroy', path: 'delete'
}
Changing as: to path: so that the route name would not be affected, but the paths would match. This works! The following routes are generated:
delete_modelname GET /modelname/:id/delete modelname#confirm_destruction
modelname DELETE /modelname/:id/delete modelname#destroy
This gives the effect I’m after, but unfortunately the modelname DELETE route masks the default modelname PUT route for updates.
Okay, so there is a way to do this, but it’s not quite as elegant as I’d hoped. I’m very open to a better answer if anyone has one.
resources :modelname, except: [:destroy] do
member {
get 'delete', to: 'confirm_destruction'
delete 'destroy', as: 'destroy', path: 'delete'
}
end
It works because these two new routes have unique names for using in views – delete_modelname_path and destroy_modelname_path – but if Javascript is disabled, the destroy_modelname path is still /modelnames/:id/delete, which comes in as a GET request and Rails matches it to the delete_modelname route (i.e. the confirmation page).
Related
I'm using apiResource in Route which is using (index, create, show, update, destroy) methods in exampleController. When I would like to use show method the route wont work. what shall I do? I think it is because of {fruits} but I do not how solve it?
Route::apiResource('/fruit/{fruits}/apples', 'exampleController');
My route in browser is:
localhost:8000/api/fruits/testFruitSlug/apples/testAppleSlug
difference between apiResource and resource in route: Route::apiResource() only creates routes for index, store, show, update and destroy while Route::resource() also adds a create and edit route which don't make sense in an API context.
Already peoples added answers, I am just adding the route differences as visually :
Normal Resource controller
Route::resource('users', 'UsersController');
Gives you these named routes:
Verb Path Action Route Name
GET /users index users.index
GET /users/create create users.create
POST /users store users.store
GET /users/{user} show users.show
GET /users/{user}/edit edit users.edit
PUT|PATCH /users/{user} update users.update
DELETE /users/{user} destroy users.destroy
Api Resource controller
Route::apiResource('users', 'UsersController');
Gives you these named routes:
Verb Path Action Route Name
GET /users index users.index
POST /users store users.store
GET /users/{user} show users.show
PUT|PATCH /users/{user} update users.update
DELETE /users/{user} destroy users.destroy
To quickly generate an API resource controller that does not include the create or edit methods, use the --api switch when executing the make:controller command:
php artisan make:controller API/PhotoController --api
Try using the command line to generate your controller. It will save you stress. You can then do this in your route
Route::apiResource('photos', 'PhotoController');
I solved my question in below way:
public function show(Fruits $fruits, Apples $apples){
}
I found that I should give all variables in my function however I did not use all of them.
I've got some problems with generating routes with polymorphic_url
Here is a part of my route.rb file :
scope path: '/my-account', controller: 'customers/base', as: :customer do
...
resources :addresses, path: 'my-addresses'
...
end
rakes routes | grep addresses give me exactly the route i want :
customer_addresses GET /:locale/my-account/my-addresses(.:format)
Now, if i use
send('customer_addresses_path)
in a link_to, all work fine.
But if i'm not able to generate the same url with polymorphic url :
app.polymorphic_path([:customer,:addresses])
#ActionController::RoutingError: No route matches {:controller=>"addresses"}
app.polymorphic_path([Customer,:addresses])
#"/Customer/my-account/my-addresses" Not the same url :'(
app.polymorphic_path([Customer.first,:addresses])
#"/1/my-account/my-addresses" Not the same url :'(
Is there a way to use polymorphic_url to generate my url?
Asking a question is a good way to reflect on it.
Solution here:
app.polymorphic_path([:customer,:addresses], locale: :en)
I want to match a specific route but not that route with any get query params.
Lets say I have a route like this:
get '/home', to: 'home#home
This works great for /home but how to I 404 /home?foo=bar?
If ?foo=bar makes no sense in your app it will have no effect at all.
Visiting /home?foo=bar will end seeing /home. This is quite a convention. Why do you need 404?
You can do this with an advanced constraint.
http://guides.rubyonrails.org/routing.html#advanced-constraints
class NoQueryParamsConstraint
def matches?(request)
request.query_parameters.blank?
end
end
get "/home", to: 'home#home', constraints: NoQueryParamsConstraint.new
I have two unrelated models, say Person and Building. When the app receives a url like www.mysite.com/JohnDoe/EmpireState I would like to show properties of the Person with the name johnDoe, and the same for the building with the name EmpireState.
I'm confused as to the routing part specifically. I'm unsure if I need to create a pages controller that can return the objects from the database. How should I go about doing this?
Am hoping for something like below?
match ':user_name/:building_name', :controller => pages
If those two are not related, you shouldn't do it that way. If they ARE related, we call that nested resources.
Example:
resources :projecs do
resources :tasks
end
Sample URL: "/projects/12/tasks/1281"
Edit:
If they are NOT related (taken from my comment):
In your BuildingsController you can fetch the parent informations too. If you use the match route in your question, you'll have params[:user_name] AND params[:building_name] available and can fetch anything you want with them...
Building.find_by_name(params[:building_name]) # return all Buildings based on URL param
I have a page_controller with a few actions (dashboard, rules, contact). Each has a corresponding view. I don't know how to route it in Rails 3.
match 'page/:action' => 'page#:action'
The above doesn't work - what I would like is named routes like: page_path(:dashboard) or page_dashboard_path.
Any ideas?
Jacob
You will have to write
get 'page/dashboard'
get 'page/rules'
get 'page/contact'
That will generate the correct named routes.
Note: you can always type rake routes to see which named routes are created.
For more info: see documentation.