Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #9731 (closed defect: invalid)

Opened 1 year ago

Last modified 1 year ago

Protect from forgery error on AJAX requests

Reported by: revans Assigned to: technoweenie
Priority: normal Milestone: 1.x
Component: ActionPack Version: edge
Severity: normal Keywords: forgery, protect_from_forgery
Cc:

Description

When doing ajax requests (link_to_remote) a Method Not Allowed error will be thrown unless you explicitly declare the type of request. (:method => :get)

Change History

09/29/07 02:54:16 changed by technoweenie

  • owner changed from core to technoweenie.
  • status changed from new to assigned.

That would be because the token is invalid. But, the token should be added to the link_to_remote link:

$ script/console p
Loading production environment (Rails 1.2.3)
>> def helper.protect_against_forgery?() true end
=> nil
>> def helper.request_forgery_protection_token() :authenticity_token end
=> nil
>> def helper.form_authenticity_token() '1234' end
=> nil
>> helper.link_to_remote 'test', :url => '#'
=> "<a href=\"#\" onclick=\"new Ajax.Request('#', {asynchronous:true, evalScripts:true, parameters:'authenticity_token=' + encodeURIComponent('1234')}); return false;\">test</a>"

Is that not working properly?

09/29/07 03:19:17 changed by revans

If you don't define the request method for the link_to_remote helper, you'll get this error:

Processing ApplicationController#index (for 127.0.0.1 at 2007-09-28 20:13:34) [POST]

Session ID: 0252d1a4b298b1f5fdb497d1f93f6230 Parameters: {"month"=>"9", "county"=>"1", "authenticity_token"=>"10cdfd3d9134539a5e63191c16015392473fdf41", "year"=>"2007", "direction"=>"previous"}

ActionController::MethodNotAllowed (Only get, put, and delete requests are allowed.):

/vendor/rails/actionpack/lib/action_controller/routing.rb:1409:in `recognize_path' /vendor/rails/actionpack/lib/action_controller/routing.rb:1394:in `recognize' /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:164:in `handle_request' /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:114:in `dispatch' /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:125:in `dispatch_cgi' /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:9:in `dispatch' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/rails.rb:78:in `process' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/rails.rb:76:in `synchronize' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/rails.rb:76:in `process' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:618:in `process_client' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:617:in `each' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:617:in `process_client' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:736:in `run' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:736:in `initialize' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:736:in `new' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:736:in `run' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:720:in `initialize' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:720:in `new' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:720:in `run' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:271:in `run' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:270:in `each' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:270:in `run' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:127:in `run' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/command.rb:211:in `run' /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:243 /vendor/rails/activesupport/lib/active_support/dependencies.rb:489:in `load' /vendor/rails/activesupport/lib/active_support/dependencies.rb:489:in `load' /vendor/rails/activesupport/lib/active_support/dependencies.rb:342:in `new_constants_in' /vendor/rails/activesupport/lib/active_support/dependencies.rb:489:in `load' /vendor/rails/railties/lib/commands/servers/mongrel.rb:64 /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' /vendor/rails/activesupport/lib/active_support/dependencies.rb:496:in `require' /vendor/rails/activesupport/lib/active_support/dependencies.rb:342:in `new_constants_in' /vendor/rails/activesupport/lib/active_support/dependencies.rb:496:in `require' /vendor/rails/railties/lib/commands/server.rb:39 ./script/server:3:in `require' ./script/server:3

I've tested this with the method set to :get and without the method parameter being set. Both link_to_remote helpers have the same token, but only the one with the defined :method works, while the one without, errors out (above).

Here is the JavaScript of each of the helpers, one with the method defined, one without:

<a onclick="new Ajax.Request('http://localhost:3000/accounts/classic-european-restoration/schedules/change?county=1&direction=previous&month=9&year=2007', {asynchronous:true, evalScripts:true, parameters:'authenticity_token=' + encodeURIComponent('10cdfd3d9134539a5e63191c16015392473fdf41')}); return false;" href="#"><img src="/images/calendar/cal_previous.jpg?1182490748" class="cal_controls" alt="previous"/></a>

September 2007

<a onclick="new Ajax.Request('http://localhost:3000/accounts/classic-european-restoration/schedules/change?county=1&direction=next&month=9&year=2007', {asynchronous:true, evalScripts:true, method:'get', parameters:'authenticity_token=' + encodeURIComponent('10cdfd3d9134539a5e63191c16015392473fdf41')}); return false;" href="#"><img src="/images/calendar/cal_next.jpg?1182490818" class="cal_controls" alt="next"/></a>

09/29/07 03:27:47 changed by revans

My route is defined at:

map.resources :accounts do |accounts|

accounts.resources :schedules, :collection => { :change => :get }

end

When not defining the method in the helper, it does a post instead of the above get request.

09/29/07 17:18:13 changed by technoweenie

  • status changed from assigned to closed.
  • resolution set to invalid.

link_to_remote has always sent post by default. The MethodNotAllowed is raised during route recognition, before it even gets to the csrf filter. If you want to allow POST you need to specify it in the route:

map.resources :accounts do |accounts|
  accounts.resources :schedules, :collection => {:change => :post}
end

If you want both GET/POST, you can use:

map.resources :accounts do |accounts|
  accounts.resources :schedules, :collection => {:change => :any}
end