actionpack 3.0.0.beta → 3.0.0.beta2

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.

Files changed (118) hide show
  1. data/CHANGELOG +291 -260
  2. data/lib/abstract_controller.rb +5 -2
  3. data/lib/abstract_controller/assigns.rb +21 -0
  4. data/lib/abstract_controller/base.rb +13 -5
  5. data/lib/abstract_controller/collector.rb +2 -0
  6. data/lib/abstract_controller/helpers.rb +4 -14
  7. data/lib/abstract_controller/layouts.rb +50 -99
  8. data/lib/abstract_controller/logger.rb +2 -2
  9. data/lib/abstract_controller/rendering.rb +105 -173
  10. data/lib/abstract_controller/view_paths.rb +69 -0
  11. data/lib/action_controller.rb +1 -2
  12. data/lib/action_controller/base.rb +10 -32
  13. data/lib/action_controller/caching.rb +19 -18
  14. data/lib/action_controller/caching/actions.rb +17 -11
  15. data/lib/action_controller/caching/fragments.rb +5 -17
  16. data/lib/action_controller/caching/pages.rb +24 -24
  17. data/lib/action_controller/caching/sweeping.rb +1 -3
  18. data/lib/action_controller/deprecated.rb +0 -2
  19. data/lib/action_controller/deprecated/base.rb +143 -0
  20. data/lib/action_controller/metal.rb +29 -26
  21. data/lib/action_controller/metal/compatibility.rb +18 -87
  22. data/lib/action_controller/metal/cookies.rb +0 -1
  23. data/lib/action_controller/metal/head.rb +1 -0
  24. data/lib/action_controller/metal/helpers.rb +2 -2
  25. data/lib/action_controller/metal/hide_actions.rb +4 -6
  26. data/lib/action_controller/metal/http_authentication.rb +18 -33
  27. data/lib/action_controller/metal/implicit_render.rb +21 -0
  28. data/lib/action_controller/metal/instrumentation.rb +1 -1
  29. data/lib/action_controller/metal/mime_responds.rb +2 -1
  30. data/lib/action_controller/metal/rack_delegation.rb +3 -8
  31. data/lib/action_controller/metal/redirecting.rb +2 -1
  32. data/lib/action_controller/metal/renderers.rb +4 -2
  33. data/lib/action_controller/metal/rendering.rb +31 -44
  34. data/lib/action_controller/metal/request_forgery_protection.rb +41 -4
  35. data/lib/action_controller/metal/responder.rb +2 -0
  36. data/lib/action_controller/metal/session_management.rb +0 -36
  37. data/lib/action_controller/metal/streaming.rb +20 -47
  38. data/lib/action_controller/metal/testing.rb +0 -1
  39. data/lib/action_controller/metal/url_for.rb +11 -148
  40. data/lib/action_controller/middleware.rb +2 -1
  41. data/lib/action_controller/polymorphic_routes.rb +1 -2
  42. data/lib/action_controller/railtie.rb +63 -10
  43. data/lib/action_controller/railties/{subscriber.rb → log_subscriber.rb} +5 -12
  44. data/lib/action_controller/railties/url_helpers.rb +14 -0
  45. data/lib/action_controller/record_identifier.rb +20 -1
  46. data/lib/action_controller/test_case.rb +123 -12
  47. data/lib/action_dispatch.rb +1 -0
  48. data/lib/action_dispatch/http/cache.rb +20 -3
  49. data/lib/action_dispatch/http/filter_parameters.rb +40 -25
  50. data/lib/action_dispatch/http/mime_negotiation.rb +6 -17
  51. data/lib/action_dispatch/http/mime_type.rb +2 -7
  52. data/lib/action_dispatch/http/request.rb +12 -33
  53. data/lib/action_dispatch/http/response.rb +35 -15
  54. data/lib/action_dispatch/http/upload.rb +2 -0
  55. data/lib/action_dispatch/http/url.rb +5 -32
  56. data/lib/action_dispatch/middleware/callbacks.rb +1 -1
  57. data/lib/action_dispatch/middleware/cookies.rb +4 -3
  58. data/lib/action_dispatch/middleware/params_parser.rb +4 -3
  59. data/lib/action_dispatch/middleware/remote_ip.rb +51 -0
  60. data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -0
  61. data/lib/action_dispatch/middleware/session/cookie_store.rb +6 -8
  62. data/lib/action_dispatch/middleware/show_exceptions.rb +0 -14
  63. data/lib/action_dispatch/middleware/stack.rb +6 -2
  64. data/lib/action_dispatch/railtie.rb +3 -1
  65. data/lib/action_dispatch/routing.rb +2 -0
  66. data/lib/action_dispatch/routing/deprecated_mapper.rb +35 -7
  67. data/lib/action_dispatch/routing/mapper.rb +134 -48
  68. data/lib/action_dispatch/routing/route.rb +2 -2
  69. data/lib/action_dispatch/routing/route_set.rb +217 -158
  70. data/lib/action_dispatch/routing/url_for.rb +139 -0
  71. data/lib/action_dispatch/testing/assertions/response.rb +14 -61
  72. data/lib/action_dispatch/testing/assertions/routing.rb +25 -14
  73. data/lib/action_dispatch/testing/integration.rb +32 -50
  74. data/lib/action_dispatch/testing/performance_test.rb +3 -1
  75. data/lib/action_dispatch/testing/test_process.rb +2 -0
  76. data/lib/action_dispatch/testing/test_request.rb +2 -0
  77. data/lib/action_pack/version.rb +4 -3
  78. data/lib/action_view.rb +11 -6
  79. data/lib/action_view/base.rb +33 -121
  80. data/lib/action_view/context.rb +0 -2
  81. data/lib/action_view/helpers.rb +26 -23
  82. data/lib/action_view/helpers/active_model_helper.rb +28 -18
  83. data/lib/action_view/helpers/asset_tag_helper.rb +109 -54
  84. data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
  85. data/lib/action_view/helpers/cache_helper.rb +22 -1
  86. data/lib/action_view/helpers/capture_helper.rb +22 -22
  87. data/lib/action_view/helpers/date_helper.rb +6 -5
  88. data/lib/action_view/helpers/form_helper.rb +78 -63
  89. data/lib/action_view/helpers/form_options_helper.rb +6 -4
  90. data/lib/action_view/helpers/form_tag_helper.rb +26 -15
  91. data/lib/action_view/helpers/javascript_helper.rb +90 -10
  92. data/lib/action_view/helpers/number_helper.rb +315 -118
  93. data/lib/action_view/helpers/prototype_helper.rb +19 -46
  94. data/lib/action_view/helpers/record_tag_helper.rb +4 -4
  95. data/lib/action_view/helpers/tag_helper.rb +7 -24
  96. data/lib/action_view/helpers/text_helper.rb +8 -7
  97. data/lib/action_view/helpers/translation_helper.rb +7 -5
  98. data/lib/action_view/helpers/url_helper.rb +19 -16
  99. data/lib/action_view/locale/en.yml +45 -6
  100. data/lib/action_view/lookup_context.rb +190 -0
  101. data/lib/action_view/paths.rb +22 -63
  102. data/lib/action_view/railtie.rb +14 -4
  103. data/lib/action_view/railties/{subscriber.rb → log_subscriber.rb} +1 -1
  104. data/lib/action_view/render/layouts.rb +73 -0
  105. data/lib/action_view/render/partials.rb +15 -41
  106. data/lib/action_view/render/rendering.rb +27 -78
  107. data/lib/action_view/template.rb +20 -24
  108. data/lib/action_view/template/error.rb +22 -2
  109. data/lib/action_view/template/handlers/erb.rb +33 -9
  110. data/lib/action_view/template/handlers/rjs.rb +1 -2
  111. data/lib/action_view/template/resolver.rb +46 -104
  112. data/lib/action_view/template/text.rb +5 -12
  113. data/lib/action_view/test_case.rb +14 -23
  114. metadata +83 -40
  115. data/lib/abstract_controller/compatibility.rb +0 -18
  116. data/lib/abstract_controller/localized_cache.rb +0 -49
  117. data/lib/action_controller/metal/configuration.rb +0 -28
  118. data/lib/action_controller/url_rewriter.rb +0 -76
@@ -1,7 +1,7 @@
1
1
  require 'active_support/testing/performance'
2
2
  require 'active_support/testing/default'
3
3
 
4
- if defined?(ActiveSupport::Testing::Performance)
4
+ begin
5
5
  module ActionDispatch
6
6
  # An integration test that runs a code profiler on your test methods.
7
7
  # Profiling output for combinations of each test method, measurement, and
@@ -14,4 +14,6 @@ if defined?(ActiveSupport::Testing::Performance)
14
14
  include ActiveSupport::Testing::Default
15
15
  end
16
16
  end
17
+ rescue NameError
18
+ $stderr.puts "Specify ruby-prof as application's dependency in Gemfile to run benchmarks."
17
19
  end
@@ -1,3 +1,5 @@
1
+ require 'action_dispatch/middleware/flash'
2
+
1
3
  module ActionDispatch
2
4
  module TestProcess
3
5
  def assigns(key = nil)
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
1
3
  module ActionDispatch
2
4
  class TestRequest < Request
3
5
  DEFAULT_ENV = Rack::MockRequest.env_for('/')
@@ -1,9 +1,10 @@
1
- module ActionPack #:nodoc:
1
+ module ActionPack
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 0
5
- TINY = "0.beta"
5
+ TINY = 0
6
+ BUILD = "beta2"
6
7
 
7
- STRING = [MAJOR, MINOR, TINY].join('.')
8
+ STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
8
9
  end
9
10
  end
@@ -37,17 +37,22 @@ module ActionView
37
37
  autoload :Helpers
38
38
 
39
39
  autoload_under "render" do
40
+ autoload :Layouts
40
41
  autoload :Partials
41
42
  autoload :Rendering
42
43
  end
43
44
 
44
- autoload :MissingTemplate, 'action_view/base'
45
- autoload :Resolver, 'action_view/template/resolver'
46
- autoload :PathResolver, 'action_view/template/resolver'
47
- autoload :PathSet, 'action_view/paths'
48
- autoload :FileSystemResolverWithFallback, 'action_view/template/resolver'
45
+ autoload :Base
46
+ autoload :LookupContext
47
+ autoload :Resolver, 'action_view/template/resolver'
48
+ autoload :PathResolver, 'action_view/template/resolver'
49
+ autoload :FileSystemResolver, 'action_view/template/resolver'
50
+ autoload :PathSet, 'action_view/paths'
49
51
 
52
+ autoload :MissingTemplate, 'action_view/template/error'
53
+ autoload :ActionViewError, 'action_view/template/error'
50
54
  autoload :TemplateError, 'action_view/template/error'
55
+
51
56
  autoload :TemplateHandler, 'action_view/template'
52
57
  autoload :TemplateHandlers, 'action_view/template'
53
58
  end
@@ -55,7 +60,7 @@ module ActionView
55
60
  autoload :TestCase, 'action_view/test_case'
56
61
  end
57
62
 
63
+ require 'active_support/i18n'
58
64
  require 'active_support/core_ext/string/output_safety'
59
- require 'action_view/base'
60
65
 
61
66
  I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
@@ -1,27 +1,10 @@
1
1
  require 'active_support/core_ext/module/attr_internal'
2
2
  require 'active_support/core_ext/module/delegation'
3
3
  require 'active_support/core_ext/class/attribute'
4
+ require 'active_support/core_ext/array/wrap'
4
5
 
5
6
  module ActionView #:nodoc:
6
- class ActionViewError < StandardError #:nodoc:
7
- end
8
-
9
- class MissingTemplate < ActionViewError #:nodoc:
10
- attr_reader :path
11
-
12
- def initialize(paths, path, details, partial)
13
- @path = path
14
- display_paths = paths.compact.join(":")
15
- template_type = if partial
16
- "partial"
17
- elsif path =~ /layouts/i
18
- 'layout'
19
- else
20
- 'template'
21
- end
22
-
23
- super("Missing #{template_type} #{path} with #{details.inspect} in view path #{display_paths}")
24
- end
7
+ class NonConcattingString < ActiveSupport::SafeBuffer
25
8
  end
26
9
 
27
10
  # Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb
@@ -173,128 +156,66 @@ module ActionView #:nodoc:
173
156
  module Subclasses
174
157
  end
175
158
 
176
- include Helpers, Rendering, Partials, ::ERB::Util
177
-
178
- def config
179
- self.config = DEFAULT_CONFIG unless @config
180
- @config
181
- end
159
+ include Helpers, Rendering, Partials, Layouts, ::ERB::Util, Context
160
+ extend ActiveSupport::Memoizable
182
161
 
183
- def config=(config)
184
- @config = ActiveSupport::OrderedOptions.new.merge(config)
185
- end
186
-
187
- extend ActiveSupport::Memoizable
188
-
189
- attr_accessor :base_path, :assigns, :template_extension, :formats
190
- attr_internal :captures
191
-
192
- def reset_formats(formats)
193
- @formats = formats
194
-
195
- if defined?(AbstractController::HashKey)
196
- # This is expensive, but we need to reset this when the format is updated,
197
- # which currently only happens
198
- Thread.current[:format_locale_key] =
199
- AbstractController::HashKey.get(self.class, formats, I18n.locale)
200
- end
201
- end
202
-
203
- class << self
204
- delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
205
- delegate :logger, :to => 'ActionController::Base', :allow_nil => true
206
- end
207
-
208
- @@debug_rjs = false
209
- ##
210
- # :singleton-method:
211
162
  # Specify whether RJS responses should be wrapped in a try/catch block
212
163
  # that alert()s the caught exception (and then re-raises it).
213
164
  cattr_accessor :debug_rjs
165
+ @@debug_rjs = false
214
166
 
215
- # Specify whether templates should be cached. Otherwise the file we be read everytime it is accessed.
216
- # Automatically reloading templates are not thread safe and should only be used in development mode.
217
- @@cache_template_loading = nil
218
- cattr_accessor :cache_template_loading
167
+ class_attribute :helpers
168
+ remove_method :helpers
169
+ attr_reader :helpers
219
170
 
220
- # :nodoc:
221
- def self.xss_safe?
222
- true
171
+ class << self
172
+ delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
173
+ delegate :logger, :to => 'ActionController::Base', :allow_nil => true
223
174
  end
224
175
 
225
- def self.cache_template_loading?
226
- ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading)
227
- end
176
+ ActiveSupport.run_load_hooks(:action_view, self)
228
177
 
229
- attr_internal :request, :layout
178
+ attr_accessor :base_path, :assigns, :template_extension, :lookup_context
179
+ attr_internal :captures, :request, :controller, :template, :config
230
180
 
231
- def controller_path
232
- @controller_path ||= controller && controller.controller_path
233
- end
181
+ delegate :find_template, :template_exists?, :formats, :formats=, :locale, :locale=,
182
+ :view_paths, :view_paths=, :with_fallbacks, :update_details, :to => :lookup_context
234
183
 
235
184
  delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
236
185
  :flash, :action_name, :controller_name, :to => :controller
237
186
 
238
187
  delegate :logger, :to => :controller, :allow_nil => true
239
188
 
240
- delegate :find, :to => :view_paths
241
-
242
- include Context
243
-
244
- def self.process_view_paths(value)
245
- ActionView::PathSet.new(Array(value))
189
+ # TODO: HACK FOR RJS
190
+ def view_context
191
+ self
246
192
  end
247
193
 
248
- class_attribute :helpers
249
- attr_reader :helpers
250
-
251
- def self.for_controller(controller)
252
- @views ||= {}
253
-
254
- # TODO: Decouple this so helpers are a separate concern in AV just like
255
- # they are in AC.
256
- if controller.class.respond_to?(:_helper_serial)
257
- klass = @views[controller.class._helper_serial] ||= Class.new(self) do
258
- # Try to make stack traces clearer
259
- class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
260
- def self.name
261
- "ActionView for #{controller.class}"
262
- end
263
-
264
- def inspect
265
- "#<#{self.class.name}>"
266
- end
267
- ruby_eval
268
-
269
- if controller.respond_to?(:_helpers)
270
- include controller._helpers
271
- self.helpers = controller._helpers
272
- end
273
- end
274
- else
275
- klass = self
276
- end
194
+ def self.xss_safe? #:nodoc:
195
+ true
196
+ end
277
197
 
278
- klass.new(controller.class.view_paths, {}, controller)
198
+ def self.process_view_paths(value)
199
+ ActionView::PathSet.new(Array.wrap(value))
279
200
  end
280
201
 
281
- def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc:
202
+ def initialize(lookup_context = nil, assigns_for_first_render = {}, controller = nil, formats = nil) #:nodoc:
282
203
  @config = nil
283
- @formats = formats
284
204
  @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) }
285
205
  @helpers = self.class.helpers || Module.new
286
206
 
287
207
  @_controller = controller
288
- @_content_for = Hash.new {|h,k| h[k] = ActiveSupport::SafeBuffer.new }
208
+ @_config = ActiveSupport::InheritableOptions.new(controller.config) if controller && controller.respond_to?(:config)
209
+ @_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
289
210
  @_virtual_path = nil
290
- self.view_paths = view_paths
291
- end
292
211
 
293
- attr_internal :controller, :template
294
- attr_reader :view_paths
212
+ @lookup_context = lookup_context.is_a?(ActionView::LookupContext) ?
213
+ lookup_context : ActionView::LookupContext.new(lookup_context)
214
+ @lookup_context.formats = formats if formats
215
+ end
295
216
 
296
- def view_paths=(paths)
297
- @view_paths = self.class.process_view_paths(paths)
217
+ def controller_path
218
+ @controller_path ||= controller && controller.controller_path
298
219
  end
299
220
 
300
221
  def punctuate_body!(part)
@@ -302,14 +223,5 @@ module ActionView #:nodoc:
302
223
  response.body_parts << part
303
224
  nil
304
225
  end
305
-
306
- # Evaluates the local assigns and controller ivars, pushes them to the view.
307
- def _evaluate_assigns_and_ivars #:nodoc:
308
- if controller
309
- variables = controller.instance_variable_names
310
- variables -= controller.protected_instance_variables if controller.respond_to?(:protected_instance_variables)
311
- variables.each { |name| instance_variable_set(name, controller.instance_variable_get(name)) }
312
- end
313
- end
314
226
  end
315
227
  end
@@ -10,8 +10,6 @@ module ActionView
10
10
  # In order to work with ActionController, a Context
11
11
  # must implement:
12
12
  #
13
- # Context.for_controller[controller] Create a new ActionView instance for a
14
- # controller
15
13
  # Context#render_partial[options]
16
14
  # - responsible for setting options[:_template]
17
15
  # - Returns String with the rendered partial
@@ -2,29 +2,32 @@ require 'active_support/benchmarkable'
2
2
 
3
3
  module ActionView #:nodoc:
4
4
  module Helpers #:nodoc:
5
- autoload :ActiveModelHelper, 'action_view/helpers/active_model_helper'
6
- autoload :AssetTagHelper, 'action_view/helpers/asset_tag_helper'
7
- autoload :AtomFeedHelper, 'action_view/helpers/atom_feed_helper'
8
- autoload :CacheHelper, 'action_view/helpers/cache_helper'
9
- autoload :CaptureHelper, 'action_view/helpers/capture_helper'
10
- autoload :CsrfHelper, 'action_view/helpers/csrf_helper'
11
- autoload :DateHelper, 'action_view/helpers/date_helper'
12
- autoload :DebugHelper, 'action_view/helpers/debug_helper'
13
- autoload :FormHelper, 'action_view/helpers/form_helper'
14
- autoload :FormOptionsHelper, 'action_view/helpers/form_options_helper'
15
- autoload :FormTagHelper, 'action_view/helpers/form_tag_helper'
16
- autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper'
17
- autoload :NumberHelper, 'action_view/helpers/number_helper'
18
- autoload :PrototypeHelper, 'action_view/helpers/prototype_helper'
19
- autoload :RawOutputHelper, 'action_view/helpers/raw_output_helper'
20
- autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper'
21
- autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper'
22
- autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper'
23
- autoload :ScriptaculousHelper, 'action_view/helpers/scriptaculous_helper'
24
- autoload :TagHelper, 'action_view/helpers/tag_helper'
25
- autoload :TextHelper, 'action_view/helpers/text_helper'
26
- autoload :TranslationHelper, 'action_view/helpers/translation_helper'
27
- autoload :UrlHelper, 'action_view/helpers/url_helper'
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :ActiveModelHelper
8
+ autoload :AssetTagHelper
9
+ autoload :AtomFeedHelper
10
+ autoload :CacheHelper
11
+ autoload :CaptureHelper
12
+ autoload :CsrfHelper
13
+ autoload :DateHelper
14
+ autoload :DebugHelper
15
+ autoload :DeprecatedBlockHelpers
16
+ autoload :FormHelper
17
+ autoload :FormOptionsHelper
18
+ autoload :FormTagHelper
19
+ autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
20
+ autoload :NumberHelper
21
+ autoload :PrototypeHelper
22
+ autoload :RawOutputHelper
23
+ autoload :RecordIdentificationHelper
24
+ autoload :RecordTagHelper
25
+ autoload :SanitizeHelper
26
+ autoload :ScriptaculousHelper
27
+ autoload :TagHelper
28
+ autoload :TextHelper
29
+ autoload :TranslationHelper
30
+ autoload :UrlHelper
28
31
 
29
32
  def self.included(base)
30
33
  base.extend(ClassMethods)
@@ -3,11 +3,14 @@ require 'action_view/helpers/form_helper'
3
3
  require 'active_support/core_ext/class/attribute_accessors'
4
4
  require 'active_support/core_ext/enumerable'
5
5
  require 'active_support/core_ext/kernel/reporting'
6
+ require 'active_support/core_ext/object/blank'
6
7
 
7
8
  module ActionView
8
- class Base
9
- @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
10
- cattr_accessor :field_error_proc
9
+ ActiveSupport.on_load(:action_view) do
10
+ class ActionView::Base
11
+ @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
12
+ cattr_accessor :field_error_proc
13
+ end
11
14
  end
12
15
 
13
16
  module Helpers
@@ -80,13 +83,13 @@ module ActionView
80
83
  record = convert_to_model(record)
81
84
 
82
85
  options = options.symbolize_keys
83
- options[:action] ||= record.new_record? ? "create" : "update"
86
+ options[:action] ||= record.persisted? ? "update" : "create"
84
87
  action = url_for(:action => options[:action], :id => record)
85
88
 
86
89
  submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize
87
90
 
88
91
  contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil)
89
- contents.safe_concat hidden_field(record_name, :id) unless record.new_record?
92
+ contents.safe_concat hidden_field(record_name, :id) if record.persisted?
90
93
  contents.safe_concat all_input_tags(record, record_name, options)
91
94
  yield contents if block_given?
92
95
  contents.safe_concat submit_tag(submit_value)
@@ -94,10 +97,10 @@ module ActionView
94
97
  end
95
98
 
96
99
  # Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
97
- # This error message is wrapped in a <tt>DIV</tt> tag, which can be extended to include a <tt>:prepend_text</tt>
98
- # and/or <tt>:append_text</tt> (to properly explain the error), and a <tt>:css_class</tt> to style it
99
- # accordingly. +object+ should either be the name of an instance variable or the actual object. The method can be
100
- # passed in either as a string or a symbol.
100
+ # This error message is wrapped in a <tt>DIV</tt> tag by default or with <tt>:html_tag</tt> if specified,
101
+ # which can be extended to include a <tt>:prepend_text</tt> and/or <tt>:append_text</tt> (to properly explain
102
+ # the error), and a <tt>:css_class</tt> to style it accordingly. +object+ should either be the name of an
103
+ # instance variable or the actual object. The method can be passed in either as a string or a symbol.
101
104
  # As an example, let's say you have a model <tt>@post</tt> that has an error message on the +title+ attribute:
102
105
  #
103
106
  # <%= error_message_on "post", "title" %>
@@ -109,25 +112,28 @@ module ActionView
109
112
  # <%= error_message_on "post", "title",
110
113
  # :prepend_text => "Title simply ",
111
114
  # :append_text => " (or it won't work).",
115
+ # :html_tag => "span",
112
116
  # :css_class => "inputError" %>
117
+ # # => <span class="inputError">Title simply can't be empty (or it won't work).</span>
113
118
  def error_message_on(object, method, *args)
114
119
  options = args.extract_options!
115
120
  unless args.empty?
116
121
  ActiveSupport::Deprecation.warn('error_message_on takes an option hash instead of separate ' +
117
- 'prepend_text, append_text, and css_class arguments', caller)
122
+ 'prepend_text, append_text, html_tag, and css_class arguments', caller)
118
123
 
119
124
  options[:prepend_text] = args[0] || ''
120
125
  options[:append_text] = args[1] || ''
121
- options[:css_class] = args[2] || 'formError'
126
+ options[:html_tag] = args[2] || 'div'
127
+ options[:css_class] = args[3] || 'formError'
122
128
  end
123
- options.reverse_merge!(:prepend_text => '', :append_text => '', :css_class => 'formError')
129
+ options.reverse_merge!(:prepend_text => '', :append_text => '', :html_tag => 'div', :css_class => 'formError')
124
130
 
125
131
  object = convert_to_model(object)
126
132
 
127
133
  if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
128
- (errors = obj.errors[method])
129
- content_tag("div",
130
- "#{options[:prepend_text]}#{ERB::Util.html_escape(errors.first)}#{options[:append_text]}",
134
+ (errors = obj.errors[method]).presence
135
+ content_tag(options[:html_tag],
136
+ (options[:prepend_text].html_safe << errors.first).safe_concat(options[:append_text]),
131
137
  :class => options[:css_class]
132
138
  )
133
139
  else
@@ -226,16 +232,16 @@ module ActionView
226
232
 
227
233
  error_messages = objects.sum do |object|
228
234
  object.errors.full_messages.map do |msg|
229
- content_tag(:li, ERB::Util.html_escape(msg))
235
+ content_tag(:li, msg)
230
236
  end
231
- end.join
237
+ end.join.html_safe
232
238
 
233
239
  contents = ''
234
240
  contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
235
241
  contents << content_tag(:p, message) unless message.blank?
236
242
  contents << content_tag(:ul, error_messages)
237
243
 
238
- content_tag(:div, contents, html)
244
+ content_tag(:div, contents.html_safe, html)
239
245
  end
240
246
  else
241
247
  ''
@@ -293,6 +299,10 @@ module ActionView
293
299
  end
294
300
  end
295
301
 
302
+ def error_message
303
+ object.errors[@method_name]
304
+ end
305
+
296
306
  def column_type
297
307
  object.send(:column_for_attribute, @method_name).type
298
308
  end