Rails routing issue - ruby-on-rails

Within a rails app I've got a special url (/profile) that I'm mapping to the user controller to allow a user to view and edit their profile. I made the following entries into my route file so that the "get" for profile will route me to the profile action in the user controller and the "post" for profile will route to the update_profile action in the user controller.
match '/profile', :to => 'users#profile', :via => "get"
match '/profile', :to => 'users#update_profile', :via => "post"
If I run rake routes I see the following two entries
profile GET /profile(.:format) {:controller=>"users", ":action=>"profile"}
profile POST /profile(.:format) {:controller=>"users", ":action=>"update_profile"}
If I try hitting the dev url http://localhost:3000/profile it brings up the profile page as expected. If I press the form button it gives me the following error:
Routing Error
No route matches "/profile"
Looking at the generated html on the initial page I see the following form tag, so it seems the action is correctly set.
<form accept-charset="UTF-8" action="/profile" class="edit_user" enctype="multipart/form-data" id="edit_user_1" method="post">
So what am I missing? By looking at the rake routes output, I was assuming this would work as is. Am I thinking about my http verbs incorrectly? Any help would be appreciated.

I see a few problems here.
First, these are actions for a specific user. So the route should probably be 'profile/:id'
Secondly, show and update are automatically generated when you scaffold a resource. What is the benefit of renaming the actions and mapping them to custom URLs? Breaking the auto-generated Rails RESTful routes is often asking for trouble. It can be done, but you should have a good reason for doing it.
Third, your routes look funny to me. There are some quotes where they shouldn't be. Is that how they appear in your console when you run rake routes?

Related

How to restrict the wild card route

get '/:company' => 'organizations#show', as: 'company_home'
I have this route, this is a way so that different companies registered to my application will login. As I have overridden all the devise related things. This is working fine until I have realized that for every route, this is getting applied
When I hit
get 'employee_dashboard' => 'dashboard#show'
The Parameters: {"company"=>"employee_dashboard"} are going to organizations#show
But I want it to hit dashboard#show how to get around with this?
Move the wildcard route after
get 'employee_dashboard' => 'dashboard#show'
or at the end of route file
get '/:company' => 'organizations#show', as: 'company_home'
so this route will be used only if no other route matches

custom route caught by REST update action

I have a Hotel resource in my Rails app. I added a few custom, non-RESTful actions for some additional functionality.
I have the following routes.rb file:
resources :hotels do
post 'sort', on: :collection
post 'update_hotel_settings', on: :collection
end
and here is the output from rake routes:
....
sort_hotels POST /hotels/sort(.:format) hotels#sort
update_hotel_settings POST /hotels/update_hotel_settings(.:format) hotels#update_hotel_settings
hotels GET /hotels(.:format) hotels#index
POST /hotels(.:format) hotels#create
new_hotel GET /hotels/new(.:format) hotels#new
edit_hotel GET /hotels/:id/edit(.:format) hotels#edit
hotel GET /hotels/:id(.:format) hotels#show
PUT /hotels/:id(.:format) hotels#update
DELETE /hotels/:id(.:format) hotels#destroy
The update_hotel_settings action is where some general settings are saved to the DB.
Here is the beggining of the form being sent to that action:
<%= simple_form_for(#store, url: update_hotel_settings_hotels_path, html: {class: 'form-horizontal', id: 'hotel-settings-form'}) do |f| %>
giving:
<form accept-charset="UTF-8" action="/hotels/update_hotel_settings" class="simple_form form-horizontal" id="hotel-settings-form" method="post" novalidate="novalidate">...
However after submitting the form, the POST request is caught by the hotels' REST update action, with an exception about net being able to find hotel with id="update_hotel_settings".
Obviously this is an unwanted result, and I can't seem to find it's cause.
Shouldn't the update action be triggered by PUT/PATCH methods, and not POST? I also tried using another name for the route+action, instead of "update_hotel_settings", with no luck.
What's most annoying is that the sort action, listed right above, works fine! (only difference is the 'sort' action is fired via ajax, but not sure that should matter)
EDIT:
Contrary to what you might think, nested route mappers actually take precedent over the resource's 7 default routes.
EDIT 2: Another Clue, Another Question!
At first I was embarrassed to notice I forgot the method: :post option in the simple_form_for's arguments, and when I added it - Kapow! the form routes to the right action! weird isn't it? especially when there was already a method="post" attribute in the form tag!
WHAT IS GOING ON?
Routes are caught top to bottom. Meaning, if there is a match, there it stops. So, all you have to do is take the update_hotel_settings route out of the resource and before it.
match '/hotels/update_hotel_settings', to: 'hotels#update_hotel_settings', via: 'post', as :update_hotel_settings_hotels
resources :hotels do
[...]

Get "home/index" in Rails project

After running rails generate controller home index in my Rails application, I see this line in routes.rb
get "home/index"
What does this line do? When I removed it, I didn't observe any difference it makes.
see the Rails Routing page for more info but...
It adds, to the routing table, an entry to direct a GET request of the form
http://localhost:3000/home/index
To the HomeController#index action, which will render a response and display the results to the user.
It is a shorthand notation for
match 'home/index' => 'home#index', :via => :get
To see what other routes your application has available, run the following from a terminal while inside your projects directory
rake routes

Rails routes generate Post request for New action in nested resources

I have the following nested resources:
resources :listings do
resources :offers do
member do
put "accept"
put "reject"
end
end
end
In my listings/show.html.haml, I have
= button_to "Make Offer", new_listing_offer_path(#listing)
Now, when I click button, rails generate a POST request, and thus an error:
Started POST "/listings/2/offers/new" for 127.0.0.1
ActionController::RoutingError (No route matches "/listings/2/offers/new"):
If I refresh (GET request), then the page displays correctly.
I believe this incorrect routing only happens when I added two extra actions: accept and reject, which happens to be POST actions.
Is it a bug in Rails, or it is my fault? How should I prevent this error?
Thank you.
The button_to helper creates a form for you which by default will send a POST request to the URL you've specified ("/listings/2/offers/new").
The routing you've specified will not generate a route to handle a POST request to /new. You can inspect your generated routes and the verbs to which they will respond by running the "rake routes" task.
If you are looking to merely link to the form, change your "button_to" to a "link_to" and add CSS for aesthetics.
= link_to "Make Offer", new_listing_offer_path(#listing)
(this GET would route to your OfferController's new action)
If you are looking to actually POST data, you will likely need to change your usage to:
= button_to "Make Offer", listing_offers_path(#listing)
(this POST would route to your OfferController's create action.)

A very basic issue with routes in ruby

I am new to ruby and while creating a sample application found out an issue that whenever I go to http://127.0.0.1:3000/people/index by default show action is executed and index is taken as a parameter. This is server log:
Started GET "/people/index" for
127.0.0.1 at 2010-12-23 18:43:01 +0500 Processing by PeopleController#show as
HTML Parameters: {"id"=>"index"}
I have this in my route file:
root :to => "people#index"
resources :people
match ':controller(/:action(/:id(.:format)))'
What is going on here and how can I fix the issue?
The route
resources :people
creates "sub"-routes
get '/people' => 'people#index'
get '/people/new' => 'people#new'
post '/people' => 'people#create'
get '/people/:id' => 'people#show'
get '/people/:id/edit' => 'people#edit'
put '/people/:id' => 'people#update'
delete '/people/:id' => 'people#destroy'
Actually, all of these sub-routes include (.:format) at the end of the recognized path.
The path /people/index would be recognized by the route /people/:id, mapping to the action #show.
The path /people would be recognized by the route /people, mapping to the action #index.
Use the URL helpers people_path and people_url for the /people route.
To get Rails to travel backward in time to before it espoused REST and to understand /people/index, do this:
resources :people do
get :index => 'people#index'
end
You might want to watch this Railscast episode.
A couple things to keep in mind when working with your routes:
rake routes dumps the map of URLs to your controllers
When providing backwards compatibility, redirect the user to the correct path
I personally have yet to upgrade my app to Rails 3, and I'll be dragging my feet until I really need to do it (just got it out the door not too long ago). In Rails 2.x you had resource routes, but if you kept the default controller/action/id route it would fall through and resolve. It appears that is no longer the case in Rails 3. Essentially your resource routes handle all URLs in that resource namespace (/people in your case).
To provide backwards compatibility, I would add a redirect route to resolve that incompatibility.
match "/people/index", :to => redirect("/people")
The main reason for that is to prevent users from saving an incorrect URL for their personal links--while allowing legacy users to still be able to get where they meant to go.
Edit: New answer, removed pointing out the typo in the question.

Resources