actionpack 2.3.4 → 2.3.5
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 +12 -0
- data/Rakefile +1 -1
- data/lib/action_controller.rb +3 -1
- data/lib/action_controller/assertions/dom_assertions.rb +19 -3
- data/lib/action_controller/assertions/selector_assertions.rb +16 -10
- data/lib/action_controller/base.rb +1 -1
- data/lib/action_controller/caching.rb +1 -0
- data/lib/action_controller/cookies.rb +2 -1
- data/lib/action_controller/http_authentication.rb +3 -2
- data/lib/action_controller/integration.rb +15 -3
- data/lib/action_controller/layout.rb +6 -1
- data/lib/action_controller/middlewares.rb +2 -0
- data/lib/action_controller/polymorphic_routes.rb +6 -21
- data/lib/action_controller/rack_lint_patch.rb +36 -0
- data/lib/action_controller/request_forgery_protection.rb +6 -2
- data/lib/action_controller/response.rb +2 -1
- data/lib/action_controller/string_coercion.rb +29 -0
- data/lib/action_controller/test_case.rb +6 -1
- data/lib/action_controller/test_process.rb +1 -1
- data/lib/action_controller/translation.rb +2 -2
- data/lib/action_controller/uploaded_file.rb +2 -2
- data/lib/action_controller/vendor/html-scanner/html/node.rb +1 -1
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_view.rb +3 -3
- data/lib/action_view/base.rb +6 -1
- data/lib/action_view/erb/util.rb +6 -0
- data/lib/action_view/helpers.rb +2 -0
- data/lib/action_view/helpers/active_record_helper.rb +3 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +2 -2
- data/lib/action_view/helpers/capture_helper.rb +2 -2
- data/lib/action_view/helpers/date_helper.rb +27 -15
- data/lib/action_view/helpers/form_helper.rb +32 -11
- data/lib/action_view/helpers/form_options_helper.rb +1 -1
- data/lib/action_view/helpers/form_tag_helper.rb +3 -3
- data/lib/action_view/helpers/number_helper.rb +6 -1
- data/lib/action_view/helpers/prototype_helper.rb +1 -1
- data/lib/action_view/helpers/raw_output_helper.rb +9 -0
- data/lib/action_view/helpers/sanitize_helper.rb +10 -2
- data/lib/action_view/helpers/tag_helper.rb +4 -4
- data/lib/action_view/helpers/translation_helper.rb +1 -1
- data/lib/action_view/helpers/url_helper.rb +3 -3
- data/lib/action_view/locale/en.yml +3 -0
- data/lib/action_view/partials.rb +1 -1
- data/lib/action_view/safe_buffer.rb +28 -0
- data/lib/action_view/template.rb +8 -2
- data/lib/action_view/test_case.rb +102 -27
- data/lib/actionpack.rb +1 -0
- data/test/controller/cookie_test.rb +7 -0
- data/test/controller/dom_assertions_test.rb +53 -0
- data/test/controller/filter_params_test.rb +1 -0
- data/test/controller/html-scanner/sanitizer_test.rb +1 -0
- data/test/controller/http_digest_authentication_test.rb +22 -0
- data/test/controller/integration_test.rb +38 -0
- data/test/controller/layout_test.rb +11 -0
- data/test/controller/polymorphic_routes_test.rb +4 -0
- data/test/controller/request_forgery_protection_test.rb +19 -1
- data/test/controller/routing_test.rb +23 -15
- data/test/controller/session/test_session_test.rb +2 -2
- data/test/fixtures/layout_tests/abs_path_layout.rhtml +1 -0
- data/test/fixtures/test/_from_helper.erb +1 -0
- data/test/template/active_record_helper_test.rb +1 -1
- data/test/template/asset_tag_helper_test.rb +12 -0
- data/test/template/benchmark_helper_test.rb +6 -6
- data/test/template/compiled_templates_test.rb +2 -1
- data/test/template/date_helper_i18n_test.rb +10 -9
- data/test/template/date_helper_test.rb +29 -13
- data/test/template/form_helper_test.rb +90 -10
- data/test/template/number_helper_test.rb +4 -0
- data/test/template/raw_output_helper_test.rb +21 -0
- data/test/template/sanitize_helper_test.rb +10 -1
- data/test/template/tag_helper_test.rb +1 -0
- data/test/view/safe_buffer_test.rb +36 -0
- data/test/view/test_case_test.rb +173 -5
- metadata +13 -4
@@ -105,6 +105,11 @@ module ActionController
|
|
105
105
|
class TestCase < ActiveSupport::TestCase
|
106
106
|
include TestProcess
|
107
107
|
|
108
|
+
def initialize(*args)
|
109
|
+
super
|
110
|
+
@controller = nil
|
111
|
+
end
|
112
|
+
|
108
113
|
module Assertions
|
109
114
|
%w(response selector tag dom routing model).each do |kind|
|
110
115
|
include ActionController::Assertions.const_get("#{kind.camelize}Assertions")
|
@@ -195,7 +200,7 @@ module ActionController
|
|
195
200
|
@controller.send(:initialize_current_url)
|
196
201
|
end
|
197
202
|
end
|
198
|
-
|
203
|
+
|
199
204
|
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
|
200
205
|
def rescue_action_in_public!
|
201
206
|
@request.remote_addr = '208.77.188.166' # example.com
|
@@ -91,7 +91,7 @@ module ActionController #:nodoc:
|
|
91
91
|
@path || super()
|
92
92
|
end
|
93
93
|
|
94
|
-
def assign_parameters(controller_path, action, parameters)
|
94
|
+
def assign_parameters(controller_path, action, parameters = {})
|
95
95
|
parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action)
|
96
96
|
extra_keys = ActionController::Routing::Routes.extra_keys(parameters)
|
97
97
|
non_path_parameters = get? ? query_parameters : request_parameters
|
@@ -3,14 +3,14 @@ module ActionController
|
|
3
3
|
def self.included(base)
|
4
4
|
base.class_eval do
|
5
5
|
attr_accessor :original_path, :content_type
|
6
|
-
alias_method :local_path, :path
|
6
|
+
alias_method :local_path, :path if method_defined?(:path)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.extended(object)
|
11
11
|
object.class_eval do
|
12
12
|
attr_accessor :original_path, :content_type
|
13
|
-
alias_method :local_path, :path
|
13
|
+
alias_method :local_path, :path if method_defined?(:path)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -162,7 +162,7 @@ module HTML #:nodoc:
|
|
162
162
|
end
|
163
163
|
|
164
164
|
closing = ( scanner.scan(/\//) ? :close : nil )
|
165
|
-
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[\
|
165
|
+
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[-:\w\x00-\x09\x0b-\x0c\x0e-\x1f]+/)
|
166
166
|
name.downcase!
|
167
167
|
|
168
168
|
unless closing
|
data/lib/action_pack/version.rb
CHANGED
data/lib/action_view.rb
CHANGED
@@ -49,10 +49,10 @@ module ActionView
|
|
49
49
|
autoload :TemplateHandler, 'action_view/template_handler'
|
50
50
|
autoload :TemplateHandlers, 'action_view/template_handlers'
|
51
51
|
autoload :Helpers, 'action_view/helpers'
|
52
|
+
autoload :SafeBuffer, 'action_view/safe_buffer'
|
52
53
|
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
end
|
55
|
+
require 'action_view/erb/util'
|
56
|
+
|
57
57
|
|
58
58
|
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
|
data/lib/action_view/base.rb
CHANGED
@@ -187,13 +187,18 @@ module ActionView #:nodoc:
|
|
187
187
|
@@cache_template_loading = nil
|
188
188
|
cattr_accessor :cache_template_loading
|
189
189
|
|
190
|
+
# :nodoc:
|
191
|
+
def self.xss_safe?
|
192
|
+
false
|
193
|
+
end
|
194
|
+
|
190
195
|
def self.cache_template_loading?
|
191
196
|
ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading)
|
192
197
|
end
|
193
198
|
|
194
199
|
attr_internal :request
|
195
200
|
|
196
|
-
delegate :request_forgery_protection_token, :
|
201
|
+
delegate :request_forgery_protection_token, :params, :session, :cookies, :response, :headers,
|
197
202
|
:flash, :logger, :action_name, :controller_name, :to => :controller
|
198
203
|
|
199
204
|
module CompiledTemplates #:nodoc:
|
data/lib/action_view/erb/util.rb
CHANGED
@@ -18,6 +18,12 @@ class ERB
|
|
18
18
|
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
|
19
19
|
end
|
20
20
|
|
21
|
+
undef :h
|
22
|
+
alias h html_escape
|
23
|
+
|
24
|
+
module_function :html_escape
|
25
|
+
module_function :h
|
26
|
+
|
21
27
|
# A utility method for escaping HTML entities in JSON strings.
|
22
28
|
# This method is also aliased as <tt>j</tt>.
|
23
29
|
#
|
data/lib/action_view/helpers.rb
CHANGED
@@ -14,6 +14,7 @@ module ActionView #:nodoc:
|
|
14
14
|
autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper'
|
15
15
|
autoload :NumberHelper, 'action_view/helpers/number_helper'
|
16
16
|
autoload :PrototypeHelper, 'action_view/helpers/prototype_helper'
|
17
|
+
autoload :RawOutputHelper, 'action_view/helpers/raw_output_helper'
|
17
18
|
autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper'
|
18
19
|
autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper'
|
19
20
|
autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper'
|
@@ -45,6 +46,7 @@ module ActionView #:nodoc:
|
|
45
46
|
include JavaScriptHelper
|
46
47
|
include NumberHelper
|
47
48
|
include PrototypeHelper
|
49
|
+
include RawOutputHelper
|
48
50
|
include RecordIdentificationHelper
|
49
51
|
include RecordTagHelper
|
50
52
|
include SanitizeHelper
|
@@ -3,7 +3,7 @@ require 'action_view/helpers/form_helper'
|
|
3
3
|
|
4
4
|
module ActionView
|
5
5
|
class Base
|
6
|
-
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>" }
|
6
|
+
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe! }
|
7
7
|
cattr_accessor :field_error_proc
|
8
8
|
end
|
9
9
|
|
@@ -171,7 +171,7 @@ module ActionView
|
|
171
171
|
options = params.extract_options!.symbolize_keys
|
172
172
|
|
173
173
|
if object = options.delete(:object)
|
174
|
-
objects =
|
174
|
+
objects = Array.wrap(object)
|
175
175
|
else
|
176
176
|
objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact
|
177
177
|
end
|
@@ -290,7 +290,7 @@ module ActionView
|
|
290
290
|
end
|
291
291
|
|
292
292
|
def error_wrapping(html_tag, has_error)
|
293
|
-
has_error ? Base.field_error_proc.call(html_tag, self) : html_tag
|
293
|
+
has_error ? Base.field_error_proc.call(html_tag, self).html_safe! : html_tag
|
294
294
|
end
|
295
295
|
|
296
296
|
def error_message
|
@@ -285,7 +285,7 @@ module ActionView
|
|
285
285
|
end
|
286
286
|
javascript_src_tag(joined_javascript_name, options)
|
287
287
|
else
|
288
|
-
expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n")
|
288
|
+
expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe!
|
289
289
|
end
|
290
290
|
end
|
291
291
|
|
@@ -434,7 +434,7 @@ module ActionView
|
|
434
434
|
end
|
435
435
|
stylesheet_tag(joined_stylesheet_name, options)
|
436
436
|
else
|
437
|
-
expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n")
|
437
|
+
expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe!
|
438
438
|
end
|
439
439
|
end
|
440
440
|
|
@@ -118,13 +118,13 @@ module ActionView
|
|
118
118
|
def content_for(name, content = nil, &block)
|
119
119
|
ivar = "@content_for_#{name}"
|
120
120
|
content = capture(&block) if block_given?
|
121
|
-
instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}")
|
121
|
+
instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}".html_safe!)
|
122
122
|
nil
|
123
123
|
end
|
124
124
|
|
125
125
|
# Use an alternate output buffer for the duration of the block.
|
126
126
|
# Defaults to a new empty string.
|
127
|
-
def with_output_buffer(buf =
|
127
|
+
def with_output_buffer(buf = "") #:nodoc:
|
128
128
|
self.output_buffer, old_buffer = buf, output_buffer
|
129
129
|
yield
|
130
130
|
output_buffer
|
@@ -26,8 +26,10 @@ module ActionView
|
|
26
26
|
# 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
|
27
27
|
# 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
|
28
28
|
# 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
|
29
|
-
# 1 yr <->
|
30
|
-
#
|
29
|
+
# 1 yr <-> 1 yr, 3 months # => about 1 year
|
30
|
+
# 1 yr, 3 months <-> 1 yr, 9 months # => over 1 year
|
31
|
+
# 1 yr, 9 months <-> 2 yr minus 1 sec # => almost 2 years
|
32
|
+
# 2 yrs <-> max time or date # => (same rules as 1 yr)
|
31
33
|
#
|
32
34
|
# With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds:
|
33
35
|
# 0-4 secs # => less than 5 seconds
|
@@ -43,17 +45,18 @@ module ActionView
|
|
43
45
|
# distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
|
44
46
|
# distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
|
45
47
|
# distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds
|
46
|
-
# distance_of_time_in_words(from_time, 3.years.from_now) # =>
|
48
|
+
# distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years
|
47
49
|
# distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days
|
48
50
|
# distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute
|
49
51
|
# distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute
|
50
52
|
# distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
|
51
53
|
# distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
|
52
|
-
# distance_of_time_in_words(from_time, from_time +
|
54
|
+
# distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years
|
55
|
+
# distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years
|
53
56
|
#
|
54
57
|
# to_time = Time.now + 6.years + 19.days
|
55
|
-
# distance_of_time_in_words(from_time, to_time, true) # =>
|
56
|
-
# distance_of_time_in_words(to_time, from_time, true) # =>
|
58
|
+
# distance_of_time_in_words(from_time, to_time, true) # => about 6 years
|
59
|
+
# distance_of_time_in_words(to_time, from_time, true) # => about 6 years
|
57
60
|
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
|
58
61
|
#
|
59
62
|
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
|
@@ -81,12 +84,21 @@ module ActionView
|
|
81
84
|
when 2..44 then locale.t :x_minutes, :count => distance_in_minutes
|
82
85
|
when 45..89 then locale.t :about_x_hours, :count => 1
|
83
86
|
when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
|
84
|
-
when 1440..
|
85
|
-
when
|
87
|
+
when 1440..2529 then locale.t :x_days, :count => 1
|
88
|
+
when 2530..43199 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round
|
86
89
|
when 43200..86399 then locale.t :about_x_months, :count => 1
|
87
|
-
when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes / 43200).round
|
88
|
-
|
89
|
-
|
90
|
+
when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
|
91
|
+
else
|
92
|
+
distance_in_years = distance_in_minutes / 525600
|
93
|
+
minute_offset_for_leap_year = (distance_in_years / 4) * 1440
|
94
|
+
remainder = ((distance_in_minutes - minute_offset_for_leap_year) % 525600)
|
95
|
+
if remainder < 131400
|
96
|
+
locale.t(:about_x_years, :count => distance_in_years)
|
97
|
+
elsif remainder < 394200
|
98
|
+
locale.t(:over_x_years, :count => distance_in_years)
|
99
|
+
else
|
100
|
+
locale.t(:almost_x_years, :count => distance_in_years + 1)
|
101
|
+
end
|
90
102
|
end
|
91
103
|
end
|
92
104
|
end
|
@@ -904,15 +916,15 @@ module ActionView
|
|
904
916
|
|
905
917
|
class InstanceTag #:nodoc:
|
906
918
|
def to_date_select_tag(options = {}, html_options = {})
|
907
|
-
datetime_selector(options, html_options).select_date
|
919
|
+
datetime_selector(options, html_options).select_date.html_safe!
|
908
920
|
end
|
909
921
|
|
910
922
|
def to_time_select_tag(options = {}, html_options = {})
|
911
|
-
datetime_selector(options, html_options).select_time
|
923
|
+
datetime_selector(options, html_options).select_time.html_safe!
|
912
924
|
end
|
913
925
|
|
914
926
|
def to_datetime_select_tag(options = {}, html_options = {})
|
915
|
-
datetime_selector(options, html_options).select_datetime
|
927
|
+
datetime_selector(options, html_options).select_datetime.html_safe!
|
916
928
|
end
|
917
929
|
|
918
930
|
private
|
@@ -923,7 +935,7 @@ module ActionView
|
|
923
935
|
options[:field_name] = @method_name
|
924
936
|
options[:include_position] = true
|
925
937
|
options[:prefix] ||= @object_name
|
926
|
-
options[:index] = @auto_index if @auto_index && !options.has_key?(:index)
|
938
|
+
options[:index] = @auto_index if defined?(@auto_index) && @auto_index && !options.has_key?(:index)
|
927
939
|
options[:datetime_separator] ||= ' — '
|
928
940
|
options[:time_separator] ||= ' : '
|
929
941
|
|
@@ -280,7 +280,7 @@ module ActionView
|
|
280
280
|
|
281
281
|
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
|
282
282
|
fields_for(object_name, *(args << options), &proc)
|
283
|
-
concat('</form>')
|
283
|
+
concat('</form>'.html_safe!)
|
284
284
|
end
|
285
285
|
|
286
286
|
def apply_form_for_options!(object_or_array, options) #:nodoc:
|
@@ -445,6 +445,15 @@ module ActionView
|
|
445
445
|
# <% end %>
|
446
446
|
# <% end %>
|
447
447
|
#
|
448
|
+
# Or a collection to be used:
|
449
|
+
#
|
450
|
+
# <% form_for @person, :url => { :action => "update" } do |person_form| %>
|
451
|
+
# ...
|
452
|
+
# <% person_form.fields_for :projects, @active_projects do |project_fields| %>
|
453
|
+
# Name: <%= project_fields.text_field :name %>
|
454
|
+
# <% end %>
|
455
|
+
# <% end %>
|
456
|
+
#
|
448
457
|
# When projects is already an association on Person you can use
|
449
458
|
# +accepts_nested_attributes_for+ to define the writer method for you:
|
450
459
|
#
|
@@ -788,7 +797,7 @@ module ActionView
|
|
788
797
|
add_default_name_and_id(options)
|
789
798
|
hidden = tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value)
|
790
799
|
checkbox = tag("input", options)
|
791
|
-
hidden + checkbox
|
800
|
+
(hidden + checkbox).html_safe!
|
792
801
|
end
|
793
802
|
|
794
803
|
def to_boolean_select_tag(options = {})
|
@@ -930,7 +939,7 @@ module ActionView
|
|
930
939
|
end
|
931
940
|
end
|
932
941
|
|
933
|
-
(field_helpers - %w(label check_box radio_button fields_for)).each do |selector|
|
942
|
+
(field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector|
|
934
943
|
src = <<-end_src
|
935
944
|
def #{selector}(method, options = {}) # def text_field(method, options = {})
|
936
945
|
@template.send( # @template.send(
|
@@ -989,6 +998,11 @@ module ActionView
|
|
989
998
|
def radio_button(method, tag_value, options = {})
|
990
999
|
@template.radio_button(@object_name, method, tag_value, objectify_options(options))
|
991
1000
|
end
|
1001
|
+
|
1002
|
+
def hidden_field(method, options = {})
|
1003
|
+
@emitted_hidden_id = true if method == :id
|
1004
|
+
@template.hidden_field(@object_name, method, objectify_options(options))
|
1005
|
+
end
|
992
1006
|
|
993
1007
|
def error_message_on(method, *args)
|
994
1008
|
@template.error_message_on(@object, method, *args)
|
@@ -1002,6 +1016,10 @@ module ActionView
|
|
1002
1016
|
@template.submit_tag(value, options.reverse_merge(:id => "#{object_name}_submit"))
|
1003
1017
|
end
|
1004
1018
|
|
1019
|
+
def emitted_hidden_id?
|
1020
|
+
@emitted_hidden_id
|
1021
|
+
end
|
1022
|
+
|
1005
1023
|
private
|
1006
1024
|
def objectify_options(options)
|
1007
1025
|
@default_options.merge(options.merge(:object => @object))
|
@@ -1013,18 +1031,21 @@ module ActionView
|
|
1013
1031
|
|
1014
1032
|
def fields_for_with_nested_attributes(association_name, args, block)
|
1015
1033
|
name = "#{object_name}[#{association_name}_attributes]"
|
1016
|
-
association =
|
1017
|
-
|
1034
|
+
association = args.first
|
1035
|
+
|
1036
|
+
if association.respond_to?(:new_record?)
|
1037
|
+
association = [association] if @object.send(association_name).is_a?(Array)
|
1038
|
+
elsif !association.is_a?(Array)
|
1039
|
+
association = @object.send(association_name)
|
1040
|
+
end
|
1018
1041
|
|
1019
1042
|
if association.is_a?(Array)
|
1020
|
-
children = explicit_object ? [explicit_object] : association
|
1021
1043
|
explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash)
|
1022
|
-
|
1023
|
-
children.map do |child|
|
1044
|
+
association.map do |child|
|
1024
1045
|
fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block)
|
1025
1046
|
end.join
|
1026
|
-
|
1027
|
-
fields_for_nested_model(name,
|
1047
|
+
elsif association
|
1048
|
+
fields_for_nested_model(name, association, args, block)
|
1028
1049
|
end
|
1029
1050
|
end
|
1030
1051
|
|
@@ -1033,8 +1054,8 @@ module ActionView
|
|
1033
1054
|
@template.fields_for(name, object, *args, &block)
|
1034
1055
|
else
|
1035
1056
|
@template.fields_for(name, object, *args) do |builder|
|
1036
|
-
@template.concat builder.hidden_field(:id)
|
1037
1057
|
block.call(builder)
|
1058
|
+
@template.concat builder.hidden_field(:id) unless builder.emitted_hidden_id?
|
1038
1059
|
end
|
1039
1060
|
end
|
1040
1061
|
end
|
@@ -296,7 +296,7 @@ module ActionView
|
|
296
296
|
options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>)
|
297
297
|
end
|
298
298
|
|
299
|
-
options_for_select.join("\n")
|
299
|
+
options_for_select.join("\n").html_safe!
|
300
300
|
end
|
301
301
|
|
302
302
|
# Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
|
@@ -432,7 +432,7 @@ module ActionView
|
|
432
432
|
concat(tag(:fieldset, options, true))
|
433
433
|
concat(content_tag(:legend, legend)) unless legend.blank?
|
434
434
|
concat(content)
|
435
|
-
concat("</fieldset>")
|
435
|
+
concat("</fieldset>".html_safe!)
|
436
436
|
end
|
437
437
|
|
438
438
|
private
|
@@ -459,14 +459,14 @@ module ActionView
|
|
459
459
|
|
460
460
|
def form_tag_html(html_options)
|
461
461
|
extra_tags = extra_tags_for_form(html_options)
|
462
|
-
tag(:form, html_options, true) + extra_tags
|
462
|
+
(tag(:form, html_options, true) + extra_tags).html_safe!
|
463
463
|
end
|
464
464
|
|
465
465
|
def form_tag_in_block(html_options, &block)
|
466
466
|
content = capture(&block)
|
467
467
|
concat(form_tag_html(html_options))
|
468
468
|
concat(content)
|
469
|
-
concat("</form>")
|
469
|
+
concat("</form>".html_safe!)
|
470
470
|
end
|
471
471
|
|
472
472
|
def token_tag
|
@@ -246,6 +246,11 @@ module ActionView
|
|
246
246
|
# number_to_human_size(483989, :precision => 0) # => 473 KB
|
247
247
|
# number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
|
248
248
|
#
|
249
|
+
# Zeros after the decimal point are always stripped out, regardless of the
|
250
|
+
# specified precision:
|
251
|
+
# helper.number_to_human_size(1234567890123, :precision => 5) # => "1.12283 TB"
|
252
|
+
# helper.number_to_human_size(524288000, :precision=>5) # => "500 MB"
|
253
|
+
#
|
249
254
|
# You can still use <tt>number_to_human_size</tt> with the old API that accepts the
|
250
255
|
# +precision+ as its optional second parameter:
|
251
256
|
# number_to_human_size(1234567, 2) # => 1.18 MB
|
@@ -291,7 +296,7 @@ module ActionView
|
|
291
296
|
:precision => precision,
|
292
297
|
:separator => separator,
|
293
298
|
:delimiter => delimiter
|
294
|
-
).sub(/(
|
299
|
+
).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
|
295
300
|
storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
|
296
301
|
rescue
|
297
302
|
number
|