aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
authorNicholas Seckar <nseckar@gmail.com>2006-02-04 19:58:45 +0000
committerNicholas Seckar <nseckar@gmail.com>2006-02-04 19:58:45 +0000
commit9474fe72dd388559aa013717e9e91b5a87aa872c (patch)
tree46dc786482cd5ae8dca7b7ede92559d9802f8238 /actionpack/lib
parent2ee6229bd8cf3a87ede0cd8b573e3faf5a15dbfa (diff)
downloadrails-9474fe72dd388559aa013717e9e91b5a87aa872c.tar.gz
rails-9474fe72dd388559aa013717e9e91b5a87aa872c.tar.bz2
rails-9474fe72dd388559aa013717e9e91b5a87aa872c.zip
Add :builder => option to form_for and friends. Closes 3268.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3536 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb60
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb13
2 files changed, 50 insertions, 23 deletions
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index c896ace862..75c09dfe87 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -97,12 +97,36 @@ module ActionView
#
# Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base.
# Like collection_select and datetime_select.
+ #
+ # You can also build forms using a customized FormBuilder class. Subclass FormBuilder and override or define some more helpers,
+ # then use your custom builder like so:
+ #
+ # <% form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %>
+ # <%= f.text_field :first_name %>
+ # <%= f.text_field :last_name %>
+ # <%= text_area :person, :biography %>
+ # <%= check_box_tag "person[admin]", @person.company.admin? %>
+ # <% end %>
+ #
+ # In many cases you will want to wrap the above in another helper, such as:
+ #
+ # def labelled_form_for(name, object, options, &proc)
+ # form_for(name, object, options.merge(:builder => LabellingFormBuiler), &proc)
+ # end
+ #
def form_for(object_name, object, options = {}, &proc)
- url_for_options = options[:url]
- additional_options = options.reject { |k, v| ![ :method, :multipart ].include?(k) }
- concat(form_tag(url_for_options, additional_options), proc.binding)
- fields_for(object_name, object, &proc)
- concat(end_form_tag, proc.binding)
+ raise ArgumentError, "form_for requires a block!" unless proc
+
+ url_options = options.delete :url
+ form_tag_selector = options.delete(:form_tag_selector) || :form_tag
+ form_options = {}
+ [:method, :multipart].each { |key| form_options[key] = options.delete(key) if options.key? key }
+
+ fields_for(object_name, object, options.merge(:proc => proc)) do |builder|
+ concat send(form_tag_selector, url_options, form_options), proc.binding
+ builder.build_form(url_options, form_options) { proc.call builder }
+ concat end_form_tag, proc.binding
+ end
end
# Creates a scope around a specific model object like form_for, but doesn't create the form tags themselves. This makes
@@ -119,8 +143,11 @@ module ActionView
#
# Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base.
# Like collection_select and datetime_select.
- def fields_for(object_name, object, &proc)
- form_builder = FormBuilder.new(object_name, object, self, proc)
+ def fields_for(object_name, object, options = {}, &proc)
+ raise ArgumentError, "fields_for requires a block!" unless proc
+
+ builder = options[:builder] || FormBuilder
+ form_builder = builder.new(object_name, object, self, options, options[:proc] || proc)
proc.call(form_builder)
end
@@ -350,13 +377,20 @@ module ActionView
end
class FormBuilder
- def initialize(object_name, object, template, proc)
- @object_name, @object, @template, @proc = object_name, object, template, proc
+ # The methods which wrap a form helper call.
+ class_inheritable_accessor :field_helpers
+ self.field_helpers = (FormHelper.instance_methods - ['form_for'])
+
+ def initialize(object_name, object, template, options, proc)
+ @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
end
-
- (FormHelper.instance_methods - [ :check_box, :radio_button ]).each do |selector|
- next if selector == "form_for"
-
+
+ # An empty stub that can be overriden to wrap a form created by form_for.
+ def build_form(url_options, form_options, &proc)
+ proc.call self
+ end
+
+ (field_helpers - %w(check_box radio_button)).each do |selector|
src = <<-end_src
def #{selector}(method, options = {})
@template.send(#{selector.inspect}, @object_name, method, options.merge(:object => @object))
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 27dc9c93cf..2cd7550c65 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -170,18 +170,11 @@ module ActionView
tag("form", options[:html], true)
end
- def form_remote_for(object_name, object, options = {}, &proc)
- concat(form_remote_tag(options), proc.binding)
- fields_for(object_name, object, &proc)
- concat(end_form_tag, proc.binding)
- end
-
# Works like form_remote_tag, but uses form_for semantics.
- def form_remote_for(object_name, object, options = {}, &proc)
- concat(form_remote_tag(options), proc.binding)
- fields_for(object_name, object, &proc)
- concat(end_form_tag, proc.binding)
+ def remote_form_for(object_name, object, options = {}, &proc)
+ form_for(object_name, object, options.merge(:form_for_select => :form_remote_tag), &proc)
end
+ alias_method :form_remote_for, :remote_form_for
# Returns a button input tag that will submit form using XMLHttpRequest
# in the background instead of regular reloading POST arrangement.