Changeset 8080
- Timestamp:
- 11/06/07 05:56:02 (1 year ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/actionpack/lib/action_view/helpers/form_helper.rb
r8033 r8080 5 5 module ActionView 6 6 module Helpers 7 # Form helpers are designed to make working with models much easier than just standard html elements by 8 # providing a set of methods for creating forms based on your models. This helper generates the HTML for forms, 9 # providing a method for each sort of input (e.g., text, password, select, and so on). When the form is 10 # submitted (i.e., when the user hits the submit button or <tt>form.submit</tt> is called via JavaScript), the form 11 # inputs will be bundled into the <tt>params</tt> object and passed back to the controller. 12 # 13 # There are two types of form helpers: those that specifically work with model attributes and those that don't. 7 # Form helpers are designed to make working with models much easier compared to using just standard HTML 8 # elements by providing a set of methods for creating forms based on your models. This helper generates the HTML 9 # for forms, providing a method for each sort of input (e.g., text, password, select, and so on). When the form 10 # is submitted (i.e., when the user hits the submit button or <tt>form.submit</tt> is called via JavaScript), the form inputs will be bundled into the <tt>params</tt> object and passed back to the controller. 11 # 12 # There are two types of form helpers: those that specifically work with model attributes and those that don't. 14 13 # This helper deals with those that work with model attributes; to see an example of form helpers that don't work 15 14 # with model attributes, check the ActionView::Helpers::FormTagHelper documentation. 16 15 # 17 # The core method of this helper, form_for, gives you the ability to create a form for a model instance; 16 # The core method of this helper, form_for, gives you the ability to create a form for a model instance; 18 17 # for example, let's say that you have a model <tt>Person</tt> and want to create a new instance of it: 19 18 # 20 # # Note: a @person variable will have been created in the controller. 19 # # Note: a @person variable will have been created in the controller. 21 20 # # For example: @person = Person.new 22 21 # <% form_for :person, @person, :url => { :action => "create" } do |f| %> … … 37 36 # 38 37 # {"action"=>"create", "controller"=>"persons", "person"=>{"first_name"=>"William", "last_name"=>"Smith"}} 39 # 38 # 40 39 # The params hash has a nested <tt>person</tt> value, which can therefore be accessed with <tt>params[:person]</tt> in the controller. 41 40 # If were editing/updating an instance (e.g., <tt>Person.find(1)</tt> rather than <tt>Person.new</tt> in the controller), the objects 42 41 # attribute values are filled into the form (e.g., the <tt>person_first_name</tt> field would have that person's first name in it). 43 # 42 # 44 43 # If the object name contains square brackets the id for the object will be inserted. For example: 45 44 # 46 45 # <%= text_field "person[]", "name" %> 47 # 46 # 48 47 # ...will generate the following ERb. 49 48 # … … 63 62 module FormHelper 64 63 # Creates a form and a scope around a specific model object that is used as a base for questioning about 65 # values for the fields. 64 # values for the fields. 66 65 # 67 66 # <% form_for :person, @person, :url => { :action => "update" } do |f| %> … … 72 71 # <% end %> 73 72 # 74 # Worth noting is that the form_for tag is called in a ERb evaluation block, not an ERb output block. So that's <tt><% %></tt>, 73 # Worth noting is that the form_for tag is called in a ERb evaluation block, not an ERb output block. So that's <tt><% %></tt>, 75 74 # not <tt><%= %></tt>. Also worth noting is that form_for yields a <tt>form_builder</tt> object, in this example as <tt>f</tt>, which emulates 76 75 # the API for the stand-alone FormHelper methods, but without the object name. So instead of <tt>text_field :person, :name</tt>, 77 # you get away with <tt>f.text_field :name</tt>. 78 # 79 # Even further, the form_for method allows you to more easily escape the instance variable convention. So while the stand-alone80 # approach would require <tt>text_field :person, :name, :object => person</tt> 76 # you get away with <tt>f.text_field :name</tt>. 77 # 78 # Even further, the form_for method allows you to more easily escape the instance variable convention. So while the stand-alone 79 # approach would require <tt>text_field :person, :name, :object => person</tt> 81 80 # to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with 82 81 # <tt>:person, person</tt> and all subsequent field calls save <tt>:person</tt> and <tt>:object => person</tt>. … … 92 91 # <% end %> 93 92 # 94 # Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base .95 # Like FormOptionHelper#collection_select and DateHelper#datetime_select.93 # Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base, 94 # like FormOptionHelper#collection_select and DateHelper#datetime_select. 96 95 # 97 96 # HTML attributes for the form tag can be given as :html => {...}. For example: 98 # 97 # 99 98 # <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %> 100 99 # ... … … 146 145 # 147 146 # You can also build forms using a customized FormBuilder class. Subclass FormBuilder and override or define some more helpers, 148 # then use your custom builder. For example, let's say you made a helper to automatically add labels to form inputs.149 # 147 # then use your custom builder. For example, let's say you made a helper to automatically add labels to form inputs. 148 # 150 149 # <% form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %> 151 150 # <%= f.text_field :first_name %> … … 154 153 # <%= check_box_tag "person[admin]", @person.company.admin? %> 155 154 # <% end %> 156 # 155 # 157 156 # In many cases you will want to wrap the above in another helper, so you could do something like the following: 158 157 # … … 189 188 def apply_form_for_options!(object_or_array, options) #:nodoc: 190 189 object = object_or_array.is_a?(Array) ? object_or_array.last : object_or_array 191 190 192 191 html_options = 193 192 if object.respond_to?(:new_record?) && object.new_record? … … 209 208 # First name: <%= person_form.text_field :first_name %> 210 209 # Last name : <%= person_form.text_field :last_name %> 211 # 210 # 212 211 # <% fields_for :permission, @person.permission do |permission_fields| %> 213 212 # Admin? : <%= permission_fields.check_box :admin %> … … 229 228 # assigned to the template (identified by +object+). The text of label will default to the attribute name unless you specify 230 229 # it explicitly. Additional options on the label tag can be passed as a hash with +options+. These options will be tagged 231 # onto the htmlas an HTML element attribute as in the example shown.230 # onto the HTML as an HTML element attribute as in the example shown. 232 231 # 233 232 # ==== Examples … … 247 246 # Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) on an object 248 247 # assigned to the template (identified by +object+). Additional options on the input tag can be passed as a 249 # hash with +options+. These options will be tagged onto the htmlas an HTML element attribute as in the example248 # hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example 250 249 # shown. 251 250 # … … 269 268 # Returns an input tag of the "password" type tailored for accessing a specified attribute (identified by +method+) on an object 270 269 # assigned to the template (identified by +object+). Additional options on the input tag can be passed as a 271 # hash with +options+. These options will be tagged onto the htmlas an HTML element attribute as in the example270 # hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example 272 271 # shown. 273 272 # … … 291 290 # Returns a hidden input tag tailored for accessing a specified attribute (identified by +method+) on an object 292 291 # assigned to the template (identified by +object+). Additional options on the input tag can be passed as a 293 # hash with +options+. These options will be tagged onto the html as an htmlelement attribute as in the example292 # hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example 294 293 # shown. 295 294 # … … 302 301 # 303 302 # hidden_field(:user, :token) 304 # # => <input type="hidden" id="user_token" name="user[token]" value="#{@user.token}" /> 303 # # => <input type="hidden" id="user_token" name="user[token]" value="#{@user.token}" /> 305 304 def hidden_field(object_name, method, options = {}) 306 305 InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("hidden", options) … … 309 308 # Returns an file upload input tag tailored for accessing a specified attribute (identified by +method+) on an object 310 309 # assigned to the template (identified by +object+). Additional options on the input tag can be passed as a 311 # hash with +options+. These options will be tagged onto the html as an htmlelement attribute as in the example310 # hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example 312 311 # shown. 313 312 # … … 457 456 options["checked"] = "checked" if checked 458 457 pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase 459 options["id"] ||= defined?(@auto_index) ? 458 options["id"] ||= defined?(@auto_index) ? 460 459 "#{@object_name}_#{@auto_index}_#{@method_name}_#{pretty_tag_value}" : 461 460 "#{@object_name}_#{@method_name}_#{pretty_tag_value}" … … 511 510 tag_text << ">True</option></select>" 512 511 end 513 512 514 513 def to_content_tag(tag_name, options = {}) 515 514 content_tag(tag_name, value(object), options) 516 515 end 517 516 518 517 def object 519 518 @object || (@template_object.instance_variable_get("@#{@object_name}") rescue nil) … … 527 526 self.class.value_before_type_cast(object, @method_name) 528 527 end 529 528 530 529 class << self 531 530 def value(object, method_name) 532 531 object.send method_name unless object.nil? 533 532 end 534 533 535 534 def value_before_type_cast(object, method_name) 536 535 unless object.nil? … … 540 539 end 541 540 end 542 541 543 542 def check_box_checked?(value, checked_value) 544 543 case value … … 555 554 end 556 555 end 557 556 558 557 def radio_button_checked?(value, checked_value) 559 558 value.to_s == checked_value.to_s … … 605 604 606 605 def initialize(object_name, object, template, options, proc) 607 @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc 608 end 609 606 @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc 607 end 608 610 609 (field_helpers - %w(label check_box radio_button fields_for)).each do |selector| 611 610 src = <<-end_src … … 629 628 @template.check_box(@object_name, method, options.merge(:object => @object), checked_value, unchecked_value) 630 629 end 631 630 632 631 def radio_button(method, tag_value, options = {}) 633 632 @template.radio_button(@object_name, method, tag_value, options.merge(:object => @object)) 634 633 end 635 634 636 635 def error_message_on(method, prepend_text = "", append_text = "", css_class = "formError") 637 636 @template.error_message_on(@object, method, prepend_text, append_text, css_class) 638 end 637 end 639 638 640 639 def error_messages(options = {}) 641 640 @template.error_messages_for(@object_name, options.merge(:object => @object)) 642 641 end 643 642 644 643 def submit(value = "Save changes", options = {}) 645 644 @template.submit_tag(value, options.reverse_merge(:id => "#{object_name}_submit"))