actionpack 1.11.2 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +392 -5
- data/lib/action_controller.rb +8 -4
- data/lib/action_controller/assertions.rb +9 -10
- data/lib/action_controller/base.rb +177 -88
- data/lib/action_controller/benchmarking.rb +5 -5
- data/lib/action_controller/caching.rb +44 -36
- data/lib/action_controller/cgi_ext/cgi_methods.rb +71 -6
- data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +1 -1
- data/lib/action_controller/cgi_process.rb +36 -24
- data/lib/action_controller/components.rb +152 -52
- data/lib/action_controller/dependencies.rb +1 -1
- data/lib/action_controller/deprecated_redirects.rb +2 -2
- data/lib/action_controller/deprecated_request_methods.rb +34 -0
- data/lib/action_controller/filters.rb +59 -19
- data/lib/action_controller/flash.rb +53 -47
- data/lib/action_controller/helpers.rb +2 -2
- data/lib/action_controller/integration.rb +524 -0
- data/lib/action_controller/layout.rb +58 -23
- data/lib/action_controller/mime_responds.rb +163 -0
- data/lib/action_controller/mime_type.rb +142 -0
- data/lib/action_controller/pagination.rb +13 -7
- data/lib/action_controller/request.rb +59 -56
- data/lib/action_controller/rescue.rb +1 -1
- data/lib/action_controller/routing.rb +29 -10
- data/lib/action_controller/scaffolding.rb +8 -0
- data/lib/action_controller/session/active_record_store.rb +21 -10
- data/lib/action_controller/session/mem_cache_store.rb +18 -12
- data/lib/action_controller/session_management.rb +30 -11
- data/lib/action_controller/templates/rescues/_trace.rhtml +1 -1
- data/lib/action_controller/templates/scaffolds/layout.rhtml +4 -4
- data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
- data/lib/action_controller/test_process.rb +189 -118
- data/lib/action_controller/vendor/html-scanner/html/node.rb +20 -1
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +3 -0
- data/lib/action_controller/vendor/html-scanner/html/version.rb +1 -1
- data/lib/action_controller/vendor/xml_node.rb +97 -0
- data/lib/action_controller/verification.rb +2 -0
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +0 -2
- data/lib/action_view/base.rb +109 -36
- data/lib/action_view/compiled_templates.rb +1 -1
- data/lib/action_view/helpers/active_record_helper.rb +4 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +6 -7
- data/lib/action_view/helpers/capture_helper.rb +49 -12
- data/lib/action_view/helpers/date_helper.rb +14 -4
- data/lib/action_view/helpers/form_helper.rb +136 -20
- data/lib/action_view/helpers/form_options_helper.rb +29 -7
- data/lib/action_view/helpers/form_tag_helper.rb +22 -20
- data/lib/action_view/helpers/java_script_macros_helper.rb +29 -9
- data/lib/action_view/helpers/javascript_helper.rb +50 -446
- data/lib/action_view/helpers/javascripts/controls.js +95 -30
- data/lib/action_view/helpers/javascripts/dragdrop.js +161 -21
- data/lib/action_view/helpers/javascripts/effects.js +310 -211
- data/lib/action_view/helpers/javascripts/prototype.js +228 -28
- data/lib/action_view/helpers/number_helper.rb +9 -9
- data/lib/action_view/helpers/pagination_helper.rb +1 -1
- data/lib/action_view/helpers/prototype_helper.rb +900 -0
- data/lib/action_view/helpers/scriptaculous_helper.rb +135 -0
- data/lib/action_view/helpers/text_helper.rb +7 -6
- data/lib/action_view/helpers/url_helper.rb +23 -14
- data/lib/action_view/partials.rb +12 -4
- data/rakefile +13 -5
- data/test/abstract_unit.rb +4 -3
- data/test/active_record_unit.rb +88 -0
- data/test/{controller → activerecord}/active_record_assertions_test.rb +7 -50
- data/test/{controller → activerecord}/active_record_store_test.rb +27 -4
- data/test/activerecord/pagination_test.rb +161 -0
- data/test/controller/action_pack_assertions_test.rb +18 -15
- data/test/controller/base_test.rb +31 -42
- data/test/controller/benchmark_test.rb +8 -11
- data/test/controller/capture_test.rb +33 -1
- data/test/controller/cgi_test.rb +33 -0
- data/test/controller/custom_handler_test.rb +8 -0
- data/test/controller/fake_controllers.rb +9 -17
- data/test/controller/filters_test.rb +32 -3
- data/test/controller/flash_test.rb +26 -41
- data/test/controller/fragment_store_setting_test.rb +1 -1
- data/test/controller/layout_test.rb +73 -0
- data/test/controller/mime_responds_test.rb +257 -0
- data/test/controller/mime_type_test.rb +24 -0
- data/test/controller/new_render_test.rb +157 -1
- data/test/controller/redirect_test.rb +23 -0
- data/test/controller/render_test.rb +54 -56
- data/test/controller/request_test.rb +25 -0
- data/test/controller/routing_test.rb +74 -66
- data/test/controller/test_test.rb +66 -1
- data/test/controller/verification_test.rb +3 -1
- data/test/controller/webservice_test.rb +255 -0
- data/test/fixtures/companies.yml +24 -0
- data/test/fixtures/company.rb +9 -0
- data/test/fixtures/db_definitions/sqlite.sql +42 -0
- data/test/fixtures/developer.rb +7 -0
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects.yml +13 -0
- data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
- data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
- data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
- data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
- data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
- data/test/fixtures/multipart/mona_lisa.jpg +0 -0
- data/test/fixtures/project.rb +3 -0
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/replies.yml +13 -0
- data/test/fixtures/reply.rb +5 -0
- data/test/fixtures/respond_to/all_types_with_layout.rhtml +1 -0
- data/test/fixtures/respond_to/all_types_with_layout.rjs +1 -0
- data/test/fixtures/respond_to/layouts/standard.rhtml +1 -0
- data/test/fixtures/respond_to/using_defaults.rhtml +1 -0
- data/test/fixtures/respond_to/using_defaults.rjs +1 -0
- data/test/fixtures/respond_to/using_defaults.rxml +1 -0
- data/test/fixtures/respond_to/using_defaults_with_type_list.rhtml +1 -0
- data/test/fixtures/respond_to/using_defaults_with_type_list.rjs +1 -0
- data/test/fixtures/respond_to/using_defaults_with_type_list.rxml +1 -0
- data/test/fixtures/test/block_content_for.rhtml +2 -0
- data/test/fixtures/test/delete_with_js.rjs +2 -0
- data/test/fixtures/test/dot.directory/render_file_with_ivar.rhtml +1 -0
- data/test/fixtures/test/enum_rjs_test.rjs +6 -0
- data/test/fixtures/test/erb_content_for.rhtml +2 -0
- data/test/fixtures/test/hello_world.rxml +3 -0
- data/test/fixtures/test/hello_world_with_layout_false.rhtml +1 -0
- data/test/fixtures/test/non_erb_block_content_for.rxml +4 -0
- data/test/fixtures/topic.rb +3 -0
- data/test/fixtures/topics.yml +22 -0
- data/test/template/active_record_helper_test.rb +4 -0
- data/test/template/asset_tag_helper_test.rb +7 -2
- data/test/template/date_helper_test.rb +39 -2
- data/test/template/form_helper_test.rb +238 -5
- data/test/template/form_options_helper_test.rb +78 -0
- data/test/template/form_tag_helper_test.rb +11 -0
- data/test/template/java_script_macros_helper_test.rb +51 -6
- data/test/template/javascript_helper_test.rb +7 -153
- data/test/template/number_helper_test.rb +14 -13
- data/test/template/prototype_helper_test.rb +423 -0
- data/test/template/scriptaculous_helper_test.rb +90 -0
- data/test/template/text_helper_test.rb +12 -9
- data/test/template/url_helper_test.rb +31 -15
- metadata +291 -246
- data/lib/action_controller/cgi_ext/multipart_progress.rb +0 -169
- data/lib/action_controller/upload_progress.rb +0 -473
- data/lib/action_controller/vendor/html-scanner/html/node.rb.rej +0 -17
- data/lib/action_view/helpers/upload_progress_helper.rb +0 -433
- data/lib/action_view/vendor/builder.rb +0 -13
- data/lib/action_view/vendor/builder/blankslate.rb +0 -53
- data/lib/action_view/vendor/builder/xmlbase.rb +0 -143
- data/lib/action_view/vendor/builder/xmlevents.rb +0 -63
- data/lib/action_view/vendor/builder/xmlmarkup.rb +0 -308
- data/test/controller/multipart_progress_testx.rb +0 -365
- data/test/controller/upload_progress_testx.rb +0 -89
- data/test/template/upload_progress_helper_testx.rb +0 -136
@@ -10,7 +10,7 @@ module ActionView
|
|
10
10
|
#
|
11
11
|
# To use a compiled template module, create a new instance and include it into the class
|
12
12
|
# in which you want the template to be rendered.
|
13
|
-
class CompiledTemplates < Module
|
13
|
+
class CompiledTemplates < Module #:nodoc:
|
14
14
|
attr_reader :method_names
|
15
15
|
|
16
16
|
def initialize
|
@@ -103,7 +103,7 @@ module ActionView
|
|
103
103
|
def error_messages_for(object_name, options = {})
|
104
104
|
options = options.symbolize_keys
|
105
105
|
object = instance_variable_get("@#{object_name}")
|
106
|
-
|
106
|
+
if object && !object.errors.empty?
|
107
107
|
content_tag("div",
|
108
108
|
content_tag(
|
109
109
|
options[:header_tag] || "h2",
|
@@ -113,6 +113,8 @@ module ActionView
|
|
113
113
|
content_tag("ul", object.errors.full_messages.collect { |msg| content_tag("li", msg) }),
|
114
114
|
"id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
|
115
115
|
)
|
116
|
+
else
|
117
|
+
""
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
@@ -139,7 +141,7 @@ module ActionView
|
|
139
141
|
to_input_field_tag("text", options)
|
140
142
|
when :date
|
141
143
|
to_date_select_tag(options)
|
142
|
-
when :datetime
|
144
|
+
when :datetime, :timestamp
|
143
145
|
to_datetime_select_tag(options)
|
144
146
|
when :boolean
|
145
147
|
to_boolean_select_tag(options)
|
@@ -59,11 +59,10 @@ module ActionView
|
|
59
59
|
# <tt>controllers/application.rb</tt> and <tt>helpers/application_helper.rb</tt>.
|
60
60
|
def javascript_include_tag(*sources)
|
61
61
|
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
|
62
|
-
if sources.
|
63
|
-
sources = @@javascript_default_sources.dup
|
64
|
-
|
65
|
-
|
66
|
-
end
|
62
|
+
if sources.include?(:defaults)
|
63
|
+
sources = sources[0..(sources.index(:defaults))] + @@javascript_default_sources.dup + sources[(sources.index(:defaults) + 1)..sources.length]
|
64
|
+
sources.delete(:defaults)
|
65
|
+
sources << "application" if defined?(RAILS_ROOT) and File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")
|
67
66
|
end
|
68
67
|
sources.collect { |source|
|
69
68
|
source = javascript_path(source)
|
@@ -131,7 +130,7 @@ module ActionView
|
|
131
130
|
# * file name, like "rss.gif", that gets expanded to "/images/rss.gif"
|
132
131
|
# * file name without extension, like "logo", that gets expanded to "/images/logo.png"
|
133
132
|
def image_tag(source, options = {})
|
134
|
-
options.symbolize_keys
|
133
|
+
options.symbolize_keys!
|
135
134
|
|
136
135
|
options[:src] = image_path(source)
|
137
136
|
options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize
|
@@ -147,7 +146,7 @@ module ActionView
|
|
147
146
|
private
|
148
147
|
def compute_public_path(source, dir, ext)
|
149
148
|
source = "/#{dir}/#{source}" unless source.first == "/" || source.include?(":")
|
150
|
-
source = "#{source}.#{ext}" unless source.include?(".")
|
149
|
+
source = "#{source}.#{ext}" unless source.split("/").last.include?(".")
|
151
150
|
source = "#{@controller.request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ source
|
152
151
|
source = ActionController::Base.asset_host + source unless source.include?(":")
|
153
152
|
source
|
@@ -43,24 +43,30 @@ module ActionView
|
|
43
43
|
# instance variable. You can use this instance variable anywhere
|
44
44
|
# in your templates and even in your layout.
|
45
45
|
#
|
46
|
-
# Example:
|
46
|
+
# Example of capture being used in a .rhtml page:
|
47
47
|
#
|
48
48
|
# <% @greeting = capture do %>
|
49
49
|
# Welcome To my shiny new web page!
|
50
|
-
# <% end %>
|
50
|
+
# <% end %>
|
51
|
+
#
|
52
|
+
# Example of capture being used in a .rxml page:
|
53
|
+
#
|
54
|
+
# @greeting = capture do
|
55
|
+
# 'Welcome To my shiny new web page!'
|
56
|
+
# end
|
51
57
|
def capture(*args, &block)
|
52
58
|
# execute the block
|
53
|
-
|
54
|
-
|
55
|
-
|
59
|
+
begin
|
60
|
+
buffer = eval("_erbout", block.binding)
|
61
|
+
rescue
|
62
|
+
buffer = nil
|
63
|
+
end
|
56
64
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
data
|
65
|
+
if buffer.nil?
|
66
|
+
capture_block(*args, &block)
|
67
|
+
else
|
68
|
+
capture_erb_with_buffer(buffer, *args, &block)
|
69
|
+
end
|
64
70
|
end
|
65
71
|
|
66
72
|
# Content_for will store the given block
|
@@ -84,6 +90,37 @@ module ActionView
|
|
84
90
|
def content_for(name, &block)
|
85
91
|
eval "@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)"
|
86
92
|
end
|
93
|
+
|
94
|
+
private
|
95
|
+
def capture_block(*args, &block)
|
96
|
+
block.call(*args)
|
97
|
+
end
|
98
|
+
|
99
|
+
def capture_erb(*args, &block)
|
100
|
+
buffer = eval("_erbout", block.binding)
|
101
|
+
capture_erb_with_buffer(buffer, *args, &block)
|
102
|
+
end
|
103
|
+
|
104
|
+
def capture_erb_with_buffer(buffer, *args, &block)
|
105
|
+
pos = buffer.length
|
106
|
+
block.call(*args)
|
107
|
+
|
108
|
+
# extract the block
|
109
|
+
data = buffer[pos..-1]
|
110
|
+
|
111
|
+
# replace it in the original with empty string
|
112
|
+
buffer[pos..-1] = ''
|
113
|
+
|
114
|
+
data
|
115
|
+
end
|
116
|
+
|
117
|
+
def erb_content_for(name, &block)
|
118
|
+
eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_erb(&block)"
|
119
|
+
end
|
120
|
+
|
121
|
+
def block_content_for(name, &block)
|
122
|
+
eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_block(&block)"
|
123
|
+
end
|
87
124
|
end
|
88
125
|
end
|
89
126
|
end
|
@@ -76,8 +76,8 @@ module ActionView
|
|
76
76
|
# date_select("user", "birthday", :order => [:month, :day])
|
77
77
|
#
|
78
78
|
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
79
|
-
def date_select(
|
80
|
-
InstanceTag.new(
|
79
|
+
def date_select(object_name, method, options = {})
|
80
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options)
|
81
81
|
end
|
82
82
|
|
83
83
|
# Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based
|
@@ -87,8 +87,8 @@ module ActionView
|
|
87
87
|
# datetime_select("post", "written_on", :start_year => 1995)
|
88
88
|
#
|
89
89
|
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
90
|
-
def datetime_select(
|
91
|
-
InstanceTag.new(
|
90
|
+
def datetime_select(object_name, method, options = {})
|
91
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options)
|
92
92
|
end
|
93
93
|
|
94
94
|
# Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
|
@@ -293,5 +293,15 @@ module ActionView
|
|
293
293
|
datetime_select
|
294
294
|
end
|
295
295
|
end
|
296
|
+
|
297
|
+
class FormBuilder
|
298
|
+
def date_select(method, options = {})
|
299
|
+
@template.date_select(@object_name, method, options.merge(:object => @object))
|
300
|
+
end
|
301
|
+
|
302
|
+
def datetime_select(method, options = {})
|
303
|
+
@template.datetime_select(@object_name, method, options.merge(:object => @object))
|
304
|
+
end
|
305
|
+
end
|
296
306
|
end
|
297
307
|
end
|
@@ -47,7 +47,7 @@ module ActionView
|
|
47
47
|
#
|
48
48
|
# If the object name contains square brackets the id for the object will be inserted. Example:
|
49
49
|
#
|
50
|
-
# <%=
|
50
|
+
# <%= text_field "person[]", "name" %>
|
51
51
|
#
|
52
52
|
# ...becomes:
|
53
53
|
#
|
@@ -65,6 +65,90 @@ module ActionView
|
|
65
65
|
# There's also methods for helping to build form tags in link:classes/ActionView/Helpers/FormOptionsHelper.html,
|
66
66
|
# link:classes/ActionView/Helpers/DateHelper.html, and link:classes/ActionView/Helpers/ActiveRecordHelper.html
|
67
67
|
module FormHelper
|
68
|
+
# Creates a form and a scope around a specific model object, which is then used as a base for questioning about
|
69
|
+
# values for the fields. Examples:
|
70
|
+
#
|
71
|
+
# <% form_for :person, @person, :url => { :action => "update" } do |f| %>
|
72
|
+
# First name: <%= f.text_field :first_name %>
|
73
|
+
# Last name : <%= f.text_field :last_name %>
|
74
|
+
# Biography : <%= f.text_area :biography %>
|
75
|
+
# Admin? : <%= f.check_box :admin %>
|
76
|
+
# <% end %>
|
77
|
+
#
|
78
|
+
# Worth noting is that the form_for tag is called in a ERb evaluation block, not a ERb output block. So that's <tt><% %></tt>,
|
79
|
+
# not <tt><%= %></tt>. Also worth noting is that the form_for yields a form_builder object, in this example as f, which emulates
|
80
|
+
# the API for the stand-alone FormHelper methods, but without the object name. So instead of <tt>text_field :person, :name</tt>,
|
81
|
+
# you get away with <tt>f.text_field :name</tt>.
|
82
|
+
#
|
83
|
+
# That in itself is a modest increase in comfort. The big news is that form_for allows us to more easily escape the instance
|
84
|
+
# variable convention, so while the stand-alone approach would require <tt>text_field :person, :name, :object => person</tt>
|
85
|
+
# to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with
|
86
|
+
# <tt>:person, person</tt> and all subsequent field calls save <tt>:person</tt> and <tt>:object => person</tt>.
|
87
|
+
#
|
88
|
+
# Also note that form_for doesn't create an exclusive scope. It's still possible to use both the stand-alone FormHelper methods
|
89
|
+
# and methods from FormTagHelper. Example:
|
90
|
+
#
|
91
|
+
# <% form_for :person, @person, :url => { :action => "update" } do |f| %>
|
92
|
+
# First name: <%= f.text_field :first_name %>
|
93
|
+
# Last name : <%= f.text_field :last_name %>
|
94
|
+
# Biography : <%= text_area :person, :biography %>
|
95
|
+
# Admin? : <%= check_box_tag "person[admin]", @person.company.admin? %>
|
96
|
+
# <% end %>
|
97
|
+
#
|
98
|
+
# Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base.
|
99
|
+
# Like collection_select and datetime_select.
|
100
|
+
#
|
101
|
+
# Html attributes for the form tag can be given as :html => {...}. Example:
|
102
|
+
#
|
103
|
+
# <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %>
|
104
|
+
# ...
|
105
|
+
# <% end %>
|
106
|
+
#
|
107
|
+
# You can also build forms using a customized FormBuilder class. Subclass FormBuilder and override or define some more helpers,
|
108
|
+
# then use your custom builder like so:
|
109
|
+
#
|
110
|
+
# <% form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %>
|
111
|
+
# <%= f.text_field :first_name %>
|
112
|
+
# <%= f.text_field :last_name %>
|
113
|
+
# <%= text_area :person, :biography %>
|
114
|
+
# <%= check_box_tag "person[admin]", @person.company.admin? %>
|
115
|
+
# <% end %>
|
116
|
+
#
|
117
|
+
# In many cases you will want to wrap the above in another helper, such as:
|
118
|
+
#
|
119
|
+
# def labelled_form_for(name, object, options, &proc)
|
120
|
+
# form_for(name, object, options.merge(:builder => LabellingFormBuiler), &proc)
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
def form_for(object_name, *args, &proc)
|
124
|
+
raise ArgumentError, "Missing block" unless block_given?
|
125
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
126
|
+
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}), proc.binding)
|
127
|
+
fields_for(object_name, *(args << options), &proc)
|
128
|
+
concat('</form>', proc.binding)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Creates a scope around a specific model object like form_for, but doesn't create the form tags themselves. This makes
|
132
|
+
# fields_for suitable for specifying additional model objects in the same form. Example:
|
133
|
+
#
|
134
|
+
# <% form_for :person, @person, :url => { :action => "update" } do |person_form| %>
|
135
|
+
# First name: <%= person_form.text_field :first_name %>
|
136
|
+
# Last name : <%= person_form.text_field :last_name %>
|
137
|
+
#
|
138
|
+
# <% fields_for :permission, @person.permission do |permission_fields| %>
|
139
|
+
# Admin? : <%= permission_fields.check_box :admin %>
|
140
|
+
# <% end %>
|
141
|
+
# <% end %>
|
142
|
+
#
|
143
|
+
# Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base.
|
144
|
+
# Like collection_select and datetime_select.
|
145
|
+
def fields_for(object_name, *args, &proc)
|
146
|
+
raise ArgumentError, "Missing block" unless block_given?
|
147
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
148
|
+
object = args.first
|
149
|
+
yield((options[:builder] || FormBuilder).new(object_name, object, self, options, proc))
|
150
|
+
end
|
151
|
+
|
68
152
|
# Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) on an object
|
69
153
|
# assigned to the template (identified by +object+). Additional options on the input tag can be passed as a
|
70
154
|
# hash with +options+.
|
@@ -72,23 +156,23 @@ module ActionView
|
|
72
156
|
# Examples (call, result):
|
73
157
|
# text_field("post", "title", "size" => 20)
|
74
158
|
# <input type="text" id="post_title" name="post[title]" size="20" value="#{@post.title}" />
|
75
|
-
def text_field(
|
76
|
-
InstanceTag.new(
|
159
|
+
def text_field(object_name, method, options = {})
|
160
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("text", options)
|
77
161
|
end
|
78
162
|
|
79
163
|
# Works just like text_field, but returns an input tag of the "password" type instead.
|
80
|
-
def password_field(
|
81
|
-
InstanceTag.new(
|
164
|
+
def password_field(object_name, method, options = {})
|
165
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("password", options)
|
82
166
|
end
|
83
167
|
|
84
168
|
# Works just like text_field, but returns an input tag of the "hidden" type instead.
|
85
|
-
def hidden_field(
|
86
|
-
InstanceTag.new(
|
169
|
+
def hidden_field(object_name, method, options = {})
|
170
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("hidden", options)
|
87
171
|
end
|
88
172
|
|
89
173
|
# Works just like text_field, but returns an input tag of the "file" type instead, which won't have a default value.
|
90
|
-
def file_field(
|
91
|
-
InstanceTag.new(
|
174
|
+
def file_field(object_name, method, options = {})
|
175
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("file", options)
|
92
176
|
end
|
93
177
|
|
94
178
|
# Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +method+)
|
@@ -100,8 +184,8 @@ module ActionView
|
|
100
184
|
# <textarea cols="20" rows="40" id="post_body" name="post[body]">
|
101
185
|
# #{@post.body}
|
102
186
|
# </textarea>
|
103
|
-
def text_area(
|
104
|
-
InstanceTag.new(
|
187
|
+
def text_area(object_name, method, options = {})
|
188
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_text_area_tag(options)
|
105
189
|
end
|
106
190
|
|
107
191
|
# Returns a checkbox tag tailored for accessing a specified attribute (identified by +method+) on an object
|
@@ -120,8 +204,8 @@ module ActionView
|
|
120
204
|
# check_box("puppy", "gooddog", {}, "yes", "no")
|
121
205
|
# <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
|
122
206
|
# <input name="puppy[gooddog]" type="hidden" value="no" />
|
123
|
-
def check_box(
|
124
|
-
InstanceTag.new(
|
207
|
+
def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
|
208
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_check_box_tag(options, checked_value, unchecked_value)
|
125
209
|
end
|
126
210
|
|
127
211
|
# Returns a radio button tag for accessing a specified attribute (identified by +method+) on an object
|
@@ -134,8 +218,8 @@ module ActionView
|
|
134
218
|
# <input type="radio" id="post_category" name="post[category]" value="rails" checked="checked" />
|
135
219
|
# <input type="radio" id="post_category" name="post[category]" value="java" />
|
136
220
|
#
|
137
|
-
def radio_button(
|
138
|
-
InstanceTag.new(
|
221
|
+
def radio_button(object_name, method, tag_value, options = {})
|
222
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_radio_button_tag(tag_value, options)
|
139
223
|
end
|
140
224
|
end
|
141
225
|
|
@@ -149,9 +233,10 @@ module ActionView
|
|
149
233
|
DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 }.freeze unless const_defined?(:DEFAULT_TEXT_AREA_OPTIONS)
|
150
234
|
DEFAULT_DATE_OPTIONS = { :discard_type => true }.freeze unless const_defined?(:DEFAULT_DATE_OPTIONS)
|
151
235
|
|
152
|
-
def initialize(object_name, method_name, template_object, local_binding = nil)
|
153
|
-
@object_name, @method_name = object_name.to_s, method_name.to_s
|
236
|
+
def initialize(object_name, method_name, template_object, local_binding = nil, object = nil)
|
237
|
+
@object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
|
154
238
|
@template_object, @local_binding = template_object, local_binding
|
239
|
+
@object = object
|
155
240
|
if @object_name.sub!(/\[\]$/,"")
|
156
241
|
@auto_index = @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}").id_before_type_cast
|
157
242
|
end
|
@@ -186,7 +271,7 @@ module ActionView
|
|
186
271
|
def to_text_area_tag(options = {})
|
187
272
|
options = DEFAULT_TEXT_AREA_OPTIONS.merge(options.stringify_keys)
|
188
273
|
add_default_name_and_id(options)
|
189
|
-
content_tag("textarea", html_escape(value_before_type_cast), options)
|
274
|
+
content_tag("textarea", html_escape(options.delete('value') || value_before_type_cast), options)
|
190
275
|
end
|
191
276
|
|
192
277
|
def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
|
@@ -240,11 +325,13 @@ module ActionView
|
|
240
325
|
end
|
241
326
|
|
242
327
|
def object
|
243
|
-
@template_object.instance_variable_get
|
328
|
+
@object || @template_object.instance_variable_get("@#{@object_name}")
|
244
329
|
end
|
245
330
|
|
246
331
|
def value
|
247
|
-
|
332
|
+
unless object.nil?
|
333
|
+
object.send(@method_name)
|
334
|
+
end
|
248
335
|
end
|
249
336
|
|
250
337
|
def value_before_type_cast
|
@@ -286,5 +373,34 @@ module ActionView
|
|
286
373
|
"#{@object_name}_#{index}_#{@method_name}"
|
287
374
|
end
|
288
375
|
end
|
376
|
+
|
377
|
+
class FormBuilder #:nodoc:
|
378
|
+
# The methods which wrap a form helper call.
|
379
|
+
class_inheritable_accessor :field_helpers
|
380
|
+
self.field_helpers = (FormHelper.instance_methods - ['form_for'])
|
381
|
+
|
382
|
+
attr_accessor :object_name, :object
|
383
|
+
|
384
|
+
def initialize(object_name, object, template, options, proc)
|
385
|
+
@object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
|
386
|
+
end
|
387
|
+
|
388
|
+
(field_helpers - %w(check_box radio_button)).each do |selector|
|
389
|
+
src = <<-end_src
|
390
|
+
def #{selector}(method, options = {})
|
391
|
+
@template.send(#{selector.inspect}, @object_name, method, options.merge(:object => @object))
|
392
|
+
end
|
393
|
+
end_src
|
394
|
+
class_eval src, __FILE__, __LINE__
|
395
|
+
end
|
396
|
+
|
397
|
+
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
398
|
+
@template.check_box(@object_name, method, options.merge(:object => @object), checked_value, unchecked_value)
|
399
|
+
end
|
400
|
+
|
401
|
+
def radio_button(method, tag_value, options = {})
|
402
|
+
@template.radio_button(@object_name, method, tag_value, options.merge(:object => @object))
|
403
|
+
end
|
404
|
+
end
|
289
405
|
end
|
290
406
|
end
|
@@ -47,7 +47,7 @@ module ActionView
|
|
47
47
|
#
|
48
48
|
# could become:
|
49
49
|
#
|
50
|
-
# <select name="post[person_id">
|
50
|
+
# <select name="post[person_id]">
|
51
51
|
# <option></option>
|
52
52
|
# <option value="1" selected="selected">David</option>
|
53
53
|
# <option value="2">Sam</option>
|
@@ -59,18 +59,21 @@ module ActionView
|
|
59
59
|
# to the database. Instead, a second model object is created when the create request is received.
|
60
60
|
# This allows the user to submit a form page more than once with the expected results of creating multiple records.
|
61
61
|
# In addition, this allows a single partial to be used to generate form inputs for both edit and create forms.
|
62
|
+
#
|
63
|
+
# By default, post.person_id is the selected option. Specify :selected => value to use a different selection
|
64
|
+
# or :selected => nil to leave all options unselected.
|
62
65
|
def select(object, method, choices, options = {}, html_options = {})
|
63
|
-
InstanceTag.new(object, method, self).to_select_tag(choices, options, html_options)
|
66
|
+
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_select_tag(choices, options, html_options)
|
64
67
|
end
|
65
68
|
|
66
69
|
# Return select and option tags for the given object and method using options_from_collection_for_select to generate the list of option tags.
|
67
70
|
def collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
|
68
|
-
InstanceTag.new(object, method, self).to_collection_select_tag(collection, value_method, text_method, options, html_options)
|
71
|
+
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options)
|
69
72
|
end
|
70
73
|
|
71
74
|
# Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags.
|
72
75
|
def country_select(object, method, priority_countries = nil, options = {}, html_options = {})
|
73
|
-
InstanceTag.new(object, method, self).to_country_select_tag(priority_countries, options, html_options)
|
76
|
+
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_country_select_tag(priority_countries, options, html_options)
|
74
77
|
end
|
75
78
|
|
76
79
|
# Return select and option tags for the given object and method, using
|
@@ -82,7 +85,7 @@ module ActionView
|
|
82
85
|
# zone model object. (See #time_zone_options_for_select for more
|
83
86
|
# information.)
|
84
87
|
def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
|
85
|
-
InstanceTag.new(object, method, self).to_time_zone_select_tag(priority_zones, options, html_options)
|
88
|
+
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
|
86
89
|
end
|
87
90
|
|
88
91
|
# Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
|
@@ -209,7 +212,7 @@ module ActionView
|
|
209
212
|
end
|
210
213
|
|
211
214
|
# Returns a string of option tags for pretty much any time zone in the
|
212
|
-
# world. Supply a TimeZone
|
215
|
+
# world. Supply a TimeZone name as +selected+ to have it marked as the
|
213
216
|
# selected option tag. You can also supply an array of TimeZone objects
|
214
217
|
# as +priority_zones+, so that they will be listed above the rest of the
|
215
218
|
# (long) list. (You can use TimeZone.us_zones as a convenience for
|
@@ -296,7 +299,8 @@ module ActionView
|
|
296
299
|
def to_select_tag(choices, options, html_options)
|
297
300
|
html_options = html_options.stringify_keys
|
298
301
|
add_default_name_and_id(html_options)
|
299
|
-
|
302
|
+
selected_value = options.has_key?(:selected) ? options[:selected] : value
|
303
|
+
content_tag("select", add_options(options_for_select(choices, selected_value), options, value), html_options)
|
300
304
|
end
|
301
305
|
|
302
306
|
def to_collection_select_tag(collection, value_method, text_method, options, html_options)
|
@@ -335,5 +339,23 @@ module ActionView
|
|
335
339
|
end
|
336
340
|
end
|
337
341
|
end
|
342
|
+
|
343
|
+
class FormBuilder
|
344
|
+
def select(method, choices, options = {}, html_options = {})
|
345
|
+
@template.select(@object_name, method, choices, options.merge(:object => @object), html_options)
|
346
|
+
end
|
347
|
+
|
348
|
+
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
|
349
|
+
@template.collection_select(@object_name, method, collection, value_method, text_method, options.merge(:object => @object), html_options)
|
350
|
+
end
|
351
|
+
|
352
|
+
def country_select(method, priority_countries = nil, options = {}, html_options = {})
|
353
|
+
@template.country_select(@object_name, method, priority_countries, options.merge(:object => @object), html_options)
|
354
|
+
end
|
355
|
+
|
356
|
+
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
|
357
|
+
@template.time_zone_select(@object_name, method, priority_zones, options.merge(:object => @object), html_options)
|
358
|
+
end
|
359
|
+
end
|
338
360
|
end
|
339
361
|
end
|