halorgium-actionpack 3.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/CHANGELOG +5179 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +409 -0
  4. data/lib/abstract_controller.rb +16 -0
  5. data/lib/abstract_controller/base.rb +158 -0
  6. data/lib/abstract_controller/callbacks.rb +113 -0
  7. data/lib/abstract_controller/exceptions.rb +12 -0
  8. data/lib/abstract_controller/helpers.rb +151 -0
  9. data/lib/abstract_controller/layouts.rb +250 -0
  10. data/lib/abstract_controller/localized_cache.rb +49 -0
  11. data/lib/abstract_controller/logger.rb +61 -0
  12. data/lib/abstract_controller/rendering_controller.rb +188 -0
  13. data/lib/action_controller.rb +72 -0
  14. data/lib/action_controller/base.rb +168 -0
  15. data/lib/action_controller/caching.rb +80 -0
  16. data/lib/action_controller/caching/actions.rb +163 -0
  17. data/lib/action_controller/caching/fragments.rb +116 -0
  18. data/lib/action_controller/caching/pages.rb +154 -0
  19. data/lib/action_controller/caching/sweeping.rb +97 -0
  20. data/lib/action_controller/deprecated.rb +4 -0
  21. data/lib/action_controller/deprecated/integration_test.rb +2 -0
  22. data/lib/action_controller/deprecated/performance_test.rb +1 -0
  23. data/lib/action_controller/dispatch/dispatcher.rb +57 -0
  24. data/lib/action_controller/metal.rb +129 -0
  25. data/lib/action_controller/metal/benchmarking.rb +73 -0
  26. data/lib/action_controller/metal/compatibility.rb +145 -0
  27. data/lib/action_controller/metal/conditional_get.rb +86 -0
  28. data/lib/action_controller/metal/configuration.rb +28 -0
  29. data/lib/action_controller/metal/cookies.rb +105 -0
  30. data/lib/action_controller/metal/exceptions.rb +55 -0
  31. data/lib/action_controller/metal/filter_parameter_logging.rb +77 -0
  32. data/lib/action_controller/metal/flash.rb +162 -0
  33. data/lib/action_controller/metal/head.rb +27 -0
  34. data/lib/action_controller/metal/helpers.rb +115 -0
  35. data/lib/action_controller/metal/hide_actions.rb +47 -0
  36. data/lib/action_controller/metal/http_authentication.rb +312 -0
  37. data/lib/action_controller/metal/layouts.rb +171 -0
  38. data/lib/action_controller/metal/mime_responds.rb +317 -0
  39. data/lib/action_controller/metal/rack_convenience.rb +27 -0
  40. data/lib/action_controller/metal/redirector.rb +22 -0
  41. data/lib/action_controller/metal/render_options.rb +103 -0
  42. data/lib/action_controller/metal/rendering_controller.rb +57 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +108 -0
  44. data/lib/action_controller/metal/rescuable.rb +13 -0
  45. data/lib/action_controller/metal/responder.rb +200 -0
  46. data/lib/action_controller/metal/session.rb +15 -0
  47. data/lib/action_controller/metal/session_management.rb +45 -0
  48. data/lib/action_controller/metal/streaming.rb +188 -0
  49. data/lib/action_controller/metal/testing.rb +39 -0
  50. data/lib/action_controller/metal/url_for.rb +41 -0
  51. data/lib/action_controller/metal/verification.rb +130 -0
  52. data/lib/action_controller/middleware.rb +38 -0
  53. data/lib/action_controller/notifications.rb +10 -0
  54. data/lib/action_controller/polymorphic_routes.rb +183 -0
  55. data/lib/action_controller/record_identifier.rb +91 -0
  56. data/lib/action_controller/testing/process.rb +111 -0
  57. data/lib/action_controller/testing/test_case.rb +345 -0
  58. data/lib/action_controller/translation.rb +13 -0
  59. data/lib/action_controller/url_rewriter.rb +204 -0
  60. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  61. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  62. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  63. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +176 -0
  64. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  65. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  66. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  67. data/lib/action_dispatch.rb +70 -0
  68. data/lib/action_dispatch/http/headers.rb +33 -0
  69. data/lib/action_dispatch/http/mime_type.rb +231 -0
  70. data/lib/action_dispatch/http/mime_types.rb +23 -0
  71. data/lib/action_dispatch/http/request.rb +539 -0
  72. data/lib/action_dispatch/http/response.rb +290 -0
  73. data/lib/action_dispatch/http/status_codes.rb +42 -0
  74. data/lib/action_dispatch/http/utils.rb +20 -0
  75. data/lib/action_dispatch/middleware/callbacks.rb +50 -0
  76. data/lib/action_dispatch/middleware/params_parser.rb +79 -0
  77. data/lib/action_dispatch/middleware/rescue.rb +26 -0
  78. data/lib/action_dispatch/middleware/session/abstract_store.rb +208 -0
  79. data/lib/action_dispatch/middleware/session/cookie_store.rb +235 -0
  80. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
  81. data/lib/action_dispatch/middleware/show_exceptions.rb +143 -0
  82. data/lib/action_dispatch/middleware/stack.rb +116 -0
  83. data/lib/action_dispatch/middleware/static.rb +44 -0
  84. data/lib/action_dispatch/middleware/string_coercion.rb +29 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +24 -0
  86. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +26 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +29 -0
  89. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +2 -0
  90. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +10 -0
  91. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +21 -0
  92. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +2 -0
  93. data/lib/action_dispatch/routing.rb +381 -0
  94. data/lib/action_dispatch/routing/deprecated_mapper.rb +878 -0
  95. data/lib/action_dispatch/routing/mapper.rb +327 -0
  96. data/lib/action_dispatch/routing/route.rb +49 -0
  97. data/lib/action_dispatch/routing/route_set.rb +497 -0
  98. data/lib/action_dispatch/testing/assertions.rb +8 -0
  99. data/lib/action_dispatch/testing/assertions/dom.rb +35 -0
  100. data/lib/action_dispatch/testing/assertions/model.rb +19 -0
  101. data/lib/action_dispatch/testing/assertions/response.rb +145 -0
  102. data/lib/action_dispatch/testing/assertions/routing.rb +144 -0
  103. data/lib/action_dispatch/testing/assertions/selector.rb +639 -0
  104. data/lib/action_dispatch/testing/assertions/tag.rb +123 -0
  105. data/lib/action_dispatch/testing/integration.rb +504 -0
  106. data/lib/action_dispatch/testing/performance_test.rb +15 -0
  107. data/lib/action_dispatch/testing/test_request.rb +83 -0
  108. data/lib/action_dispatch/testing/test_response.rb +131 -0
  109. data/lib/action_pack.rb +24 -0
  110. data/lib/action_pack/version.rb +9 -0
  111. data/lib/action_view.rb +58 -0
  112. data/lib/action_view/base.rb +308 -0
  113. data/lib/action_view/context.rb +44 -0
  114. data/lib/action_view/erb/util.rb +48 -0
  115. data/lib/action_view/helpers.rb +62 -0
  116. data/lib/action_view/helpers/active_model_helper.rb +306 -0
  117. data/lib/action_view/helpers/ajax_helper.rb +68 -0
  118. data/lib/action_view/helpers/asset_tag_helper.rb +830 -0
  119. data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
  120. data/lib/action_view/helpers/cache_helper.rb +39 -0
  121. data/lib/action_view/helpers/capture_helper.rb +168 -0
  122. data/lib/action_view/helpers/date_helper.rb +988 -0
  123. data/lib/action_view/helpers/debug_helper.rb +38 -0
  124. data/lib/action_view/helpers/form_helper.rb +1102 -0
  125. data/lib/action_view/helpers/form_options_helper.rb +600 -0
  126. data/lib/action_view/helpers/form_tag_helper.rb +495 -0
  127. data/lib/action_view/helpers/javascript_helper.rb +208 -0
  128. data/lib/action_view/helpers/number_helper.rb +311 -0
  129. data/lib/action_view/helpers/prototype_helper.rb +1309 -0
  130. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  131. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  132. data/lib/action_view/helpers/record_tag_helper.rb +58 -0
  133. data/lib/action_view/helpers/sanitize_helper.rb +259 -0
  134. data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
  135. data/lib/action_view/helpers/tag_helper.rb +151 -0
  136. data/lib/action_view/helpers/text_helper.rb +594 -0
  137. data/lib/action_view/helpers/translation_helper.rb +39 -0
  138. data/lib/action_view/helpers/url_helper.rb +639 -0
  139. data/lib/action_view/locale/en.yml +117 -0
  140. data/lib/action_view/paths.rb +80 -0
  141. data/lib/action_view/render/partials.rb +342 -0
  142. data/lib/action_view/render/rendering.rb +134 -0
  143. data/lib/action_view/safe_buffer.rb +28 -0
  144. data/lib/action_view/template/error.rb +101 -0
  145. data/lib/action_view/template/handler.rb +36 -0
  146. data/lib/action_view/template/handlers.rb +52 -0
  147. data/lib/action_view/template/handlers/builder.rb +17 -0
  148. data/lib/action_view/template/handlers/erb.rb +53 -0
  149. data/lib/action_view/template/handlers/rjs.rb +18 -0
  150. data/lib/action_view/template/resolver.rb +165 -0
  151. data/lib/action_view/template/template.rb +131 -0
  152. data/lib/action_view/template/text.rb +38 -0
  153. data/lib/action_view/test_case.rb +163 -0
  154. metadata +236 -0
@@ -0,0 +1,44 @@
1
+ module ActionView
2
+ module CompiledTemplates #:nodoc:
3
+ # holds compiled template code
4
+ end
5
+
6
+ # ActionView contexts are supplied to ActionController
7
+ # to render template. The default ActionView context
8
+ # is ActionView::Base.
9
+ #
10
+ # In order to work with ActionController, a Context
11
+ # must implement:
12
+ #
13
+ # Context.for_controller[controller] Create a new ActionView instance for a
14
+ # controller
15
+ # Context#render_partial[options]
16
+ # - responsible for setting options[:_template]
17
+ # - Returns String with the rendered partial
18
+ # options<Hash>:: see _render_partial in ActionView::Base
19
+ # Context#render_template[template, layout, options, partial]
20
+ # - Returns String with the rendered template
21
+ # template<ActionView::Template>:: The template to render
22
+ # layout<ActionView::Template>:: The layout to render around the template
23
+ # options<Hash>:: See _render_template_with_layout in ActionView::Base
24
+ # partial<Boolean>:: Whether or not the template to render is a partial
25
+ #
26
+ # An ActionView context can also mix in ActionView's
27
+ # helpers. In order to mix in helpers, a context must
28
+ # implement:
29
+ #
30
+ # Context#controller
31
+ # - Returns an instance of AbstractController
32
+ #
33
+ # In any case, a context must mix in ActionView::Context,
34
+ # which stores compiled template and provides the output
35
+ # buffer.
36
+ module Context
37
+ include CompiledTemplates
38
+ attr_accessor :output_buffer
39
+
40
+ def convert_to_model(object)
41
+ object.respond_to?(:to_model) ? object.to_model : object
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,48 @@
1
+ require 'erb'
2
+
3
+ class ERB
4
+ module Util
5
+ HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
6
+ JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
7
+
8
+ # A utility method for escaping HTML tag characters.
9
+ # This method is also aliased as <tt>h</tt>.
10
+ #
11
+ # In your ERb templates, use this method to escape any unsafe content. For example:
12
+ # <%=h @person.name %>
13
+ #
14
+ # ==== Example:
15
+ # puts html_escape("is a > 0 & a < 10?")
16
+ # # => is a &gt; 0 &amp; a &lt; 10?
17
+ def html_escape(s)
18
+ s = s.to_s
19
+ if s.html_safe?
20
+ s
21
+ else
22
+ s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe!
23
+ end
24
+ end
25
+
26
+ alias h html_escape
27
+
28
+ module_function :html_escape
29
+ module_function :h
30
+
31
+ # A utility method for escaping HTML entities in JSON strings.
32
+ # This method is also aliased as <tt>j</tt>.
33
+ #
34
+ # In your ERb templates, use this method to escape any HTML entities:
35
+ # <%=j @person.to_json %>
36
+ #
37
+ # ==== Example:
38
+ # puts json_escape("is a > 0 & a < 10?")
39
+ # # => is a \u003E 0 \u0026 a \u003C 10?
40
+ def json_escape(s)
41
+ s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
42
+ end
43
+
44
+ alias j json_escape
45
+ module_function :j
46
+ module_function :json_escape
47
+ end
48
+ end
@@ -0,0 +1,62 @@
1
+ require 'active_support/benchmarkable'
2
+
3
+ module ActionView #:nodoc:
4
+ module Helpers #:nodoc:
5
+ autoload :ActiveModelHelper, 'action_view/helpers/active_model_helper'
6
+ autoload :AjaxHelper, 'action_view/helpers/ajax_helper'
7
+ autoload :AssetTagHelper, 'action_view/helpers/asset_tag_helper'
8
+ autoload :AtomFeedHelper, 'action_view/helpers/atom_feed_helper'
9
+ autoload :CacheHelper, 'action_view/helpers/cache_helper'
10
+ autoload :CaptureHelper, 'action_view/helpers/capture_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'
28
+
29
+ def self.included(base)
30
+ base.extend(ClassMethods)
31
+ end
32
+
33
+ module ClassMethods
34
+ include SanitizeHelper::ClassMethods
35
+ end
36
+
37
+ include ActiveSupport::Benchmarkable
38
+
39
+ include ActiveModelHelper
40
+ include AssetTagHelper
41
+ include AtomFeedHelper
42
+ include CacheHelper
43
+ include CaptureHelper
44
+ include DateHelper
45
+ include DebugHelper
46
+ include FormHelper
47
+ include FormOptionsHelper
48
+ include FormTagHelper
49
+ include JavaScriptHelper
50
+ include NumberHelper
51
+ include PrototypeHelper
52
+ include RawOutputHelper
53
+ include RecordIdentificationHelper
54
+ include RecordTagHelper
55
+ include SanitizeHelper
56
+ include ScriptaculousHelper
57
+ include TagHelper
58
+ include TextHelper
59
+ include TranslationHelper
60
+ include UrlHelper
61
+ end
62
+ end
@@ -0,0 +1,306 @@
1
+ require 'cgi'
2
+ require 'action_view/helpers/form_helper'
3
+ require 'active_support/core_ext/class/attribute_accessors'
4
+ require 'active_support/core_ext/enumerable'
5
+ require 'active_support/core_ext/kernel/reporting'
6
+
7
+ 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
11
+ end
12
+
13
+ module Helpers
14
+ # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the +form+
15
+ # method that creates a complete form for all the basic content types of the record (not associations or aggregations, though). This
16
+ # is a great way of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form.
17
+ # In that case, it's better to use the +input+ method and the specialized +form+ methods in link:classes/ActionView/Helpers/FormHelper.html
18
+ module ActiveModelHelper
19
+ # Returns a default input tag for the type of object returned by the method. For example, if <tt>@post</tt>
20
+ # has an attribute +title+ mapped to a +VARCHAR+ column that holds "Hello World":
21
+ #
22
+ # input("post", "title")
23
+ # # => <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
24
+ def input(record_name, method, options = {})
25
+ InstanceTag.new(record_name, method, self).to_tag(options)
26
+ end
27
+
28
+ # Returns an entire form with all needed input tags for a specified Active Record object. For example, if <tt>@post</tt>
29
+ # has attributes named +title+ of type +VARCHAR+ and +body+ of type +TEXT+ then
30
+ #
31
+ # form("post")
32
+ #
33
+ # would yield a form like the following (modulus formatting):
34
+ #
35
+ # <form action='/posts/create' method='post'>
36
+ # <p>
37
+ # <label for="post_title">Title</label><br />
38
+ # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
39
+ # </p>
40
+ # <p>
41
+ # <label for="post_body">Body</label><br />
42
+ # <textarea cols="40" id="post_body" name="post[body]" rows="20"></textarea>
43
+ # </p>
44
+ # <input name="commit" type="submit" value="Create" />
45
+ # </form>
46
+ #
47
+ # It's possible to specialize the form builder by using a different action name and by supplying another
48
+ # block renderer. For example, if <tt>@entry</tt> has an attribute +message+ of type +VARCHAR+ then
49
+ #
50
+ # form("entry",
51
+ # :action => "sign",
52
+ # :input_block => Proc.new { |record, column|
53
+ # "#{column.human_name}: #{input(record, column.name)}<br />"
54
+ # })
55
+ #
56
+ # would yield a form like the following (modulus formatting):
57
+ #
58
+ # <form action="/entries/sign" method="post">
59
+ # Message:
60
+ # <input id="entry_message" name="entry[message]" size="30" type="text" /><br />
61
+ # <input name="commit" type="submit" value="Sign" />
62
+ # </form>
63
+ #
64
+ # It's also possible to add additional content to the form by giving it a block, such as:
65
+ #
66
+ # form("entry", :action => "sign") do |form|
67
+ # form << content_tag("b", "Department")
68
+ # form << collection_select("department", "id", @departments, "id", "name")
69
+ # end
70
+ #
71
+ # The following options are available:
72
+ #
73
+ # * <tt>:action</tt> - The action used when submitting the form (default: +create+ if a new record, otherwise +update+).
74
+ # * <tt>:input_block</tt> - Specialize the output using a different block, see above.
75
+ # * <tt>:method</tt> - The method used when submitting the form (default: +post+).
76
+ # * <tt>:multipart</tt> - Whether to change the enctype of the form to "multipart/form-data", used when uploading a file (default: +false+).
77
+ # * <tt>:submit_value</tt> - The text of the submit button (default: "Create" if a new record, otherwise "Update").
78
+ def form(record_name, options = {})
79
+ record = instance_variable_get("@#{record_name}")
80
+ record = convert_to_model(record)
81
+
82
+ options = options.symbolize_keys
83
+ options[:action] ||= record.new_record? ? "create" : "update"
84
+ action = url_for(:action => options[:action], :id => record)
85
+
86
+ submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize
87
+
88
+ contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil)
89
+ contents << hidden_field(record_name, :id) unless record.new_record?
90
+ contents << all_input_tags(record, record_name, options)
91
+ yield contents if block_given?
92
+ contents << submit_tag(submit_value)
93
+ contents << '</form>'
94
+ contents.html_safe!
95
+ end
96
+
97
+ # Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
98
+ # This error message is wrapped in a <tt>DIV</tt> tag, which can be extended to include a <tt>:prepend_text</tt>
99
+ # and/or <tt>:append_text</tt> (to properly explain the error), and a <tt>:css_class</tt> to style it
100
+ # accordingly. +object+ should either be the name of an instance variable or the actual object. The method can be
101
+ # passed in either as a string or a symbol.
102
+ # As an example, let's say you have a model <tt>@post</tt> that has an error message on the +title+ attribute:
103
+ #
104
+ # <%= error_message_on "post", "title" %>
105
+ # # => <div class="formError">can't be empty</div>
106
+ #
107
+ # <%= error_message_on @post, :title %>
108
+ # # => <div class="formError">can't be empty</div>
109
+ #
110
+ # <%= error_message_on "post", "title",
111
+ # :prepend_text => "Title simply ",
112
+ # :append_text => " (or it won't work).",
113
+ # :css_class => "inputError" %>
114
+ def error_message_on(object, method, *args)
115
+ options = args.extract_options!
116
+ unless args.empty?
117
+ ActiveSupport::Deprecation.warn('error_message_on takes an option hash instead of separate ' +
118
+ 'prepend_text, append_text, and css_class arguments', caller)
119
+
120
+ options[:prepend_text] = args[0] || ''
121
+ options[:append_text] = args[1] || ''
122
+ options[:css_class] = args[2] || 'formError'
123
+ end
124
+ options.reverse_merge!(:prepend_text => '', :append_text => '', :css_class => 'formError')
125
+
126
+ object = convert_to_model(object)
127
+
128
+ if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
129
+ (errors = obj.errors[method])
130
+ content_tag("div",
131
+ "#{options[:prepend_text]}#{ERB::Util.html_escape(errors.first)}#{options[:append_text]}",
132
+ :class => options[:css_class]
133
+ )
134
+ else
135
+ ''
136
+ end
137
+ end
138
+
139
+ # Returns a string with a <tt>DIV</tt> containing all of the error messages for the objects located as instance variables by the names
140
+ # given. If more than one object is specified, the errors for the objects are displayed in the order that the object names are
141
+ # provided.
142
+ #
143
+ # This <tt>DIV</tt> can be tailored by the following options:
144
+ #
145
+ # * <tt>:header_tag</tt> - Used for the header of the error div (default: "h2").
146
+ # * <tt>:id</tt> - The id of the error div (default: "errorExplanation").
147
+ # * <tt>:class</tt> - The class of the error div (default: "errorExplanation").
148
+ # * <tt>:object</tt> - The object (or array of objects) for which to display errors,
149
+ # if you need to escape the instance variable convention.
150
+ # * <tt>:object_name</tt> - The object name to use in the header, or any text that you prefer.
151
+ # If <tt>:object_name</tt> is not set, the name of the first object will be used.
152
+ # * <tt>:header_message</tt> - The message in the header of the error div. Pass +nil+
153
+ # or an empty string to avoid the header message altogether. (Default: "X errors
154
+ # prohibited this object from being saved").
155
+ # * <tt>:message</tt> - The explanation message after the header message and before
156
+ # the error list. Pass +nil+ or an empty string to avoid the explanation message
157
+ # altogether. (Default: "There were problems with the following fields:").
158
+ #
159
+ # To specify the display for one object, you simply provide its name as a parameter.
160
+ # For example, for the <tt>@user</tt> model:
161
+ #
162
+ # error_messages_for 'user'
163
+ #
164
+ # You can also supply an object:
165
+ #
166
+ # error_messages_for @user
167
+ #
168
+ # This will use the last part of the model name in the presentation. For instance, if
169
+ # this is a MyKlass::User object, this will use "user" as the name in the String. This
170
+ # is taken from MyKlass::User.model_name.human, which can be overridden.
171
+ #
172
+ # To specify more than one object, you simply list them; optionally, you can add an extra <tt>:object_name</tt> parameter, which
173
+ # will be the name used in the header message:
174
+ #
175
+ # error_messages_for 'user_common', 'user', :object_name => 'user'
176
+ #
177
+ # You can also use a number of objects, which will have the same naming semantics
178
+ # as a single object.
179
+ #
180
+ # error_messages_for @user, @post
181
+ #
182
+ # If the objects cannot be located as instance variables, you can add an extra <tt>:object</tt> parameter which gives the actual
183
+ # object (or array of objects to use):
184
+ #
185
+ # error_messages_for 'user', :object => @question.user
186
+ #
187
+ # NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what
188
+ # you need is significantly different from the default presentation, it makes plenty of sense to access the <tt>object.errors</tt>
189
+ # instance yourself and set it up. View the source of this method to see how easy it is.
190
+ def error_messages_for(*params)
191
+ options = params.extract_options!.symbolize_keys
192
+
193
+ objects = Array.wrap(options.delete(:object) || params).map do |object|
194
+ object = instance_variable_get("@#{object}") unless object.respond_to?(:to_model)
195
+ object = convert_to_model(object)
196
+
197
+ if object.class.respond_to?(:model_name)
198
+ options[:object_name] ||= object.class.model_name.human.downcase
199
+ end
200
+
201
+ object
202
+ end
203
+
204
+ objects.compact!
205
+ count = objects.inject(0) {|sum, object| sum + object.errors.count }
206
+
207
+ unless count.zero?
208
+ html = {}
209
+ [:id, :class].each do |key|
210
+ if options.include?(key)
211
+ value = options[key]
212
+ html[key] = value unless value.blank?
213
+ else
214
+ html[key] = 'errorExplanation'
215
+ end
216
+ end
217
+ options[:object_name] ||= params.first
218
+
219
+ I18n.with_options :locale => options[:locale], :scope => [:activemodel, :errors, :template] do |locale|
220
+ header_message = if options.include?(:header_message)
221
+ options[:header_message]
222
+ else
223
+ locale.t :header, :count => count, :model => options[:object_name].to_s.gsub('_', ' ')
224
+ end
225
+
226
+ message = options.include?(:message) ? options[:message] : locale.t(:body)
227
+
228
+ error_messages = objects.sum do |object|
229
+ object.errors.full_messages.map do |msg|
230
+ content_tag(:li, ERB::Util.html_escape(msg))
231
+ end
232
+ end.join
233
+
234
+ contents = ''
235
+ contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
236
+ contents << content_tag(:p, message) unless message.blank?
237
+ contents << content_tag(:ul, error_messages)
238
+
239
+ content_tag(:div, contents, html)
240
+ end
241
+ else
242
+ ''
243
+ end
244
+ end
245
+
246
+ private
247
+ def all_input_tags(record, record_name, options)
248
+ input_block = options[:input_block] || default_input_block
249
+ record.class.content_columns.collect{ |column| input_block.call(record_name, column) }.join("\n")
250
+ end
251
+
252
+ def default_input_block
253
+ Proc.new { |record, column| %(<p><label for="#{record}_#{column.name}">#{column.human_name}</label><br />#{input(record, column.name)}</p>) }
254
+ end
255
+ end
256
+
257
+ module ActiveRecordInstanceTag
258
+ def object
259
+ @active_model_object ||= begin
260
+ object = super
261
+ object.respond_to?(:to_model) ? object.to_model : object
262
+ end
263
+ end
264
+
265
+ def to_tag(options = {})
266
+ case column_type
267
+ when :string
268
+ field_type = @method_name.include?("password") ? "password" : "text"
269
+ to_input_field_tag(field_type, options)
270
+ when :text
271
+ to_text_area_tag(options)
272
+ when :integer, :float, :decimal
273
+ to_input_field_tag("text", options)
274
+ when :date
275
+ to_date_select_tag(options)
276
+ when :datetime, :timestamp
277
+ to_datetime_select_tag(options)
278
+ when :time
279
+ to_time_select_tag(options)
280
+ when :boolean
281
+ to_boolean_select_tag(options)
282
+ end
283
+ end
284
+
285
+ %w(tag content_tag to_date_select_tag to_datetime_select_tag to_time_select_tag).each do |meth|
286
+ module_eval "def #{meth}(*) error_wrapping(super) end"
287
+ end
288
+
289
+ def error_wrapping(html_tag)
290
+ if object.respond_to?(:errors) && object.errors.respond_to?(:full_messages) && object.errors[@method_name].any?
291
+ Base.field_error_proc.call(html_tag, self)
292
+ else
293
+ html_tag
294
+ end
295
+ end
296
+
297
+ def column_type
298
+ object.send(:column_for_attribute, @method_name).type
299
+ end
300
+ end
301
+
302
+ class InstanceTag
303
+ include ActiveRecordInstanceTag
304
+ end
305
+ end
306
+ end