rails link_to using get instead of post - ruby-on-rails

I'm making a website for a class and I'm trying to implement a friend request function with a model called 'Users' and a join model called 'Relationships'. I have a button on the user#show page that should add a friend by using the create method in the Relationships controller. Here is the code for the button:
<%= link_to "Add as Friend", relationships_path(:friend_id => #user), method: :post %>
When I press the link, however, it tries to access the index method instead. After looking in the console, it looks like the link is sending a GET request, which routes to the index method, instead of a POST request, which routes to the create method. Can someone explain why this error is occurring and how I can fix it?
Edit: As requested, here is what I have in my routes:
Rails.application.routes.draw do
resources :interests
get 'interests/create'
get 'interests/destroy'
get 'home/index'
get 'sessions/create'
get 'sessions/destroy'
resources :users
resources :relationships
resources :subscriptions
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
root 'home#index'
get "/auth/:provider/callback" => "sessions#create"
get "/signout" => "sessions#destroy", :as => :signout

Using a link_to helper indicates to Rails that you'd like to produce an a tag in your HTML. No element of the HTML specification regarding a tags allows for producing POST requests. Because Rails understands the utility of allowing for POST and DELETE requests to be issued using links, however, it provides those options in the link_to helper. It's implementation, though, must use JavaScript under the hood in order to appropriately function.
Check that jquery-ujs is installed, and that your asset pipeline is working correctly in order to use the helper in this way.
You may also evaluate whether using a form_for and a button is better, since that will automatically POST.

I'm pretty sure you are matching the wrong route. Run rake routes and see the route that links to the Relationships#create.

Using 'url' instead of 'path' with the route helper solved the problem for me. So instead of 'relationships_path' use 'relationships_url'.

Related

Rails routes.rb unexpected behaviour

Editing my Rails 4 app routes.rb file and I'm getting unexpected behaviour (unexpected form my point of view anyway).
I'm trying to create a link that updates a booking record. I have created an action in my BookingsController called WITHDRAW ready to handle the update process. I would like the link to pass the booking id and my code for the link is this:
<%= link_to "Withdraw this booking", bookings_withdraw_path(#booking), :confirm => "Are you sure you want to withdraw this booking?", :method => :patch %>
My problem arises when I try and setup the route for this link. If I add the following line to my routes file:
match 'bookings/withdraw/:bid' => 'bookings#withdraw', via: 'patch'
then when I run the rake command to check the routes it shows this:
bookings_withdrawn GET /bookings/withdrawn(.:format) bookings#withdrawn
PATCH /bookings/withdraw/:bid(.:format) bookings#withdraw
As you can see, the WITHDRAW path is part of the one above (WITHDRAWN is a different path by the way). If I remove the /:bid part from the path then it creates it's own path which is what I would expect.
Can someone explain why this is happening?
try this out
in you routes file pass a block to resources :bookings like this
resources :bookings do
member do
patch :withdraw
end
end
and remove this
match 'bookings/withdraw/:bid' => 'bookings#withdraw', via: 'patch'
As I've written in comment, you should add :as option to your route, i.e.:
match 'bookings/withdraw/:bid' => 'bookings#withdraw', via: 'patch', as: 'bookings_withdraw'
Named route probably wasn't autogenerated because of dynamic part :bid, AFAIK Rails aren't generating implicitly named routes in such cases, so you have to add them explicitly, but I still can't find it in an docs, maybe if somebody've got and can share so I'll update my answer.

Rails always routes an action to show action, and the action it self becomes the id

There's a strange behavior in rails I found recently related to routes and actions, specifically, it's on rails 2.3.5. I have a controller, let's call it Users. In the routes, I declare Users as a resources.
map.resources :users
And within the controller, I have the standard action: index, show, edit, update & destroy. Also, I added other action to fullfil certain requirements.
def generated_pdf_report
# do something
end
The problem is, when I go to page /users/generated_pdf_report, I get this on the console:
Processing UsersController#show (some timestamps) [GET]
Parameters: {"action"=>"show", "id"=>"generated_pdf_report", "controller"=>"users"}
As you can see, the server route the request to method show rather than to method generated_pdf_report. What's interesting, is that I have other controllers having similar action and is working fine.
The solution to the above problem is easy enough, make sure the added feed is above the resources:
map.feed 'users/generated_pdf_report', :controller => 'users', :action => 'generated_pdf_report'
map.resources :users
My question is: Anyone knows why rails behaves like that? The above solution is kind of sloppy, what do you think the best practices for such problem like one mentioned above.
As outlined in the Rails 2 routing guide, you can add collection routes like so:
map.resources :users, :collection => { :generated_pdf_report => :get }
When rails looks at
/users/generate_report
That is exactly the path it would use to show a user whose id was generate_report, so that is what it does, assuming you haven't told it otherwise.
A shorter alternative to what you wrote is
resources :users, :collection => {:generate_report => :get}
Which tells rails to map a GET to /users/generate_report to your generate_report action

Rails 3 Finding the right :id in a controller using a specific route

I have my routes arranged so that when visiting the site the :id is displayed before the slug like so
match "/causes/:id/:slug" => "causes#show", :as => :cause, :via => 'get'
But I also have a nested attribute called "post" that belongs to causes like so
match "/causes/:id/:slug/posts" => "causes#posts", :via => 'get', :as => :posts
When I use this, everything works great for the causes, but not for the posts.
If I use
#post = Post.find(params[:id])
in causes or posts controller it always looks for the ID of the causes, and not the :id of the posts. So if the post :id is 9, and the cause :id is 1, and I use
#post = Post.find(params[:id])
it will always look for post[1] and not 9 or whatever the post id really is.
What am I doing wrong? Is there a way to make this work in the routes, or maybe a different way to find the id of a nested object in the controller?
I need the route to be the way I have it set up, :id/:slug...
rake routes information:
cause GET /causes/:id/:slug(.:format) causes#show
edit_cause GET /causes/:id/:slug/edit(.:format) causes#edit
PUT /causes/:id/:slug(.:format) causes#update
posts GET /causes/:id/:slug/posts(.:format) causes#posts
POST /causes/:id/:slug/posts(.:format)
PUT /causes/:id/:slug/posts(.:format) causes#update_post
DELETE /causes/:id/:slug/posts(.:format) causes#destroy_post
causes GET /causes(.:format) causes#index
POST /causes(.:format) causes#create
Any help would be great.
To solve your immediate problem, you'll want to add something like this to routes.rb
# config/routes.rb
match "/causes/:cause_id/:slug/post/:id" => "causes#update_post", :via => 'put', :as => :update_post
And then you can generate the URL in your views like this...
link_to 'Update this post', update_post_path(#cause, #post)
...and access the parameters in your controller as params[:id] (for the post) and params[:cause_id] (for the cause).
More generally, though, the way you are specifying your routes is pretty cumbersome, and I suspect you're making your life harder than it needs to be. If this were me, I would do something like
# config/routes.rb
resources :causes do
resources :posts
end
This would accomplish something pretty close to what you have now, the main difference being that it wouldn't contain slugs. I'm not sure why you need to have both slugs and IDs, maybe you could just identify your causes by their slugs? Stringex is a good gem for generating slugs, and you can set it so that slugs are guaranteed to be unique.
Here is the section of the Rails guide on nested resources
http://guides.rubyonrails.org/routing.html#nested-resources
And here is a Railscast about using slugs with nested resources
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=comments
Hope this helps.
This is because you're using the id of the cause, and if you're doing /causes/:id/posts shouldn't you be doing #posts = #cause.postsanyway?
I would look into the new router syntax for rails 3 if I were you, as there is a nicer way to nest resources http://guides.rubyonrails.org/routing.html
edit:
use the friendly_id gem and nest your resources, to avoid confusion follow REST best practises that resource in question is at the end so
/causes/:slug/posts/:slug

Rails 3 - Nested Resources Routing

In my application I have users, and then each user has one mailbox where they're delivered messages. My routes.rb looks something like:
resources :users do
resources :mailboxes
end
If I do a rake route, I see this route available to me:
user_mailbox GET /users/:user_id/mailboxes/:id(.:format) {:action=>"show", :controller=>"mailboxes"}
I wanted to link to this path in my application layout, in a sort of toolbar the user finds at the top of the screen.
My view code is:
<%= link_to image_tag("mail_icon.png", :id => 'mail_notice'), user_mailbox_path(current_user)%>
The problem I'm having is that I get a routing error for this path if I'm nothing withing users/* - So anywhere else in my application besides the resource my mailbox is nested under. If I'm on, lets say my user's index page, the path does work without issue.
No route matches {:action=>"show", :controller=>"mailboxes",
Is there something I could be missing with this route? Anything related to users works, it's just the mailbox that I'm having issues with.
Thanks
It sounds like mailbox should be a singleton resource.
resources :users do
resource :mailbox
end
Otherwise it would expect that a user has multiple mailboxes and you'd have to provide the mailbox_id to user_mailbox_path as well.
user_mailbox_path(current_user, #mailbox)
As you can see from the route:
user_mailbox GET /users/:user_id/mailboxes/:id(.:format)
you need to provide two ids, the :user_id and the :id of the mailbox. This makes sense if the user can have several mailboxes.
<%= link_to image_tag("mail_icon.png", :id => 'mail_notice'),
user_mailbox_path(current_user, current_user.mailboxes.first) %>
If you intend the user to have only one mailbox, then I would change the routes.rb like this:
resources :users do
get :mailbox, :on => :member
end
and you would get a route like:
mailbox_user GET /users/:id/mailbox(.:format)
which would be handled by the mailbox method on UsersController, and you can get the path to it in your views with mailbox_user_path(current_user).

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