Rail3 routes [edit problem] - ruby-on-rails-3

Example I have had configured my routes as
match '/cellphones/:permalink/:charger', :controller => 'mycontroller', :action => 'myaction'
resources :cellphones
Everything ok when I put something like this localhost/cellphones/nokia3323/lion but I can't edit a cellphone because have the same structure localhost/cellphones/edit/4

Routes that are defined earlier take precedence, so you could make the edit route accessible again by reversing the order that you've declared your routes in. Since a route of /cellphones/edit/:id is more restrictive than /cellphones/:permalink/:charger, the edit route will match if the second part of the route is "edit" and pass through to your other route if it's something else.
However, you most likely don't actually have a /cellphones/edit/:id route, because what's created by resources :cellphones is /cellphones/:id/edit which is much harder to distinguish from /cellphones/:permalink/:charger since both have the wildcard part of the route as the second segment.
The easiest way the fix the problem would be to change the /cellphones/:permalink/:charger route so it's easier to distinguish. You could use something like /cellphones/p/:permalink/:charger ("p" for permalink), or anything else that's easy to distinguish from the RESTful routes created by resources.
There's a few other ways you could approach it as well, such as using segment contraints or adding more restful actions.

I found the solution, just had to change the order
resources :cellphones
match '/cellphones/:permalink/:charger', :controller => 'mycontroller', :action => 'myaction'

Related

Rails Routing based on Parameters

I am working on a Rails app, and I am looking for a way to route to different actions in the controller based on the existence of parameters in the url.
For example I want website.com/model to route to model#index, however I want website.com/model?opt=dev to route to model#show. Is there some way this can be done?
Use route constraints to look at the request object and see if it has URL parameters. If you're using restful routes, you want to put this "one-off" before the restful route. Something like this:
get 'users' => 'users#show', constraints: { query_string: /.+/ }
resources :users
So what this is saying is that if you request "/users?opt=dev" then it will match your special case. Otherwise, it falls through to your normal restful route to the index action. Your model#show action will then have to know to pick up the param[:opt] and do whatever with it.
Also, note that the regex is very loose and it's simply checking for ANY param...you'll want to tighten that up to fit whatever you're trying to do.
Not strictly the same, but if you came to this post and were wondering how to do the same via a POST, then you can do it based on the request_paramters.
for your routes.rb ..
module MyConstraintName
extend self
def matches?(request)
request.request_parameters["routeFlag"] == "routeToModelShow"
end
end
match "pages/:id", :via=>:post, :controller=>"model", :action=>"show", :constraints => MyConstraintName
and in your form for example..
<%= hidden_field_tag :routeFlag, "routeToModelShow" %>

How do you use :as and match a route correctly?

I don't know what I'm doing wrong. This is my route:
resources :stores do
get '/add_shoes' => 'stores#add_shoes', :as => :add_shoes
end
And my path should be: <%= link_to "Add Shoes", add_shoes_path %>
But it gives the error that the path does not exist. How do I use both of them?
If I recall correctly, because it's nested in a resources block, it's going to append stores to the end. So the correct route is add_shoes_stores_path. Sometimes it also adds an index to the end (not sure why), to give you add_shoes_stores_index_path.
Since it's a get call, you could always put it outside the resources block.
Additionally, the more Rails way to do it would be:
resources :stores do
collection do
get :add_shoes
end
end
You've got a bunch of options here on how you want to handle it. But just a quick tip, you can always type rake routes from the command line to get a list of all available routes and where they point.
If you're looking at doing it this way for your clarity of code, just remember this: Your routes should always mention where they're pointing to. That would be both add_shoes and stores. Having an add_shoes_path could point to literally any controller, as it's not really verbose. I would definitely stick to the Rails way of doing it - it will make more sense as you dive in deeper.
Finally, another thought - If you're adding shoes in the stores model, it would make sense for each store to have shoes. You should probably create a new model for Shoes and use RESTFUL routing.

Rails -- rename restful route

I wanted to know what the easiest way to rename a restful route is. Basically I have a controller called Employees and rather than have employees/new I want employees/hire to be used and achieve the same thing and make employees/new an invalid url.
For your specific need, the guide has exactly this example for new, edit, this should work:
resources :employees, :path_names => { :new => 'hire' }
http://guides.rubyonrails.org/routing.html#overriding-the-new-and-edit-segments
One of the best sources of data on routes is the rails guide:
Rails Guide on Routes, also the command
rake routes
This command will show you all the current routes.
But in answer to this specification question
if you look into your routes file you can create new routes
manually.
match 'employee/hire' => 'Employees#new', :via => :get, :as => 'employee_path'
the first argument matches what the browser is looking for.
The second argument is the controller and method.
The third is if it is a get, put, post, or delete call.
The fourth is the name for the path so you can access with the standard name_path type of call from code.
This makes sense?

URL helper for a post route in a resource

I have a resourceful route, with a post route nested within it:
resources :groups, :only => [:index, :show] do
post 'send_audit_reminder', :on => :member
end
If I run rake routes, this route shows up just fine:
send_audit_reminder_group POST /groups/:id/send_audit_reminder(.:format)
{:controller=>"groups", :action=>"send_audit_reminder"}
However, I can't seem to figure out how to refer to the send_audit_reminder URL for a given route. I've tried send_audit_reminder_group_path(#group) and send_audit_reminder_url(#group), which both give me the following error:
No route matches {:controller=>"groups", :action=>"send_audit_reminder"}
As you can see from rake routes, there is indeed a route that matches those parameters, and there is also a matching method on the controller.
How can I find the path or URL for this route? I would like not to hard code it, since our apps are deployed to subdirectories on the same virtual host, so a hard-coded absolute path won't work.
And where would I look for documentation or information on this in the future? Since these path and URL helper methods are generated from my routes, I obviously can't look for documentation, and while rake routes tells me that the route is there, it doesn't appear to be there when I try and get the URL.
It might be that you're missing the placeholders and it can't route because of that. The following should work based on your definition:
send_audit_reminder_group_path(group)
Any time you see identifiers like :id or :group_id in your route, you must supply them unless they are in brackets, which declares them as optional, as is the case here with :format. The arguments need to be supplied in the same order they are declared. For this:
/example/:user_id/groups/:id
The arguments to this route would be user_id and id and both must be supplied. Generally with routes you can either use a literal number or string, or a model that supports to_param as all ActiveRecord::Base-derived ones do.
This all stems from declaring with :member, meaning it is specific to a particular record, and not :collection where that is omitted. The Rails Routing Guide explains more.

Rails 3 routes: How to avoid conflict with 'show' action?

I currently have the following routes set up for photos:
resources :photos
match 'photos/:user' => 'photos#user', :as => :user_photo
match 'photos/:user/:key' => 'photos#show', :as => :show_photo
Those two match routes give me URLs like:
http://example.com/photos/joe_schmoe
http://example.com/photos/joe_schmoe/123xyz
...similar to the way Flickr formats its URLs.
The problem I'm having, though, is that the photos/:user route is either interpreted as the show method, or if I put those custom routes before the resources then routes like /new get interpreted as the user method.
How can I get around that without having to do a ton of custom routes?
You'll want to put this custom route above the resources :users, so that it is matched first in the routes.
match 'photos/:user' => 'photos#user', :as => :user_photo
resources :photos
Additionally you can disable the show action altogether:
resources :photos, :except => :show
It's not a good idea to mix restful routes with custom match routes on the same resource. As you observed these two routes will intercept each others actions. Your best choice is to pick only one routing system for a resource and stick with it. If you want flickr style routes you should remove the restful route and add the other necessary match routes for new/create/etc you might need. If you desperately want to keep both of these routes You either need to disable show from the rest route with the rest route being on top, or you disable new from the match route while match being on top. You can use regexp to filter out some requests from match like this:
match 'photos/:user' => 'photos#user', :as => :user_photo, :constraints => { :user => /.*[^n][^e][^w].*/ }
This gets ugly really fast tho and I suggest just not using the rest route at all.