aquajach
aquajach

Reputation: 2578

Rails's PUT request via link_to becomes POST

In views file, my code is similar with:

<%= link_to refresh_post_user_post_path(@user,@post), :method => :put%>

In routes.rb:

resources :users do
  resources :posts do
    member do
      put :refresh_post
    end
  end
end

The interesting thing is when inspecting the request object in controller:

def refresh_post
  ... ...
  p request.method # => POST
  p request.request_method # => PUT
  ... ...
end

I know method and request method are different, but where's POST request from?

Moreover:

$ rake routes 
refresh_post_user_post_path PUT /users/:user_id/posts/:id/refresh_post, {:action => "refresh_post", :controller => "posts"}

I am with Rails 3.0.11 and Ruby ree-1.8.7, everything above works with no exception. But any body knows how come the request is a POST?

Upvotes: 2

Views: 1017

Answers (2)

aquajach
aquajach

Reputation: 2578

The truth is request.method always returns POST, no matter for a PUT or POST request and no matter the controller method is a default 'update' or a custom one. Sergio, you are right. It is from Rails' doc for request class:

method: Returns the original value of the environment’s REQUEST_METHOD, even if it was overridden by middleware

request_method: Returns the HTTP method that the application should see. In the case where the method was overridden by a middleware (for instance, if a HEAD request was converted to a #GET, or if a _method parameter was used to determine the method the application should use), this method returns the overridden value, not the original.

The interesting thing is even if it is a PUT request, in the log file it says like:

Started POST "/users/251/posts/1234" for 127.0.0.1 at Fri Jan 18 21:48:21 +0800 2012

This happens in Rails 3.0.11, and log file doesn't tell it is a PUT request at all. However in later versions, it has been fixed:

https://github.com/rails/rails/commit/17a91a6ef93008170e50c073d1c3794f038a0a33

And the log becomes as friendly as:

Started PUT "/users/251/posts/1234" for 127.0.0.1 at Fri Jan 18 21:48:21 +0800 2012

Upvotes: 0

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230316

Rails emulates "advanced" request types (PUT, DELETE, etc) with a POST type. This is because browsers typically support only GET and POST.

So rails accepts a POST request and looks for a :method parameter. If such parameter is found, it updates request type accordingly (so that your routes can work, for example).

Upvotes: 3

Related Questions