aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md2
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb24
-rw-r--r--actionpack/lib/action_view/railtie.rb8
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb50
-rw-r--r--guides/source/configuring.textile2
5 files changed, 76 insertions, 10 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 92efb060a2..de62919c3c 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -128,6 +128,8 @@
## Rails 3.2.3 (unreleased) ##
+* Add `config.action_view.embed_authenticity_token_in_remote_forms` (defaults to true) which allows to set if authenticity token will be included by default in remote forms. If you change it to false, you can still force authenticity token by passing `:authenticity_token => true` in form options *Piotr Sarnacki*
+
* Do not include the authenticity token in forms where remote: true as ajax forms use the meta-tag value *DHH*
* Upgrade rack-cache to 1.2. *José Valim*
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 41d895c15e..be4e88c9b3 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -2,6 +2,7 @@ require 'cgi'
require 'action_view/helpers/tag_helper'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/output_safety'
+require 'active_support/core_ext/module/attribute_accessors'
module ActionView
# = Action View Form Tag Helpers
@@ -17,6 +18,9 @@ module ActionView
include UrlHelper
include TextHelper
+ mattr_accessor :embed_authenticity_token_in_remote_forms
+ self.embed_authenticity_token_in_remote_forms = true
+
# Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
# ActionController::Base#url_for. The method for the form defaults to POST.
#
@@ -27,9 +31,11 @@ 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>). 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>).
+ # (by passing <tt>false</tt>). Remote forms may omit the embedded authenticity token
+ # by setting <tt>config.action_view.embed_authenticity_token_in_remote_forms = false</tt>.
+ # This is helpful when you're fragment-caching the form. Remote forms get the
+ # authenticity from the <tt>meta</tt> tag, so embedding is unnecessary unless you
+ # support browsers without JavaScript.
# * 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.
@@ -618,16 +624,18 @@ module ActionView
# responsibility of the caller to escape all the values.
html_options["action"] = url_for(url_for_options)
html_options["accept-charset"] = "UTF-8"
-
+
html_options["data-remote"] = true if html_options.delete("remote")
- if html_options["data-remote"] && html_options["authenticity_token"] == true
+ if html_options["data-remote"] &&
+ !embed_authenticity_token_in_remote_forms &&
+ html_options["authenticity_token"] != true
+ # The authenticity token is taken from the meta tag in this case
+ html_options["authenticity_token"] = false
+ elsif 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
end
end
end
diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb
index 43371a1c49..5162e1955b 100644
--- a/actionpack/lib/action_view/railtie.rb
+++ b/actionpack/lib/action_view/railtie.rb
@@ -7,6 +7,14 @@ module ActionView
config.action_view = ActiveSupport::OrderedOptions.new
config.action_view.stylesheet_expansions = {}
config.action_view.javascript_expansions = { :defaults => %w(jquery jquery_ujs) }
+ config.action_view.embed_authenticity_token_in_remote_forms = true
+
+ initializer "action_view.embed_authenticity_token_in_remote_forms" do |app|
+ ActiveSupport.on_load(:action_view) do
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms =
+ app.config.action_view.delete(:embed_authenticity_token_in_remote_forms)
+ end
+ end
initializer "action_view.logger" do
ActiveSupport.on_load(:action_view) { self.logger ||= Rails.logger }
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 7b722bd3d7..7ded9ddc81 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -44,6 +44,14 @@ module RequestForgeryProtectionActions
render :inline => "<%= form_for(:some_resource, :remote => true, :authenticity_token => true ) {} %>"
end
+ def form_for_with_token
+ render :inline => "<%= form_for(:some_resource, :authenticity_token => true ) {} %>"
+ end
+
+ def form_for_remote_with_external_token
+ render :inline => "<%= form_for(:some_resource, :remote => true, :authenticity_token => 'external_token') {} %>"
+ end
+
def rescue_action(e) raise e end
end
@@ -108,11 +116,42 @@ module RequestForgeryProtectionTests
assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token
end
- def test_should_render_form_without_token_tag_if_remote
+ def test_should_render_form_with_token_tag_if_remote
assert_not_blocked do
get :form_for_remote
end
- assert_no_match(/authenticity_token/, response.body)
+ assert_match(/authenticity_token/, response.body)
+ end
+
+ def test_should_render_form_without_token_tag_if_remote_and_embedding_token_is_off
+ begin
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = false
+ assert_not_blocked do
+ get :form_for_remote
+ end
+ assert_no_match(/authenticity_token/, response.body)
+ ensure
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = true
+ end
+ end
+
+ def test_should_render_form_with_token_tag_if_remote_and_embedding_token_is_off_but_true_option_passed
+ begin
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = false
+ assert_not_blocked do
+ get :form_for_remote_with_token
+ end
+ assert_match(/authenticity_token/, response.body)
+ ensure
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = true
+ end
+ end
+
+ def test_should_render_form_with_token_tag_if_remote_and_external_authenticity_token_requested
+ assert_not_blocked do
+ get :form_for_remote_with_external_token
+ end
+ assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', 'external_token'
end
def test_should_render_form_with_token_tag_if_remote_and_authenticity_token_requested
@@ -122,6 +161,13 @@ module RequestForgeryProtectionTests
assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token
end
+ def test_should_render_form_with_token_tag_with_authenticity_token_requested
+ assert_not_blocked do
+ get :form_for_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
diff --git a/guides/source/configuring.textile b/guides/source/configuring.textile
index cf0d8f1a43..46e02c904f 100644
--- a/guides/source/configuring.textile
+++ b/guides/source/configuring.textile
@@ -395,6 +395,8 @@ And can reference in the view with the following code:
* +config.action_view.cache_asset_ids+ With the cache enabled, the asset tag helper methods will make fewer expensive file system calls (the default implementation checks the file system timestamp). However this prevents you from modifying any asset files while the server is running.
+* +config.action_view.embed_authenticity_token_in_remote_forms+ This is by default set to true. If you set it to false, authenticity_token will not be added to forms with +:remote => true+ by default. You can force +authenticity_token+ to be added to such remote form by passing +:authenticity_token => true+ option.
+
h4. Configuring Action Mailer
There are a number of settings available on +config.action_mailer+: