From e50abbad4f4141642bf5c4c27ec77852803a3a72 Mon Sep 17 00:00:00 2001
From: David Heinemeier Hansson <david@loudthinking.com>
Date: Wed, 14 Mar 2012 19:28:36 -0400
Subject: Allow you to force the authenticity_token to be rendered even on
 remote forms if you pass true

---
 actionpack/lib/action_view/helpers/form_tag_helper.rb      | 14 +++++++++-----
 .../test/controller/request_forgery_protection_test.rb     | 11 +++++++++++
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 74b6034c8d..4ce878f26a 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -27,7 +27,9 @@ module ActionView
       #   is added to simulate the verb over post.
       # * <tt>:authenticity_token</tt> - Authenticity token to use in the form. Use only if you need to
       #   pass custom authenticity token string, or to not add authenticity_token field at all
-      #   (by passing <tt>false</tt>).
+      #   (by passing <tt>false</tt>). If this is a remote form, the authenticity_token will by default
+      #   not be included as the ajax handler will get it from the meta-tag (but you can force it to be
+      #   rendered anyway in that case by passing <tt>true</tt>).
       # * A list of parameters to feed to the URL the form will be posted to.
       # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
       #   submit behavior. By default this behavior is an ajax submit.
@@ -610,13 +612,15 @@ module ActionView
             html_options["action"]  = url_for(url_for_options)
             html_options["accept-charset"] = "UTF-8"
             
-            if html_options.delete("remote")
-              html_options["data-remote"] = true 
+            html_options["data-remote"] = true if html_options.delete("remote")
 
+            if html_options["data-remote"] && html_options["authenticity_token"] == true
+              # Include the default authenticity_token, which is only generated when its set to nil,
+              # but we needed the true value to override the default of no authenticity_token on data-remote.
+              html_options["authenticity_token"] = nil
+            elsif html_options["data-remote"]
               # The authenticity token is taken from the meta tag in this case
               html_options["authenticity_token"] = false
-            else
-              html_options["authenticity_token"] = html_options.delete("authenticity_token") if html_options.has_key?("authenticity_token")
             end
           end
         end
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index f4e7336834..37b9de350b 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -41,6 +41,10 @@ module RequestForgeryProtectionActions
     render :inline => "<%= form_for(:some_resource, :remote => true ) {} %>"
   end
 
+  def form_for_remote_with_token
+    render :inline => "<%= form_for(:some_resource, :remote => true, :authenticity_token => true ) {} %>"
+  end
+
   def rescue_action(e) raise e end
 end
 
@@ -114,6 +118,13 @@ module RequestForgeryProtectionTests
     assert_no_match /authenticity_token/, response.body
   end
 
+  def test_should_render_form_with_token_tag_if_remote_and_authenticity_token_requested
+    assert_not_blocked do
+      get :form_for_remote_with_token
+    end
+    assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token
+  end
+
   def test_should_allow_get
     assert_not_blocked { get :index }
   end
-- 
cgit v1.2.3