Skip to content

Commit

Permalink
Move form_remote_tag and remote_form_for into prototype_legacy_helper
Browse files Browse the repository at this point in the history
  • Loading branch information
josh committed Jan 30, 2010
1 parent 779094a commit 9c2c307
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 265 deletions.
109 changes: 0 additions & 109 deletions actionpack/lib/action_view/helpers/prototype_helper.rb
Expand Up @@ -102,115 +102,6 @@ module PrototypeHelper
:form, :with, :update, :script, :type ]).merge(CALLBACKS)
end

# Returns a form tag that will submit using XMLHttpRequest in the
# background instead of the regular reloading POST arrangement. Even
# though it's using JavaScript to serialize the form elements, the form
# submission will work just like a regular submission as viewed by the
# receiving side (all elements available in <tt>params</tt>). The options for
# specifying the target with <tt>:url</tt> and defining callbacks is the same as
# +link_to_remote+.
#
# A "fall-through" target for browsers that doesn't do JavaScript can be
# specified with the <tt>:action</tt>/<tt>:method</tt> options on <tt>:html</tt>.
#
# Example:
# # Generates:
# # <form action="/some/place" method="post" onsubmit="new Ajax.Request('',
# # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
# form_remote_tag :html => { :action =>
# url_for(:controller => "some", :action => "place") }
#
# The Hash passed to the <tt>:html</tt> key is equivalent to the options (2nd)
# argument in the FormTagHelper.form_tag method.
#
# By default the fall-through action is the same as the one specified in
# the <tt>:url</tt> (and the default method is <tt>:post</tt>).
#
# form_remote_tag also takes a block, like form_tag:
# # Generates:
# # <form action="/" method="post" onsubmit="new Ajax.Request('/',
# # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)});
# # return false;"> <div><input name="commit" type="submit" value="Save" /></div>
# # </form>
# <% form_remote_tag :url => '/posts' do -%>
# <div><%= submit_tag 'Save' %></div>
# <% end -%>
def form_remote_tag(options = {}, &block)
options[:form] = true

options[:html] ||= {}
options[:html][:onsubmit] =
(options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") +
"#{remote_function(options)}; return false;"

form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block)
end

# Creates a form that will submit using XMLHttpRequest in the background
# instead of the regular reloading POST arrangement and a scope around a
# specific resource that is used as a base for questioning about
# values for the fields.
#
# === Resource
#
# Example:
# <% remote_form_for(@post) do |f| %>
# ...
# <% end %>
#
# This will expand to be the same as:
#
# <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
# ...
# <% end %>
#
# === Nested Resource
#
# Example:
# <% remote_form_for([@post, @comment]) do |f| %>
# ...
# <% end %>
#
# This will expand to be the same as:
#
# <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %>
# ...
# <% end %>
#
# If you don't need to attach a form to a resource, then check out form_remote_tag.
#
# See FormHelper#form_for for additional semantics.
def remote_form_for(record_or_name_or_array, *args, &proc)
options = args.extract_options!

case record_or_name_or_array
when String, Symbol
object_name = record_or_name_or_array
when Array
object = record_or_name_or_array.last
object_name = ActionController::RecordIdentifier.singular_class_name(object)
apply_form_for_options!(record_or_name_or_array, options)
args.unshift object
else
object = record_or_name_or_array
object_name = ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array)
apply_form_for_options!(object, options)
args.unshift object
end

concat(form_remote_tag(options))
fields_for(object_name, *(args << options), &proc)
concat('</form>'.html_safe!)
end
alias_method :form_remote_for, :remote_form_for

# Returns '<tt>eval(request.responseText)</tt>' which is the JavaScript function
# that +form_remote_tag+ can call in <tt>:complete</tt> to evaluate a multiple
# update return document using +update_element_function+ calls.
def evaluate_remote_response
"eval(request.responseText)"
end

# Returns the JavaScript needed for a remote function.
# Takes the same arguments as link_to_remote.
#
Expand Down
45 changes: 18 additions & 27 deletions actionpack/test/controller/request_forgery_protection_test.rb
Expand Up @@ -6,14 +6,10 @@ module RequestForgeryProtectionActions
def index
render :inline => "<%= form_tag('/') {} %>"
end

def show_button
render :inline => "<%= button_to('New', '/') {} %>"
end

def remote_form
render :inline => "<% form_remote_tag(:url => '/') {} %>"
end

def unsafe
render :text => 'pwn'
Expand All @@ -30,11 +26,11 @@ class RequestForgeryProtectionController < ActionController::Base

class FreeCookieController < RequestForgeryProtectionController
self.allow_forgery_protection = false

def index
render :inline => "<%= form_tag('/') {} %>"
end

def show_button
render :inline => "<%= button_to('New', '/') {} %>"
end
Expand Down Expand Up @@ -65,11 +61,6 @@ def test_should_render_button_to_with_token_tag
assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
end

def test_should_render_remote_form_with_only_one_token_parameter
get :remote_form
assert_equal 1, @response.body.scan(@token).size
end

def test_should_allow_get
get :index
assert_response :success
Expand All @@ -84,12 +75,12 @@ def test_should_not_allow_html_post_without_token
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
assert_raise(ActionController::InvalidAuthenticityToken) { post :index, :format => :html }
end

def test_should_not_allow_html_put_without_token
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
assert_raise(ActionController::InvalidAuthenticityToken) { put :index, :format => :html }
end

def test_should_not_allow_html_delete_without_token
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
assert_raise(ActionController::InvalidAuthenticityToken) { delete :index, :format => :html }
Expand Down Expand Up @@ -154,51 +145,51 @@ def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_to
delete :index, :format => 'xml'
end
end

def test_should_allow_xhr_post_without_token
assert_nothing_raised { xhr :post, :index }
end

def test_should_allow_xhr_put_without_token
assert_nothing_raised { xhr :put, :index }
end

def test_should_allow_xhr_delete_without_token
assert_nothing_raised { xhr :delete, :index }
end

def test_should_allow_xhr_post_with_encoded_form_content_type_without_token
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
assert_nothing_raised { xhr :post, :index }
end

def test_should_allow_post_with_token
post :index, :authenticity_token => @token
assert_response :success
end

def test_should_allow_put_with_token
put :index, :authenticity_token => @token
assert_response :success
end

def test_should_allow_delete_with_token
delete :index, :authenticity_token => @token
assert_response :success
end

def test_should_allow_post_with_xml
@request.env['CONTENT_TYPE'] = Mime::XML.to_s
post :index, :format => 'xml'
assert_response :success
end

def test_should_allow_put_with_xml
@request.env['CONTENT_TYPE'] = Mime::XML.to_s
put :index, :format => 'xml'
assert_response :success
end

def test_should_allow_delete_with_xml
@request.env['CONTENT_TYPE'] = Mime::XML.to_s
delete :index, :format => 'xml'
Expand Down Expand Up @@ -231,17 +222,17 @@ def setup

ActiveSupport::SecureRandom.stubs(:base64).returns(@token)
end

def test_should_not_render_form_with_token_tag
get :index
assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false
end

def test_should_not_render_button_to_with_token_tag
get :show_button
assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false
end

def test_should_allow_all_methods_without_token
[:post, :put, :delete].each do |method|
assert_nothing_raised { send(method, :index)}
Expand Down
29 changes: 0 additions & 29 deletions actionpack/test/template/form_helper_test.rb
Expand Up @@ -1230,26 +1230,6 @@ def test_default_form_builder_no_instance_variable

end

# Perhaps this test should be moved to prototype helper tests.
def test_remote_form_for_with_labelled_builder
self.extend ActionView::Helpers::PrototypeHelper

remote_form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
end

expected =
%(<form action="http://www.example.com" onsubmit="new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" method="post">) +
"<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
"<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
"<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>" +
"</form>"

assert_dom_equal expected, output_buffer
end

def test_fields_for_with_labelled_builder
fields_for(:post, @post, :builder => LabelledFormBuilder) do |f|
concat f.text_field(:title)
Expand Down Expand Up @@ -1396,15 +1376,6 @@ def test_form_for_with_existing_object_and_custom_url
assert_equal expected, output_buffer
end

def test_remote_form_for_with_html_options_adds_options_to_form_tag
self.extend ActionView::Helpers::PrototypeHelper

remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\" onsubmit=\"new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"></form>"

assert_dom_equal expected, output_buffer
end

protected
def comments_path(post)
"/posts/#{post.id}/comments"
Expand Down

0 comments on commit 9c2c307

Please sign in to comment.