URL helper for a post route in a resource - ruby-on-rails-3

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.

Related

Rails path helper generate dot or undefined method instead of slash

Route defined as follows
resources :purchases do
collection do
put :wirecardtest
end
end
Controller actions redirect in one of the following manners with associated error generated
format.html { redirect_to wirecardtest_purchase_path(#purchase)
undefined method `wirecardtest_purchase_path'
format.html { redirect_to wirecardtest_purchases_path(#purchase)
/purchases/wirecardtest.44
Behaviour is identical when putting code in view.
The ressource is defined in plural mode, as it ought to be. The redirect, as it is supposed to call a specific ressource should call the singular model-action mode (in plural it would generate the period).
I don't understand how I got into this damned-if-you-do, damned-if-you-don't position.
wirecardtest_purchases PUT /purchases/wirecardtest(.:format) purchases#wirecardtest
That's your mistake right there.. the path is generated as 'wirecardtest_purchases' but you are using 'wirecardtest_purchase' note the missing 's' to pluralize the 'purchase'.
Remember its a collection. So the path method is pluralized by rails.
When in doubt rake routes :)
---Update---
Improving the answer (check comments). Need here is to actually define a route as :member and not a :collection if you want to act upon a single object. Referring to Rails Docs,
resources ::purchases do
member do
get 'wirecardtest'
end
end

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" %>

Passing :new to Rails url_for

Maybe I'm stupid but Rails provides this nifty syntax for generating URL's like so:
url_for([user, comment]) # => /users/1/comment/1
Passing :edit allows me to create something like this:
url_for([:edit, user, comment]) # => /users/1/comment/1/edit
but is there some way to do following?
url_for([:new, user, comments]) # => NoMethodError: undefined method `new_user_comments_url'
UPDATE: Added more information.
My routes.rb:
resources :users do
resources :comments
end
resources :posts do
resources :comments
end
My problem here is, that I can't use Rails auto-generated url helper (user_comments_url), because I'm sharing the views for both user comments and post comments.
There are two workarounds (but no one feels like the "Rails"-way) for my problem:
Adding logic to the view, e.g. some if conditions.
Defining my own url helpers like new_parent_comment(user_or_blog).
Ok, found a solution, but I'm not sure if this is the intended one:
url_for([:new, user, :comment]) # => '/users/1/comments/new'
url_for([:new, post, :comment]) # => '/posts/1/comments/new'
Stuck with the same problem, and found next solution (tested on Rails 5.2):
url_for([user, Comment, action: :new])
where Comment model class name.
By the way, action also could be :edit.
According to the Rails Docs url_for uses the class name of the object passed to generate the RESTful route. It also states that with nested routes it can not make this assumption correctly:
If you have a nested route, such as admin_workshop_path you’ll have to call that explicitly (it’s impossible for url_for to guess that route).
I would suggest using a named route here something like new_user_comment_path(). I am assuming you have set up your routes.rb something like:
resources :users do
resources :comments do
end
end
Additionally you can run rake routes to print out the proper names for all your routes.
Hope this helps,
/Salernost
Could this simply be a typo? I think the last line should read comment, not comments:
url_for([:new, user, comment])
(Assuming your comment variable has been defined.)

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?

Rail3 routes [edit problem]

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'