Browse files

file_field makes the enclosing form multipart

  • Loading branch information...
1 parent e808224 commit b17b980a15ee4a5f2f629d91c6fa6ca7db74daa8 @spastorino spastorino committed Sep 17, 2010
View
2 actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.1.0 (unreleased)*
+* file_field automatically adds :multipart => true to the enclosing form. [Santiago Pastorino]
+
* Renames csrf_meta_tag -> csrf_meta_tags, and aliases csrf_meta_tag for backwards compatibility. [fxn]
* 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
View
55 actionpack/lib/action_view/helpers/form_helper.rb
@@ -317,8 +317,11 @@ def form_for(record, record_object = nil, options = nil, &proc)
options[:html] ||= {}
options[:html][:remote] = options.delete(:remote)
- output = form_tag(options.delete(:url) || {}, options.delete(:html) || {})
- output << fields_for(object_name, object, options, &proc)
+ builder = instantiate_builder(object_name, object, options, &proc)
+ fields_for = capture(builder, &proc)
+ default_options = builder.multipart? ? { :multipart => true } : {}
+ output = form_tag(options.delete(:url) || {}, default_options.merge!(options.delete(:html) || {}))
+ output << fields_for
output.safe_concat('</form>')
end
@@ -529,22 +532,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
# <% end %>
# <% end %>
def fields_for(record, record_object = nil, options = nil, &block)
- raise ArgumentError, "Missing block" unless block_given?
-
- options, record_object = record_object, nil if record_object.is_a?(Hash)
- options ||= {}
-
- case record
- when String, Symbol
- object = record_object
- object_name = record
- else
- object = record
- object_name = ActiveModel::Naming.param_key(object)
- end
-
- builder = options[:builder] || ActionView::Base.default_form_builder
- capture(builder.new(object_name, object, self, options, block), &block)
+ capture(instantiate_builder(record, record_object, options, &block), &block)
end
# 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 = {})
def range_field(object_name, method, options = {})
InstanceTag.new(object_name, method, self, options.delete(:object)).to_number_field_tag("range", options)
end
+
+ private
+
+ def instantiate_builder(record, record_object = nil, options = nil, &block)
+ raise ArgumentError, "Missing block" unless block_given?
+
+ options, record_object = record_object, nil if record_object.is_a?(Hash)
+ options ||= {}
+
+ case record
+ when String, Symbol
+ object = record_object
+ object_name = record
+ else
+ object = record
+ object_name = ActiveModel::Naming.param_key(object)
+ end
+
+ builder = options[:builder] || ActionView::Base.default_form_builder
+ builder.new(object_name, object, self, options, block)
+ end
end
module InstanceTagMethods #:nodoc:
@@ -1112,6 +1121,9 @@ class FormBuilder #:nodoc:
attr_accessor :object_name, :object, :options
+ attr_reader :multipart
+ alias :multipart? :multipart
+
def self.model_name
@model_name ||= Struct.new(:partial_path).new(name.demodulize.underscore.sub!(/_builder$/, ''))
end
@@ -1131,9 +1143,10 @@ def initialize(object_name, object, template, options, proc)
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
end
end
+ @multipart = nil
end
- (field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector|
+ (field_helpers - %w(label check_box radio_button fields_for hidden_field file_field)).each do |selector|
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{selector}(method, options = {}) # def text_field(method, options = {})
@template.send( # @template.send(
@@ -1197,6 +1210,10 @@ def hidden_field(method, options = {})
@template.hidden_field(@object_name, method, objectify_options(options))
end
+ def file_field(method, options = {})
+ @multipart = true
+ @template.file_field(@object_name, method, objectify_options(options))
+ end
# Add the submit button for the given form. When no value is given, it checks
# if the object is a new resource or not to create the proper label:
#
View
18 actionpack/test/template/form_helper_test.rb
@@ -665,6 +665,24 @@ def test_form_for
assert_dom_equal expected, output_buffer
end
+ def test_form_for_with_file_field_generate_multipart
+ Post.send :attr_accessor, :file
+
+ assert_deprecated do
+ form_for(:post, @post, :html => { :id => 'create-post' }) do |f|
+ concat f.file_field(:file)
+ end
+ end
+
+ expected =
+ "<form accept-charset='UTF-8' action='/' id='create-post' method='post' enctype='multipart/form-data'>" +
+ snowman +
+ "<input name='post[file]' type='file' id='post_file' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_form_for_with_format
form_for(@post, :format => :json, :html => { :id => "edit_post_123", :class => "edit_post" }) do |f|
concat f.label(:title)

20 comments on commit b17b980

@sikachu
Ruby on Rails member

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

@drogus
Ruby on Rails member

+1 :D

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

@fxn
Ruby on Rails member

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

@joshk

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

@KieranP

+1 Make sure to add a deprecation to rails_upgrade plugin

@sorentwo

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

@oleander

Perfect!

@daviscabral

+1. good job.

@BrunoGrasselli

+1, good job =)

@fj

+1 for a useful addition, but no test?

@spastorino
Ruby on Rails member

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.

@fj

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

@tilsammans

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.

@nicolasblanco

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

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.

@tilsammans

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.

@josevalim
Ruby on Rails member

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

@fagiani

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

@spastorino
Ruby on Rails member

@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.