actionpack 0.9.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.

Files changed (100) hide show
  1. data/CHANGELOG +604 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +418 -0
  4. data/RUNNING_UNIT_TESTS +14 -0
  5. data/examples/.htaccess +24 -0
  6. data/examples/address_book/index.rhtml +33 -0
  7. data/examples/address_book/layout.rhtml +8 -0
  8. data/examples/address_book_controller.cgi +9 -0
  9. data/examples/address_book_controller.fcgi +6 -0
  10. data/examples/address_book_controller.rb +52 -0
  11. data/examples/address_book_controller.rbx +4 -0
  12. data/examples/benchmark.rb +52 -0
  13. data/examples/benchmark_with_ar.fcgi +89 -0
  14. data/examples/blog_controller.cgi +53 -0
  15. data/examples/debate/index.rhtml +14 -0
  16. data/examples/debate/new_topic.rhtml +22 -0
  17. data/examples/debate/topic.rhtml +32 -0
  18. data/examples/debate_controller.cgi +57 -0
  19. data/install.rb +93 -0
  20. data/lib/action_controller.rb +47 -0
  21. data/lib/action_controller/assertions/action_pack_assertions.rb +166 -0
  22. data/lib/action_controller/assertions/active_record_assertions.rb +65 -0
  23. data/lib/action_controller/base.rb +626 -0
  24. data/lib/action_controller/benchmarking.rb +49 -0
  25. data/lib/action_controller/cgi_ext/cgi_ext.rb +43 -0
  26. data/lib/action_controller/cgi_ext/cgi_methods.rb +91 -0
  27. data/lib/action_controller/cgi_process.rb +123 -0
  28. data/lib/action_controller/filters.rb +279 -0
  29. data/lib/action_controller/flash.rb +65 -0
  30. data/lib/action_controller/layout.rb +143 -0
  31. data/lib/action_controller/request.rb +92 -0
  32. data/lib/action_controller/rescue.rb +94 -0
  33. data/lib/action_controller/response.rb +15 -0
  34. data/lib/action_controller/scaffolding.rb +183 -0
  35. data/lib/action_controller/session/active_record_store.rb +72 -0
  36. data/lib/action_controller/session/drb_server.rb +9 -0
  37. data/lib/action_controller/session/drb_store.rb +31 -0
  38. data/lib/action_controller/support/class_attribute_accessors.rb +57 -0
  39. data/lib/action_controller/support/class_inheritable_attributes.rb +37 -0
  40. data/lib/action_controller/support/clean_logger.rb +10 -0
  41. data/lib/action_controller/support/cookie_performance_fix.rb +121 -0
  42. data/lib/action_controller/support/inflector.rb +70 -0
  43. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +28 -0
  44. data/lib/action_controller/templates/rescues/diagnostics.rhtml +22 -0
  45. data/lib/action_controller/templates/rescues/layout.rhtml +29 -0
  46. data/lib/action_controller/templates/rescues/missing_template.rhtml +2 -0
  47. data/lib/action_controller/templates/rescues/template_error.rhtml +26 -0
  48. data/lib/action_controller/templates/rescues/unknown_action.rhtml +2 -0
  49. data/lib/action_controller/templates/scaffolds/edit.rhtml +6 -0
  50. data/lib/action_controller/templates/scaffolds/layout.rhtml +29 -0
  51. data/lib/action_controller/templates/scaffolds/list.rhtml +24 -0
  52. data/lib/action_controller/templates/scaffolds/new.rhtml +5 -0
  53. data/lib/action_controller/templates/scaffolds/show.rhtml +9 -0
  54. data/lib/action_controller/test_process.rb +194 -0
  55. data/lib/action_controller/url_rewriter.rb +153 -0
  56. data/lib/action_view.rb +40 -0
  57. data/lib/action_view/base.rb +253 -0
  58. data/lib/action_view/helpers/active_record_helper.rb +171 -0
  59. data/lib/action_view/helpers/date_helper.rb +223 -0
  60. data/lib/action_view/helpers/debug_helper.rb +17 -0
  61. data/lib/action_view/helpers/form_helper.rb +176 -0
  62. data/lib/action_view/helpers/form_options_helper.rb +169 -0
  63. data/lib/action_view/helpers/tag_helper.rb +59 -0
  64. data/lib/action_view/helpers/text_helper.rb +129 -0
  65. data/lib/action_view/helpers/url_helper.rb +72 -0
  66. data/lib/action_view/partials.rb +61 -0
  67. data/lib/action_view/template_error.rb +84 -0
  68. data/lib/action_view/vendor/builder.rb +13 -0
  69. data/lib/action_view/vendor/builder/blankslate.rb +21 -0
  70. data/lib/action_view/vendor/builder/xmlbase.rb +143 -0
  71. data/lib/action_view/vendor/builder/xmlevents.rb +63 -0
  72. data/lib/action_view/vendor/builder/xmlmarkup.rb +288 -0
  73. data/rakefile +105 -0
  74. data/test/abstract_unit.rb +9 -0
  75. data/test/controller/action_pack_assertions_test.rb +295 -0
  76. data/test/controller/active_record_assertions_test.rb +118 -0
  77. data/test/controller/cgi_test.rb +142 -0
  78. data/test/controller/cookie_test.rb +38 -0
  79. data/test/controller/filters_test.rb +159 -0
  80. data/test/controller/flash_test.rb +69 -0
  81. data/test/controller/layout_test.rb +49 -0
  82. data/test/controller/redirect_test.rb +44 -0
  83. data/test/controller/render_test.rb +169 -0
  84. data/test/controller/url_test.rb +318 -0
  85. data/test/fixtures/layouts/builder.rxml +3 -0
  86. data/test/fixtures/layouts/standard.rhtml +1 -0
  87. data/test/fixtures/test/_customer.rhtml +1 -0
  88. data/test/fixtures/test/greeting.rhtml +1 -0
  89. data/test/fixtures/test/hello.rxml +4 -0
  90. data/test/fixtures/test/hello_world.rhtml +1 -0
  91. data/test/fixtures/test/hello_xml_world.rxml +11 -0
  92. data/test/fixtures/test/list.rhtml +1 -0
  93. data/test/template/active_record_helper_test.rb +76 -0
  94. data/test/template/date_helper_test.rb +103 -0
  95. data/test/template/form_helper_test.rb +115 -0
  96. data/test/template/form_options_helper_test.rb +174 -0
  97. data/test/template/tag_helper_test.rb +18 -0
  98. data/test/template/text_helper_test.rb +62 -0
  99. data/test/template/url_helper_test.rb +35 -0
  100. metadata +154 -0
@@ -0,0 +1,40 @@
1
+ #--
2
+ # Copyright (c) 2004 David Heinemeier Hansson
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ begin
25
+ require 'rubygems'
26
+ require 'builder'
27
+ rescue LoadError
28
+ # RubyGems is not available, use included Builder
29
+ $:.unshift(File.dirname(__FILE__) + "/action_view/vendor")
30
+ require 'action_view/vendor/builder'
31
+ end
32
+
33
+ require 'action_view/base'
34
+ require 'action_view/partials'
35
+
36
+ ActionView::Base.class_eval do
37
+ include ActionView::Partials
38
+ end
39
+
40
+ ActionView::Base.load_helpers(File.dirname(__FILE__) + "/action_view/helpers/")
@@ -0,0 +1,253 @@
1
+ require 'erb'
2
+
3
+ module ActionView #:nodoc:
4
+ class ActionViewError < StandardError #:nodoc:
5
+ end
6
+
7
+ # Action View templates can be written in two ways. If the template file has a +.rhtml+ extension then it uses a mixture of ERb
8
+ # (included in Ruby) and HTML. If the template file has a +.rxml+ extension then Jim Weirich's Builder::XmlMarkup library is used.
9
+ #
10
+ # = ERb
11
+ #
12
+ # You trigger ERb by using embeddings such as <% %> and <%= %>. The difference is whether you want output or not. Consider the
13
+ # following loop for names:
14
+ #
15
+ # <b>Names of all the people</b>
16
+ # <% for person in @people %>
17
+ # Name: <%= person.name %><br/>
18
+ # <% end %>
19
+ #
20
+ # The loop is setup in regular embedding tags (<% %>) and the name is written using the output embedding tag (<%= %>). Note that this
21
+ # is not just a usage suggestion. Regular output functions like print or puts won't work with ERb templates. So this would be wrong:
22
+ #
23
+ # Hi, Mr. <% puts "Frodo" %>
24
+ #
25
+ # (If you absolutely must write from within a function, you can use the TextHelper#concat)
26
+ #
27
+ # == Using sub templates
28
+ #
29
+ # Using sub templates allows you to sidestep tedious replication and extract common display structures in shared templates. The
30
+ # classic example is the use of a header and footer (even though the Action Pack-way would be to use Layouts):
31
+ #
32
+ # <%= render "shared/header" %>
33
+ # Something really specific and terrific
34
+ # <%= render "shared/footer" %>
35
+ #
36
+ # As you see, we use the output embeddings for the render methods. The render call itself will just return a string holding the
37
+ # result of the rendering. The output embedding writes it to the current template.
38
+ #
39
+ # But you don't have to restrict yourself to static includes. Templates can share variables amongst themselves by using instance
40
+ # variables defined in using the regular embedding tags. Like this:
41
+ #
42
+ # <% @page_title = "A Wonderful Hello" %>
43
+ # <%= render "shared/header" %>
44
+ #
45
+ # Now the header can pick up on the @page_title variable and use it for outputting a title tag:
46
+ #
47
+ # <title><%= @page_title %></title>
48
+ #
49
+ # == Passing local variables to sub templates
50
+ #
51
+ # You can pass local variables to sub templates by using a hash with the variable names as keys and the objects as values:
52
+ #
53
+ # <%= render "shared/header", { "headline" => "Welcome", "person" => person } %>
54
+ #
55
+ # These can now be accessed in shared/header with:
56
+ #
57
+ # Headline: <%= headline %>
58
+ # First name: <%= person.first_name %>
59
+ #
60
+ # == Template caching
61
+ #
62
+ # The parsing of ERb templates are cached by default, but the reading of them are not. This means that the application by default
63
+ # will reflect changes to the templates immediatly. If you'd like to sacrifice that immediacy for the speed gain given by also
64
+ # caching the loading of templates (reading from the file systen), you can turn that on with
65
+ # <tt>ActionView::Base.cache_template_loading = true</tt>.
66
+ #
67
+ # == Builder
68
+ #
69
+ # Builder templates are a more programatic alternative to ERb. They are especially useful for generating XML content. An +XmlMarkup+ object
70
+ # named +xml+ is automatically made available to templates with a +.rxml+ extension.
71
+ #
72
+ # Here are some basic examples:
73
+ #
74
+ # xml.em("emphasized") # => <em>emphasized</em>
75
+ # xml.em { xml.b("emp & bold") } # => <em><b>emph &amp; bold</b></em>
76
+ # xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
77
+ # xm.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\>
78
+ # # NOTE: order of attributes is not specified.
79
+ #
80
+ # Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following:
81
+ #
82
+ # xml.div {
83
+ # xml.h1(@person.name)
84
+ # xml.p(@person.bio)
85
+ # }
86
+ #
87
+ # would produce something like:
88
+ #
89
+ # <div>
90
+ # <h1>David Heinemeier Hansson</h1>
91
+ # <p>A product of Danish Design during the Winter of '79...</p>
92
+ # </div>
93
+ #
94
+ # A full-length RSS example actually used on Basecamp:
95
+ #
96
+ # xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
97
+ # xml.channel do
98
+ # xml.title(@feed_title)
99
+ # xml.link(@url)
100
+ # xml.description "Basecamp: Recent items"
101
+ # xml.language "en-us"
102
+ # xml.ttl "40"
103
+ #
104
+ # for item in @recent_items
105
+ # xml.item do
106
+ # xml.title(item_title(item))
107
+ # xml.description(item_description(item)) if item_description(item)
108
+ # xml.pubDate(item_pubDate(item))
109
+ # xml.guid(@person.firm.account.url + @recent_items.url(item))
110
+ # xml.link(@person.firm.account.url + @recent_items.url(item))
111
+ #
112
+ # xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
113
+ # end
114
+ # end
115
+ # end
116
+ # end
117
+ #
118
+ # More builder documentation can be found at http://builder.rubyforge.org.
119
+ class Base
120
+ include ERB::Util
121
+
122
+ attr_reader :first_render
123
+ attr_accessor :base_path, :assigns, :template_extension
124
+ attr_accessor :controller
125
+
126
+ # Turn on to cache the reading of templates from the file system. Doing so means that you have to restart the server
127
+ # when changing templates, but that rendering will be faster.
128
+ @@cache_template_loading = false
129
+ cattr_accessor :cache_template_loading
130
+
131
+ @@compiled_erb_templates = {}
132
+ @@loaded_templates = {}
133
+
134
+ def self.load_helpers(helper_dir)#:nodoc:
135
+ Dir.foreach(helper_dir) do |helper_file|
136
+ next unless helper_file =~ /_helper.rb$/
137
+ require helper_dir + helper_file
138
+ helper_module_name = helper_file.capitalize.gsub(/_([a-z])/) { |m| $1.capitalize }[0..-4]
139
+
140
+ class_eval("include ActionView::Helpers::#{helper_module_name}") if Helpers.const_defined?(helper_module_name)
141
+ end
142
+ end
143
+
144
+ def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)#:nodoc:
145
+ @base_path, @assigns = base_path, assigns_for_first_render
146
+ @controller = controller
147
+ end
148
+
149
+ # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
150
+ # it's relative to the template_root, otherwise it's absolute. The hash in <tt>local_assigns</tt>
151
+ # is made available as local variables.
152
+ def render_file(template_path, use_full_path = true, local_assigns = {})
153
+ @first_render = template_path if @first_render.nil?
154
+
155
+ if use_full_path
156
+ template_extension = pick_template_extension(template_path)
157
+ template_file_name = full_template_path(template_path, template_extension)
158
+ else
159
+ template_file_name = template_path
160
+ template_extension = template_path.split(".").last
161
+ end
162
+
163
+ template_source = read_template_file(template_file_name)
164
+
165
+ begin
166
+ render_template(template_extension, template_source, local_assigns)
167
+ rescue Exception => e
168
+ if TemplateError === e
169
+ e.sub_template_of(template_file_name)
170
+ raise e
171
+ else
172
+ raise TemplateError.new(@base_path, template_file_name, @assigns, template_source, e)
173
+ end
174
+ end
175
+ end
176
+
177
+ # Renders the template present at <tt>template_path</tt> (relative to the template_root).
178
+ # The hash in <tt>local_assigns</tt> is made available as local variables.
179
+ def render(template_path, local_assigns = {})
180
+ render_file(template_path, true, local_assigns)
181
+ end
182
+
183
+ # Renders the +template+ which is given as a string as either rhtml or rxml depending on <tt>template_extension</tt>.
184
+ # The hash in <tt>local_assigns</tt> is made available as local variables.
185
+ def render_template(template_extension, template, local_assigns = {})
186
+ b = binding
187
+ local_assigns.each { |key, value| eval "#{key} = local_assigns[\"#{key}\"]", b }
188
+ @assigns.each { |key, value| instance_variable_set "@#{key}", value }
189
+ xml = Builder::XmlMarkup.new(:indent => 2)
190
+
191
+ send(pick_rendering_method(template_extension), template, binding)
192
+ end
193
+
194
+ def pick_template_extension(template_path)#:nodoc:
195
+ if erb_template_exists?(template_path)
196
+ "rhtml"
197
+ elsif builder_template_exists?(template_path)
198
+ "rxml"
199
+ else
200
+ raise ActionViewError, "No rhtml or rxml template found for #{template_path}"
201
+ end
202
+ end
203
+
204
+ def pick_rendering_method(template_extension)#:nodoc:
205
+ (template_extension == "rxml" ? "rxml" : "rhtml") + "_render"
206
+ end
207
+
208
+ def erb_template_exists?(template_path)#:nodoc:
209
+ template_exists?(template_path, "rhtml")
210
+ end
211
+
212
+ def builder_template_exists?(template_path)#:nodoc:
213
+ template_exists?(template_path, "rxml")
214
+ end
215
+
216
+ def file_exists?(template_path)#:nodoc:
217
+ erb_template_exists?(template_path) || builder_template_exists?(template_path)
218
+ end
219
+
220
+ # Returns true is the file may be rendered implicitly.
221
+ def file_public?(template_path)#:nodoc:
222
+ template_path.split("/").last[0,1] != "_"
223
+ end
224
+
225
+ private
226
+ def full_template_path(template_path, extension)
227
+ "#{@base_path}/#{template_path}.#{extension}"
228
+ end
229
+
230
+ def template_exists?(template_path, extension)
231
+ FileTest.exists?(full_template_path(template_path, extension))
232
+ end
233
+
234
+ def read_template_file(template_path)
235
+ unless cache_template_loading && @@loaded_templates[template_path]
236
+ @@loaded_templates[template_path] = File.read(template_path)
237
+ end
238
+
239
+ @@loaded_templates[template_path]
240
+ end
241
+
242
+ def rhtml_render(template, binding)
243
+ @@compiled_erb_templates[template] ||= ERB.new(template)
244
+ @@compiled_erb_templates[template].result(binding)
245
+ end
246
+
247
+ def rxml_render(template, binding)
248
+ eval(template, binding)
249
+ end
250
+ end
251
+ end
252
+
253
+ require 'action_view/template_error'
@@ -0,0 +1,171 @@
1
+ require 'cgi'
2
+ require File.dirname(__FILE__) + '/form_helper'
3
+
4
+ module ActionView
5
+ class Base
6
+ @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>" }
7
+ cattr_accessor :field_error_proc
8
+ end
9
+
10
+ module Helpers
11
+ # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the form
12
+ # method that creates a complete form for all the basic content types of the record (not associations or aggregations, though). This
13
+ # is a great of making the record quickly available for editing, but likely to prove lacklusters for a complicated real-world form.
14
+ # In that case, it's better to use the input method and the specialized form methods in link:classes/ActionView/Helpers/FormHelper.html
15
+ module ActiveRecordHelper
16
+ # Returns a default input tag for the type of object returned by the method. Example
17
+ # (title is a VARCHAR column and holds "Hello World"):
18
+ # input("post", "title") =>
19
+ # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
20
+ def input(record_name, method)
21
+ InstanceTag.new(record_name, method, self).to_tag
22
+ end
23
+
24
+ # Returns an entire form with input tags and everything for a specified Active Record object. Example
25
+ # (post is a new record that has a title using VARCHAR and a body using TEXT):
26
+ # form("post") =>
27
+ # <form action='create' method='POST'>
28
+ # <p>
29
+ # <b>Title</b><br />
30
+ # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
31
+ # </p>
32
+ # <p>
33
+ # <b>Body</b><br />
34
+ # <textarea cols="40" id="post_body" name="post[body]" rows="20" wrap="virtual">
35
+ # Back to the hill and over it again!
36
+ # </textarea>
37
+ # </p>
38
+ # <input type='submit' value='Create' />
39
+ # </form>
40
+ #
41
+ # It's possible to specialize the form builder by using a different action name and by supplying another
42
+ # block renderer. Example (entry is a new record that has a message attribute using VARCHAR):
43
+ #
44
+ # form("entry", :action => "sign", :input_block =>
45
+ # Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}<br />" }) =>
46
+ #
47
+ # <form action='sign' method='POST'>
48
+ # Message:
49
+ # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /><br />
50
+ # <input type='submit' value='Sign' />
51
+ # </form>
52
+ def form(record_name, options = {})
53
+ record = instance_eval("@#{record_name}")
54
+ action = options[:action] || (record.new_record? ? "create" : "update")
55
+ id_field = record.new_record? ? "" : InstanceTag.new(record_name, "id", self).to_input_field_tag("hidden")
56
+
57
+ "<form action='#{action}' method='POST'>" +
58
+ id_field + all_input_tags(record, record_name, options) +
59
+ "<input type='submit' value='#{action.gsub(/[^A-Za-z]/, "").capitalize}' />" +
60
+ "</form>"
61
+ end
62
+
63
+ # Returns a string containing the error message attached to the +method+ on the +object+, if one exists.
64
+ # This error message is wrapped in a DIV tag, which can be specialized to include both a +prepend_text+ and +append_text+
65
+ # to properly introduce the error and a +css_class+ to style it accordingly. Examples (post has an error message
66
+ # "can't be empty" on the title attribute):
67
+ #
68
+ # <%= error_message_on "post", "title" %> =>
69
+ # <div class="formError">can't be empty</div>
70
+ #
71
+ # <%= error_message_on "post", "title", "Title simply ", " (or it won't work)", "inputError" %> =>
72
+ # <div class="inputError">Title simply can't be empty (or it won't work)</div>
73
+ def error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError")
74
+ if instance_eval("@#{object}").errors.on(method)
75
+ "<div class=\"#{css_class}\">#{prepend_text + instance_eval("@#{object}").errors.on(method) + append_text}</div>"
76
+ end
77
+ end
78
+
79
+ def error_messages_for(object_name)
80
+ object = instance_eval("@#{object_name}")
81
+ unless object.errors.empty?
82
+ "<div id=\"errorExplanation\">" +
83
+ "<h2>#{object.errors.count} error#{"s" unless object.errors.count == 1} prohibited this #{object_name.gsub("_", " ")} from being saved</h2>" +
84
+ "<p>There were problems with the following fields (marked in red below):</p>" +
85
+ "<ul>#{object.errors.full_messages.collect { |msg| "<li>#{msg}</li>"}}</ul>" +
86
+ "</div>"
87
+ end
88
+ end
89
+
90
+ private
91
+ def all_input_tags(record, record_name, options)
92
+ input_block = options[:input_block] || default_input_block
93
+ record.class.content_columns.collect{ |column| input_block.call(record_name, column) }.join("\n")
94
+ end
95
+
96
+ def default_input_block
97
+ Proc.new { |record, column| "<p><b>#{column.human_name}</b><br />#{input(record, column.name)}</p>" }
98
+ end
99
+ end
100
+
101
+ class InstanceTag #:nodoc:
102
+ def to_tag(options = {})
103
+ case column_type
104
+ when :string
105
+ field_type = @method_name.include?("password") ? "password" : "text"
106
+ to_input_field_tag(field_type, options)
107
+ when :text
108
+ to_text_area_tag(options)
109
+ when :integer, :float
110
+ to_input_field_tag("text", options)
111
+ when :date
112
+ to_date_select_tag(options)
113
+ when :datetime
114
+ to_datetime_select_tag(options)
115
+ when :boolean
116
+ to_boolean_select_tag(options)
117
+ end
118
+ end
119
+
120
+ alias_method :tag_without_error_wrapping, :tag
121
+
122
+ def tag(name, options)
123
+ if object.respond_to?("errors") && object.errors.respond_to?("on")
124
+ error_wrapping(tag_without_error_wrapping(name, options), object.errors.on(@method_name))
125
+ else
126
+ tag_without_error_wrapping(name, options)
127
+ end
128
+ end
129
+
130
+ alias_method :content_tag_without_error_wrapping, :content_tag
131
+
132
+ def content_tag(name, value, options)
133
+ if object.respond_to?("errors") && object.errors.respond_to?("on")
134
+ error_wrapping(content_tag_without_error_wrapping(name, value, options), object.errors.on(@method_name))
135
+ else
136
+ content_tag_without_error_wrapping(name, value, options)
137
+ end
138
+ end
139
+
140
+ alias_method :to_date_select_tag_without_error_wrapping, :to_date_select_tag
141
+ def to_date_select_tag(options = {})
142
+ if object.respond_to?("errors") && object.errors.respond_to?("on")
143
+ error_wrapping(to_date_select_tag_without_error_wrapping(options), object.errors.on(@method_name))
144
+ else
145
+ to_date_select_tag_without_error_wrapping(options)
146
+ end
147
+ end
148
+
149
+ alias_method :to_datetime_select_tag_without_error_wrapping, :to_datetime_select_tag
150
+ def to_datetime_select_tag(options = {})
151
+ if object.respond_to?("errors") && object.errors.respond_to?("on")
152
+ error_wrapping(to_datetime_select_tag_without_error_wrapping(options), object.errors.on(@method_name))
153
+ else
154
+ to_datetime_select_tag_without_error_wrapping(options)
155
+ end
156
+ end
157
+
158
+ def error_wrapping(html_tag, has_error)
159
+ has_error ? Base.field_error_proc.call(html_tag, self) : html_tag
160
+ end
161
+
162
+ def error_message
163
+ object.errors.on(@method_name)
164
+ end
165
+
166
+ def column_type
167
+ object.send("column_for_attribute", @method_name).type
168
+ end
169
+ end
170
+ end
171
+ end