Skip to content

Commit

Permalink
add namespace options to form_for
Browse files Browse the repository at this point in the history
You can provide a namespace for your form to ensure uniqueness of id attributes on form elements.
The namespace attribute will be prefixed with underscore on the generate HTML id
  • Loading branch information
nashby committed Nov 27, 2011
1 parent e7e046f commit fb8b555
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 2 deletions.
11 changes: 9 additions & 2 deletions actionpack/lib/action_view/helpers/form_helper.rb
Expand Up @@ -158,6 +158,9 @@ def convert_to_model(object)
# * <tt>:url</tt> - The URL the form is submitted to. It takes the same
# fields you pass to +url_for+ or +link_to+. In particular you may pass
# here a named route directly as well. Defaults to the current action.
# * <tt>:namespace</tt> - A namespace for your form to ensure uniqueness of
# id attributes on form elements. The namespace attribute will be prefixed
# with underscore on the generate HTML id.
# * <tt>:html</tt> - Optional HTML attributes for the form tag.
#
# Also note that +form_for+ doesn't create an exclusive scope. It's still
Expand Down Expand Up @@ -385,7 +388,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
action, method = object.respond_to?(:persisted?) && object.persisted? ? [:edit, :put] : [:new, :post]
options[:html].reverse_merge!(
:class => as ? "#{as}_#{action}" : dom_class(object, action),
:id => as ? "#{as}_#{action}" : dom_id(object, action),
:id => as ? "#{as}_#{action}" : [options[:namespace], dom_id(object, action)].compact.join("_").presence,
:method => method
)

Expand Down Expand Up @@ -971,6 +974,7 @@ class InstanceTag
def initialize(object_name, method_name, template_object, object = nil)
@object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
@template_object = template_object

@object_name.sub!(/\[\]$/,"") || @object_name.sub!(/\[\]\]$/,"]")
@object = retrieve_object(object)
@auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match
Expand All @@ -989,6 +993,7 @@ def to_label_tag(text = nil, options = {}, &block)

add_default_name_and_id_for_value(tag_value, name_and_id)
options.delete("index")
options.delete("namespace")
options["for"] ||= name_and_id["id"]

if block_given?
Expand Down Expand Up @@ -1195,6 +1200,7 @@ def add_default_name_and_id(options)
options["name"] ||= tag_name + (options['multiple'] ? '[]' : '')
options["id"] = options.fetch("id"){ tag_id }
end
options["id"] = [options.delete('namespace'), options["id"]].compact.join("_").presence
end

def tag_name
Expand Down Expand Up @@ -1253,7 +1259,7 @@ def initialize(object_name, object, template, options, proc)
@nested_child_index = {}
@object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
@parent_builder = options[:parent_builder]
@default_options = @options ? @options.slice(:index) : {}
@default_options = @options ? @options.slice(:index, :namespace) : {}
if @object_name.to_s.match(/\[\]$/)
if object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(:to_param)
@auto_index = object.to_param
Expand All @@ -1280,6 +1286,7 @@ def fields_for(record_name, record_object = nil, fields_options = {}, &block)
fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
fields_options[:builder] ||= options[:builder]
fields_options[:parent_builder] = self
fields_options[:namespace] = fields_options[:parent_builder].options[:namespace]

case record_name
when String, Symbol
Expand Down
76 changes: 76 additions & 0 deletions actionpack/test/template/form_helper_test.rb
Expand Up @@ -935,6 +935,82 @@ def test_form_for_with_nil_index_option_override
assert_dom_equal expected, output_buffer
end

def test_form_for_with_namespace
form_for(@post, :namespace => 'namespace') do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
end

expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do
"<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />" +
"<textarea name='post[body]' id='namespace_post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
"<input name='post[secret]' checked='checked' type='checkbox' id='namespace_post_secret' value='1' />"
end

assert_dom_equal expected, output_buffer
end

def test_form_for_with_namespace_with_label
form_for(@post, :namespace => 'namespace') do |f|
concat f.label(:title)
concat f.text_field(:title)
end

expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do
"<label for='namespace_post_title'>Title</label>" +
"<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />"
end

assert_dom_equal expected, output_buffer
end

def test_two_form_for_with_namespace
form_for(@post, :namespace => 'namespace_1') do |f|
concat f.label(:title)
concat f.text_field(:title)
end

expected_1 = whole_form('/posts/123', 'namespace_1_edit_post_123', 'edit_post', 'put') do
"<label for='namespace_1_post_title'>Title</label>" +
"<input name='post[title]' size='30' type='text' id='namespace_1_post_title' value='Hello World' />"
end

assert_dom_equal expected_1, output_buffer

form_for(@post, :namespace => 'namespace_2') do |f|
concat f.label(:title)
concat f.text_field(:title)
end

expected_2 = whole_form('/posts/123', 'namespace_2_edit_post_123', 'edit_post', 'put') do
"<label for='namespace_2_post_title'>Title</label>" +
"<input name='post[title]' size='30' type='text' id='namespace_2_post_title' value='Hello World' />"
end

assert_dom_equal expected_2, output_buffer
end

def test_fields_for_with_namespace
@comment.body = 'Hello World'
form_for(@post, :namespace => 'namespace') do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.fields_for(@comment) { |c|
concat c.text_field(:body)
}
end

expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do
"<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />" +
"<textarea name='post[body]' id='namespace_post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
"<input name='post[comment][body]' size='30' type='text' id='namespace_post_comment_body' value='Hello World' />"
end

assert_dom_equal expected, output_buffer
end

def test_submit_with_object_as_new_record_and_locale_strings
old_locale, I18n.locale = I18n.locale, :submit

Expand Down

0 comments on commit fb8b555

Please sign in to comment.