Skip to content
This repository
Browse code

file_field makes the enclosing form multipart

  • Loading branch information...
commit b17b980a15ee4a5f2f629d91c6fa6ca7db74daa8 1 parent e808224
Santiago Pastorino spastorino authored
2  actionpack/CHANGELOG
... ... @@ -1,5 +1,7 @@
1 1 *Rails 3.1.0 (unreleased)*
2 2
  3 +* file_field automatically adds :multipart => true to the enclosing form. [Santiago Pastorino]
  4 +
3 5 * Renames csrf_meta_tag -> csrf_meta_tags, and aliases csrf_meta_tag for backwards compatibility. [fxn]
4 6
5 7 * Add Rack::Cache to the default stack. Create a Rails store that delegates to the Rails cache, so by default, whatever caching layer you are using will be used
55 actionpack/lib/action_view/helpers/form_helper.rb
@@ -317,8 +317,11 @@ def form_for(record, record_object = nil, options = nil, &proc)
317 317 options[:html] ||= {}
318 318 options[:html][:remote] = options.delete(:remote)
319 319
320   - output = form_tag(options.delete(:url) || {}, options.delete(:html) || {})
321   - output << fields_for(object_name, object, options, &proc)
  320 + builder = instantiate_builder(object_name, object, options, &proc)
  321 + fields_for = capture(builder, &proc)
  322 + default_options = builder.multipart? ? { :multipart => true } : {}
  323 + output = form_tag(options.delete(:url) || {}, default_options.merge!(options.delete(:html) || {}))
  324 + output << fields_for
322 325 output.safe_concat('</form>')
323 326 end
324 327
@@ -529,22 +532,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
529 532 # <% end %>
530 533 # <% end %>
531 534 def fields_for(record, record_object = nil, options = nil, &block)
532   - raise ArgumentError, "Missing block" unless block_given?
533   -
534   - options, record_object = record_object, nil if record_object.is_a?(Hash)
535   - options ||= {}
536   -
537   - case record
538   - when String, Symbol
539   - object = record_object
540   - object_name = record
541   - else
542   - object = record
543   - object_name = ActiveModel::Naming.param_key(object)
544   - end
545   -
546   - builder = options[:builder] || ActionView::Base.default_form_builder
547   - capture(builder.new(object_name, object, self, options, block), &block)
  535 + capture(instantiate_builder(record, record_object, options, &block), &block)
548 536 end
549 537
550 538 # Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
@@ -848,6 +836,27 @@ def number_field(object_name, method, options = {})
848 836 def range_field(object_name, method, options = {})
849 837 InstanceTag.new(object_name, method, self, options.delete(:object)).to_number_field_tag("range", options)
850 838 end
  839 +
  840 + private
  841 +
  842 + def instantiate_builder(record, record_object = nil, options = nil, &block)
  843 + raise ArgumentError, "Missing block" unless block_given?
  844 +
  845 + options, record_object = record_object, nil if record_object.is_a?(Hash)
  846 + options ||= {}
  847 +
  848 + case record
  849 + when String, Symbol
  850 + object = record_object
  851 + object_name = record
  852 + else
  853 + object = record
  854 + object_name = ActiveModel::Naming.param_key(object)
  855 + end
  856 +
  857 + builder = options[:builder] || ActionView::Base.default_form_builder
  858 + builder.new(object_name, object, self, options, block)
  859 + end
851 860 end
852 861
853 862 module InstanceTagMethods #:nodoc:
@@ -1112,6 +1121,9 @@ class FormBuilder #:nodoc:
1112 1121
1113 1122 attr_accessor :object_name, :object, :options
1114 1123
  1124 + attr_reader :multipart
  1125 + alias :multipart? :multipart
  1126 +
1115 1127 def self.model_name
1116 1128 @model_name ||= Struct.new(:partial_path).new(name.demodulize.underscore.sub!(/_builder$/, ''))
1117 1129 end
@@ -1131,9 +1143,10 @@ def initialize(object_name, object, template, options, proc)
1131 1143 raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
1132 1144 end
1133 1145 end
  1146 + @multipart = nil
1134 1147 end
1135 1148
1136   - (field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector|
  1149 + (field_helpers - %w(label check_box radio_button fields_for hidden_field file_field)).each do |selector|
1137 1150 class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
1138 1151 def #{selector}(method, options = {}) # def text_field(method, options = {})
1139 1152 @template.send( # @template.send(
@@ -1197,6 +1210,10 @@ def hidden_field(method, options = {})
1197 1210 @template.hidden_field(@object_name, method, objectify_options(options))
1198 1211 end
1199 1212
  1213 + def file_field(method, options = {})
  1214 + @multipart = true
  1215 + @template.file_field(@object_name, method, objectify_options(options))
  1216 + end
1200 1217 # Add the submit button for the given form. When no value is given, it checks
1201 1218 # if the object is a new resource or not to create the proper label:
1202 1219 #
18 actionpack/test/template/form_helper_test.rb
@@ -665,6 +665,24 @@ def test_form_for
665 665 assert_dom_equal expected, output_buffer
666 666 end
667 667
  668 + def test_form_for_with_file_field_generate_multipart
  669 + Post.send :attr_accessor, :file
  670 +
  671 + assert_deprecated do
  672 + form_for(:post, @post, :html => { :id => 'create-post' }) do |f|
  673 + concat f.file_field(:file)
  674 + end
  675 + end
  676 +
  677 + expected =
  678 + "<form accept-charset='UTF-8' action='/' id='create-post' method='post' enctype='multipart/form-data'>" +
  679 + snowman +
  680 + "<input name='post[file]' type='file' id='post_file' />" +
  681 + "</form>"
  682 +
  683 + assert_dom_equal expected, output_buffer
  684 + end
  685 +
668 686 def test_form_for_with_format
669 687 form_for(@post, :format => :json, :html => { :id => "edit_post_123", :class => "edit_post" }) do |f|
670 688 concat f.label(:title)

20 comments on commit b17b980

Prem Sichanugrist
Collaborator

Owwwww .... +1 on this commit. I love it :)

Piotr Sarnacki
Collaborator

+1 :D

I can't count times when I forget about adding multipart to forms ;-)

Xavier Noria
Owner

Hey, a commit like this should grep the project for ":multipart" and revise the existing examples.

Josh Kalderimis

Fantastic work! +1 and another +1 for doing this while at gogaruco!

Kieran Pilkington

+1 Make sure to add a deprecation to rails_upgrade plugin

Parker Selbert

+1 Very nicely done. I think you even beat formtastic to it.

Linus Oleander

Perfect!

Davis Z. Cabral

+1. good job.

Bruno Grasselli

+1, good job =)

John Feminella

+1 for a useful addition, but no test?

Santiago Pastorino

Hey thanks to everyone.
@fj of course i've added a test take a look again, this file actionpack/test/template/form_helper_test.rb has one more test.

John Feminella

My bad, GitHub was being wonky and that file came up blank. Thanks for your contribution!

Joost Baaij

This goodness only works with form_for, and not form_tag?

Edit: confirmed. I'll try to whip up a patch that adds it to form_tag too.

Nicolas Blanco

tilsammans > "xxx_tag"s are basic HTML tags with no magic at all. They remain "basic" tags and won't get these kind of "magic" features.

Dallas Reedy

tilsammans this feature is only available to forms using a FormBuilder and, as slainer68 pointed out, form_tag simply outputs a <form> tag (or wraps the given block with <form>…</form>)—no "magic" involved.

Joost Baaij

Yeah I got that. But there's no reason not to make the form_tag a little more intelligent isn't there? I've got a patch on LH already.

José Valim
Owner

This behavior should not be added form_tag. form_tag is a basic/raw constructor.

Paulo Fagiani

@spastorino what is the chance this can be added in rails 3.0.x yet?

Santiago Pastorino
Owner

@fagiani hey, I'm sorry but this is a new feature and doesn't fit on a stable release. We are just pushing bug fixes or important stuff to 3.0.x. But you can go ahead and monkey patch for your apps :).

Please sign in to comment.
Something went wrong with that request. Please try again.