Submit a form to a Rails route with a dynamic segment - ruby-on-rails

I have a route that looks like
match 'solar_systems/:planet_num/:moon_num' => 'solar_system#moon', :as => :moon
I'd like to have a form with a select box for planet number and moon number and have it submit to this route. However I cannot use moon_path because it will have an error if the dynamic parameters are not included in it like this moon_path(4, 1). Is what I want even possible? If so, what do I give to the form tag for the route?

You don't have to use the routing helper methods, and here you can't since at the time of rendering your form you do not know the required parameters. You do, however, know the controller and action, which is really all that's needed for the destination URL. So this should work:
= form_tag('/solar_systems/moon') do
= select_tag(:planet_num, ...
= select_tag(:moon_num, ...
This should render the form tag. To process the request, you will also have to add another route so the right controller action is called:
match 'solar_systems#moon' => 'solar_system#moon', :via => :post
Or, if it makes more sense in the context of your application, you could modify your existing route to make the parameters optional:
match 'solar_systems(/:planet_num(/:moon_num')) => 'solar_system#moon', :as => :moon
See this Rails guide for more details on non-resourceful routes.

If you use this params on controller you need to specified what params is each one, btw in you helper you need to do something like this
moon_path(planet_moon: 4, moon_num: 1)
Cheers!

Related

How does this rails route match any incoming action to it's correlated method on the controller?

I have a Rails route defined like this:
match '/test_report(/:action)' => 'test_report#index', via: :all
I am not an expert on Rails routing, but using context clues I would have expected that this route to map any request like /test_report/some_action or /test_report/other_action to the index method on the TestReportController, because of the part of the route definition after the hash rocket: => 'test_report#index'.
However, this is not the behavior. Instead, I can create another method on the TestReportController called update_report, and then I can POST to /test_report/update_report to trigger the update_report method. From the route definition I'm using, I wouldn't expect this to work, but it does. I would have expected the POST to hit the index method on the controller.
Note: Just so we're clear, I do understand that the (/:action) part of the route marks it as an optional part of the URL, and the :action symbol is special here and is interpreted as an action's name.
TL;DR:
If the => 'test_report#index' in the above route doesn't map all requests to the index method on the controller, what does it actually do?
As you probably know, whatever parameters you define within the route pattern become available in the params hash in the controller.
So in your example, :action becomes available within the controller as params[:action], which is also used internally by Rails to load the correct action. (If you inspect, you'll see params[:route], params[:controller], params[:action], etc.)
I'm guessing that defining your own :action in the URL pattern like that causes Rails to prefer that over what's in your mapping (skipping the index in test_report#index).
If you want to live in both worlds, you'll probably want to name it something other than :action.

Understanding what's going on with : and # in ruby, rails routes

In the answer to this question about routes in Devise: Devise & Custom Rails User URLs
There is a line of code:
match '/:user' => "users#show", :as => :user_profile
That apparently works for the question asker, but not for me. I end up with
NoMethodError in UsersController#show
undefined method `books' for nil:NilClass
when I go to localhost:3000/username instead of localhost:3000/user/username. I assume because the match line above isn't working correctly and that url does not refer to any user, according to my routes file.
The second url routes me to the user's show page, but I don't want the extra /user in the url.
So I'm trying to figure out exactly what '/:user', :as, and :user_profile mean because I think I'm supposed to substitute a few things here specific to my app. I think :as is some kind of aliased method. I can't find anything in the Devise documentation about a route called user_profile. And I don't know what '/:user' is referring to. An instance of the User object? A user attribute/unique column in my database that I use to refer to specific users? (I use permalink for my user-defined urls).
The route is working for you. Thats why ur getting error from users_controller#show.
In your show action you must be doing something like User.where(:id => params[:id]). But in this case, the attribute in your params is called :user . So to make make both routes work, without any change in the show action, change the route to
match '/:id' => "users#show", :as => :user_profile
Devise documentation won't refer to a 'user_profile' because it is a custom route being used to help address the issue that the questioner (in the linked question) was asking.
match '/:user' => "users#show" means "match any route with a single parameter after / that doesn't match a previously defined route, pair this route to the UsersController 'show' action (passing along the singe parameter as 'user')"
Modifying a route using :as => :anything will provide several helper methods to refer to this route that may be used in controllers, views, and mailers (in this case anything_path and anything_url).
As far as why this won't work for you, this is likely do to a problem with this entry in regard to the rest of your routes or because of your controller action itself. Posting these can help someone track down the exact reason...

Adding a route to match a specific pattern

I have a controller in Ruby on Rails and I would like to do the following:
When a user is trying to access the controller I want to match some parameters. For example
domain.com/hello/19213/sayHello
I want to translate this to:
domain.com/hello/:id/:method
in my routes files.
Keep in mind that :method parameter might not exist but :id will always be there.
In addition if it is possible I would like to match the specific :method with a method in my controller. If not I plan to use a switch case.
Can someone provide an example for this and what I have to put in my routes.rb?
I found this:
match ':controller(/:action(/:id(.:format)))'
But I believe that this is somehow different as I only want to match router for the specific controller not every controller in my project.
Thanks
By method, I assume you mean a method you have in your model. If that is the case, I believe you want something like this in your routes.rb
match ':controller/:id(/:method)'
The parentheses around :method mean that it is optional.
If you do not include a method, it will evaluate your SHOW action with params[:id] = :id
If you do include a method, it will evaluate the :method with params[:id] = :id
This is for methods you have defined in your controller

I want the following urls pattern, please help I'm using rails 3

I want the following urls for my UserController:
localhost/user/join
localhost/user/login
localhost/user/user_name (this can be any name in here, it should fire the 'profile' action)
Then within the /user/user_name_here/ folder I want:
/user/user_name/blah1/
/user/user_name/blah2/
/user/user_name/blah3/
It seems doing resources :user only creates things for index/show/get, so I'm confused as to how to do this other than creating so many match '/user/join' etc. lines in routes.
match "user/:user_name" => "users#show"
then /user/username will redirect to the User controller, call the show method, and pass the :user_name param
you could do the same to other actions that doesn't neet parameters,
match '/user/login' => "sessions#new"
match '/user/join' => "user#new"
Yup - 'resources :user' is just scaffolding for the usual CRUD methods. If you want paths additional to those, you're going to have to create routes (it's the only way your app knows how to route a given URL to a given controller and method).
The friendly_id gem does something similar to what you're suggesting (though I believe it's monkey-patching the .find method on ActiveRecords classes rather than handling routing specifically).

rails routing problem

I have some RESTful controllers and have added a custom method to application_controller.
I have not changed anything in the routes to indicate this new method. The method is poll_memos. I have entered the following URL:
/groups/1234/poll_memos
I get the following error:
Unknown action
No action responded to 1234. Actions: create, destroy, edit, index, new, poll_memos, show, and update
Two questions: Since I didn't modify routes how does rails know about poll_memos? Second, since it seems to know about it, why is it not working?
I don't think thats a restful route that rails automatically generates. This means you'll need to add it yourself.
Look at this question and this one.
And its in the actions because its in the controller, the error message is just printing all actions.
The correct url is /groups/poll_memos/1234. In your example rails thinks that you're trying to call controller method named "1234", which is absent, of course.
Rails knows about poll_memos because the code that prints the error message looks at controller code, not to the routing. You may set routes up in such a way that it will say that there is poll_memos method, but you're unable to access it via URL.
This is because you are most likely triggering the default route:
map.connect ':controller/:action/:id'
Your URL
/groups/1234/poll_memos
would map as follows:
{:controller => "groups", :action => "1234", :id => "poll_memos"}
Also, as you are using a restful style you need to configure the route. To get the poll memos working on the items in the collection you'll need to modify your routes to map as follows:
map.resources :groups, :member => {:poll_memos => :get}

Resources