mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Took first stab at reimplementing form_remote_tag helpers
This commit is contained in:
committed by
Stefan Penner
parent
0955f57915
commit
118a720a01
@@ -2,26 +2,41 @@ module ActionView
|
||||
module Helpers
|
||||
module AjaxHelper
|
||||
include UrlHelper
|
||||
|
||||
def link_to_remote(name, url, options = {})
|
||||
html = options.delete(:html) || {}
|
||||
|
||||
def form_remote_tag(options = {}, &block)
|
||||
attributes = {}
|
||||
attributes.merge!(extract_remote_attributes!(options))
|
||||
attributes.merge!(options)
|
||||
|
||||
url = attributes.delete(:url)
|
||||
form_tag(attributes.delete(:action) || url_for(url), attributes, &block)
|
||||
end
|
||||
|
||||
def extract_remote_attributes!(options)
|
||||
attributes = options.delete(:html) || {}
|
||||
|
||||
update = options.delete(:update)
|
||||
if update.is_a?(Hash)
|
||||
html["data-update-success"] = update[:success]
|
||||
html["data-update-failure"] = update[:failure]
|
||||
attributes["data-update-success"] = update[:success]
|
||||
attributes["data-update-failure"] = update[:failure]
|
||||
else
|
||||
html["data-update-success"] = update
|
||||
attributes["data-update-success"] = update
|
||||
end
|
||||
|
||||
html["data-update-position"] = options.delete(:position)
|
||||
html["data-method"] = options.delete(:method)
|
||||
html["data-remote"] = "true"
|
||||
|
||||
html.merge!(options)
|
||||
attributes["data-update-position"] = options.delete(:position)
|
||||
attributes["data-method"] = options.delete(:method)
|
||||
attributes["data-remote"] = true
|
||||
|
||||
attributes
|
||||
end
|
||||
|
||||
def link_to_remote(name, url, options = {})
|
||||
attributes = {}
|
||||
attributes.merge!(extract_remote_attributes!(options))
|
||||
attributes.merge!(options)
|
||||
|
||||
url = url_for(url) if url.is_a?(Hash)
|
||||
link_to(name, url, html)
|
||||
link_to(name, url, attributes)
|
||||
end
|
||||
|
||||
def button_to_remote(name, options = {}, html_options = {})
|
||||
@@ -72,17 +87,6 @@ module ActionView
|
||||
SCRIPT
|
||||
end
|
||||
|
||||
# TODO: Move to javascript helpers - BR
|
||||
class JSFunction
|
||||
def initialize(statements, *arguments)
|
||||
@statements, @arguments = statements, arguments
|
||||
end
|
||||
|
||||
def as_json(options = nil)
|
||||
"function(#{@arguments.join(", ")}) {#{@statements}}"
|
||||
end
|
||||
end
|
||||
|
||||
module Rails2Compatibility
|
||||
def set_callbacks(options, html)
|
||||
[:complete, :failure, :success, :interactive, :loaded, :loading].each do |type|
|
||||
@@ -111,7 +115,20 @@ module ActionView
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
# TODO: Move to javascript helpers - BR
|
||||
class JSFunction
|
||||
def initialize(statements, *arguments)
|
||||
@statements, @arguments = statements, arguments
|
||||
end
|
||||
|
||||
def as_json(options = nil)
|
||||
"function(#{@arguments.join(", ")}) {#{@statements}}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,22 @@ require "abstract_unit"
|
||||
|
||||
class AjaxTestCase < ActiveSupport::TestCase
|
||||
include ActionView::Helpers::AjaxHelper
|
||||
|
||||
# TODO: Ask Katz: Should these be included by the AjaxHelper? - BR
|
||||
include ActionView::Helpers::TagHelper
|
||||
include ActionView::Helpers::FormTagHelper
|
||||
|
||||
# TODO: Replace with the real url_for method - BR
|
||||
def url_for(url)
|
||||
case url
|
||||
when Hash
|
||||
"/url/hash"
|
||||
when String
|
||||
url
|
||||
else
|
||||
raise TypeError.new("Unsupported url type (#{url.class}) for this test helper")
|
||||
end
|
||||
end
|
||||
|
||||
def assert_html(html, matches)
|
||||
matches.each do |match|
|
||||
@@ -10,6 +25,12 @@ class AjaxTestCase < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
def assert_html_not_present(html, matches)
|
||||
matches.each do |match|
|
||||
assert_no_match Regexp.new(Regexp.escape(match)), html
|
||||
end
|
||||
end
|
||||
|
||||
def extract_json_from_data_element(data_element)
|
||||
root = HTML::Document.new(data_element).root
|
||||
script = root.find(:tag => "script")
|
||||
@@ -98,6 +119,108 @@ class LinkToRemoteTest < AjaxTestCase
|
||||
end
|
||||
end
|
||||
|
||||
class FormRemoteTagTest < AjaxTestCase
|
||||
|
||||
def protect_against_forgery?
|
||||
false
|
||||
end
|
||||
|
||||
def request_forgery_protection_token
|
||||
"token_name"
|
||||
end
|
||||
|
||||
def form_authenticity_token
|
||||
"t0k3n"
|
||||
end
|
||||
|
||||
def authenticity_input_attributes
|
||||
%w(input type="hidden" name="token_name" value="t0k3n")
|
||||
end
|
||||
|
||||
# TODO: Play with using assert_dom_equal
|
||||
test "basic" do
|
||||
assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }),
|
||||
%w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer")
|
||||
end
|
||||
|
||||
test "when protect_against_forgery? is true" do
|
||||
def protect_against_forgery?
|
||||
true
|
||||
end
|
||||
|
||||
expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer")
|
||||
expected_patterns = expected_form_attributes + authenticity_input_attributes
|
||||
|
||||
assert_equal true, protect_against_forgery?
|
||||
assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), expected_patterns
|
||||
end
|
||||
|
||||
test ":action is used when it is present" do
|
||||
html = form_remote_tag(:update => "#glass_of_beer", :action => "foo")
|
||||
|
||||
assert_html html, %w(form action="foo" method="post" data-remote="true" data-update-success="#glass_of_beer")
|
||||
assert_no_match /url="foo"/, html
|
||||
end
|
||||
|
||||
test ":url is used when :action is not present" do
|
||||
html = form_remote_tag(:update => "#glass_of_beer", :url => "bar")
|
||||
|
||||
assert_html html, %w(form action="bar" method="post" data-remote="true" data-update-success="#glass_of_beer")
|
||||
assert_no_match /url="bar"/, html
|
||||
end
|
||||
|
||||
test "when protect_against_forgery? is false" do
|
||||
assert_equal false, protect_against_forgery?
|
||||
assert_html_not_present form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }),
|
||||
authenticity_input_attributes
|
||||
end
|
||||
|
||||
test "update callbacks" do
|
||||
assert_html form_remote_tag(:update => { :success => "#glass_of_beer" }, :url => { :action => :fast }),
|
||||
%w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer")
|
||||
|
||||
assert_html form_remote_tag(:update => { :failure => "#glass_of_water" }, :url => { :action => :fast }),
|
||||
%w(form action="/url/hash" method="post" data-remote="true" data-update-failure="#glass_of_water")
|
||||
|
||||
assert_html form_remote_tag(:update => { :success => "#glass_of_beer", :failure => "#glass_of_water" }, :url => { :action => :fast }),
|
||||
%w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water")
|
||||
end
|
||||
|
||||
test "using a :method option" do
|
||||
expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer")
|
||||
# TODO: Ask Katz: Why does rails do this? Some web servers don't allow PUT or DELETE from what I remember... - BR
|
||||
expected_input_attributes = %w(input name="_method" type="hidden" value="put")
|
||||
|
||||
assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }),
|
||||
expected_form_attributes + expected_input_attributes
|
||||
end
|
||||
|
||||
|
||||
# FIXME: This test is janky as hell. We are essentially rewriting capture and concat and they don't really work right
|
||||
# because output is out of order. This test passes because it's only doing a regex match on the buffer, but this really
|
||||
# needs to be fixed by using the real helper methods that rails provides. capture, concat, url_for etc. should be
|
||||
# implemented by their *real* methods or we need to find a better workaround so that our tests aren't written so
|
||||
# poorly. - BR
|
||||
test "form_remote_tag with block in erb" do
|
||||
def capture(*args, &block)
|
||||
@buffer = []
|
||||
block.call(*args) if block_given?
|
||||
end
|
||||
def concat(str)
|
||||
@buffer << str
|
||||
end
|
||||
|
||||
expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" /form)
|
||||
expected_inner_html = %w(w00t!)
|
||||
|
||||
form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) { concat expected_inner_html }
|
||||
assert_html @buffer.to_s,
|
||||
expected_form_attributes + expected_inner_html
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
class ButtonToRemoteTest < AjaxTestCase
|
||||
def button(options, html = {})
|
||||
button_to_remote("Remote outpost", options, html)
|
||||
|
||||
Reference in New Issue
Block a user