25

I want a link to update a resource, without using an HTML form.

Routes:

resources :users do
  resources :friends
end    

Rake routes:

 user_friend GET /users/:user_id/friends/:id(.:format){:action=>"show", :controller=>"friends"}
             PUT /users/:user_id/friends/:id(.:format){:action=>"update", :controller=>"friends"}

I want to use the put to update a friend by a simple link, something like this:

<%= link_to "Add as friend", user_friend_path(current_user, :method=>'put') %>

But when I click the link, it tries to go into the show action.

What is the right way to do this?

Andrew
  • 227,796
  • 193
  • 515
  • 708
Joe
  • 1,747
  • 3
  • 17
  • 24
  • 1
    Have you tried adding action parameter? <%=link_to "Add as friend", user_friend_path(current_user, :method=>'put, :action => :update')%> And why do you need put method if you don't pass any update parameters? – Tadas T Jan 20 '11 at 20:07

3 Answers3

39
link_to "Add as friend", user_friend_path(current_user, @friend), :method=> :put

Will insert a link with attribute 'data-method' set to 'put', which will in turn be picked up by the rails javascript and turned into a form behind the scenes... I guess that's what you want.

You should consider using :post, since you are creating a new link between the two users, not updating it, it seems.

Jeppe Liisberg
  • 3,734
  • 3
  • 25
  • 24
  • I don't have the object @friend in that view, I just have its id, it doesen't work. – Joe Jan 20 '11 at 20:18
  • I solved for what about friend but it still doesen't work : Writing down your code it reports me a routing error: No route matches {:action=>"show", :controller=>"friends", :user_id=># – Joe Jan 20 '11 at 20:21
  • are you using rails 3? I just tried it out in one of my own projects using jquery and jquery-rails and it worked. Try :put as a symbol instead of a string (my mistake). – Jeppe Liisberg Jan 20 '11 at 20:30
  • 1
    Yes I'm using rails 3, but it still doesn't work. I changed put to symbol but the result is the same: It still try to access the show action (get) ... very very strange – Joe Jan 20 '11 at 20:39
  • Another question: Why do I have to pass current_user and friend variable ? is it possible to pass just the current_user and the id of a friend ? – Joe Jan 20 '11 at 20:41
  • Yes, you can either give an integer or an instance of a model to the route helper methods (as user_friend_path) – Jeppe Liisberg Jan 20 '11 at 21:39
  • When i write the link to, the html generated looks like this: Add as friend. For this to work, the rails.js should be loaded, and dynamically change the link into a form. can you see if the javascript is loaded and running? – Jeppe Liisberg Jan 20 '11 at 21:40
  • have you got javascript_include_tag :defaults in your layout? – Jeppe Liisberg Jan 20 '11 at 21:43
  • My javascript tags was <%= javascript_include_tag 'jquery-1.4.2.min', 'rails', 'application' %>, now I added <%= javascript_include_tag :defaults %>, but the result it's the same, it still looking for the show... I paste my link_to again: <%=link_to "Add as friend", user_friend_path(current_user, @u), :method=>:put %> – Joe Jan 20 '11 at 22:03
  • Is it possible that the problem arise because the page where I put the link, is outside all the models ? (in the root localhost:3000/users_list ) ? – Joe Jan 20 '11 at 22:05
  • Error in the error: It even give me the same error if I just write <%=link_to "Add as friend", user_friend_path %> No route matches {:action=>"show", :controller=>"friends"}, It can helps to understand that the origin of the problem is another – Joe Jan 20 '11 at 22:09
  • SOLVED : Silly error: the second parameter in my link was @u a variable that doesen't exists, I didn't paid too much attention becase the error was no route match. Now I fill the right parameter (u without @) and it works perfectly. Thank you for the advice ! – Joe Jan 20 '11 at 22:26
  • 1
    Starting with rails 4, you can use `method: "patch"` instead of `method: "put"`. Both will work, but `"patch"` is recommended. – Jared Beck Sep 24 '15 at 23:03
3

The problem is that you're specifying the method as a URL query param instead of as an option to the link_to method.

Here's one way that you can achieve what you're looking for:

<%= link_to "Add as friend", user_friend_path(current_user, friend), method: 'put' %>
# or more simply:
<%= link_to "Add as friend", [current_user, friend], method: 'put' %>

Another way of using the link_to helper to update model attributes is by passing query params. For example:

<%= link_to "Accept friend request", friend_request_path(friend_request, friend_request: { status: 'accepted' }), method: 'patch' %>
# or more simply:
<%= link_to "Accept friend request", [friend_request, { friend_request: { status: 'accepted' }}], method: 'patch' %>

That would make a request like this:

Started PATCH "/friend_requests/123?friend_request%5Bstatus%5D=accepted"
Processing by FriendRequestsController#update as 
  Parameters: {"friend_request"=>{"status"=>"accepted"}, "id"=>"123"}

Which you could handle in a controller action like this:

def update
  @friend_request = current_user.friend_requests.find(params[:id])
  @friend_request.update(params.require(:friend_request).permit(:status))
  redirect_to friend_requests_path
end
Andrew
  • 227,796
  • 193
  • 515
  • 708
0

In rails 7, this worked nicely for me:

<% if page.published? %>
  <%= button_to 'Unpublish', page_path(page: { status: "draft" }), { method: :patch, form: { data: { turbo: true } } } %>  
<% else %>
  <%= button_to 'Publish', page_path(page: { status: "published" }), { method: :patch, form: { data: { turbo: true } } } %> 
<% end %>

Note: you may be able to simplify it further by removing form: { data: { turbo: true } } - I only include that because I had turbo turned off by default across my app, but most people probably won't, so you could remove it.

stevec
  • 41,291
  • 27
  • 223
  • 311