Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of github.com:lifo/docrails

  • Loading branch information...
commit 72973a30704894c808836d80a001208c1af39e7c 2 parents 0118636 + 0ad2146
@alvaropereyra alvaropereyra authored
Showing with 2,973 additions and 639 deletions.
  1. +1 −0  Rakefile
  2. +1 −0  actionmailer/actionmailer.gemspec
  3. +1 −0  actionmailer/lib/action_mailer/delivery_methods.rb
  4. +1 −0  actionmailer/lib/rails/generators/mailer/templates/mailer.rb
  5. +19 −0 actionpack/CHANGELOG.md
  6. +1 −0  actionpack/actionpack.gemspec
  7. +9 −9 actionpack/examples/performance.rb
  8. +1 −1  actionpack/lib/abstract_controller/base.rb
  9. +1 −0  actionpack/lib/abstract_controller/helpers.rb
  10. +1 −2  actionpack/lib/abstract_controller/layouts.rb
  11. +1 −0  actionpack/lib/action_controller/base.rb
  12. +3 −2 actionpack/lib/action_controller/caching/actions.rb
  13. +1 −3 actionpack/lib/action_controller/log_subscriber.rb
  14. +2 −0  actionpack/lib/action_controller/metal.rb
  15. +4 −1 actionpack/lib/action_controller/metal/exceptions.rb
  16. +1 −0  actionpack/lib/action_controller/metal/helpers.rb
  17. +1 −0  actionpack/lib/action_controller/metal/mime_responds.rb
  18. +2 −1  actionpack/lib/action_controller/metal/params_wrapper.rb
  19. +10 −0 actionpack/lib/action_controller/metal/responder.rb
  20. +1 −0  actionpack/lib/action_controller/metal/streaming.rb
  21. +2 −0  actionpack/lib/action_dispatch/http/mime_negotiation.rb
  22. +10 −3 actionpack/lib/action_dispatch/http/request.rb
  23. +2 −1  actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
  24. +1 −0  actionpack/lib/action_dispatch/middleware/reloader.rb
  25. +8 −0 actionpack/lib/action_dispatch/request/session.rb
  26. +1 −0  actionpack/lib/action_dispatch/routing.rb
  27. +4 −3 actionpack/lib/action_dispatch/routing/mapper.rb
  28. +2 −0  actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
  29. +10 −0 actionpack/lib/action_dispatch/routing/redirection.rb
  30. +17 −3 actionpack/lib/action_dispatch/routing/route_set.rb
  31. +1 −0  actionpack/lib/action_dispatch/routing/url_for.rb
  32. +1 −1  actionpack/lib/action_dispatch/testing/assertions/response.rb
  33. +14 −7 actionpack/lib/action_dispatch/testing/assertions/routing.rb
  34. +3 −4 actionpack/lib/action_dispatch/testing/integration.rb
  35. +1 −1  actionpack/lib/action_dispatch/testing/test_request.rb
  36. +1 −0  actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
  37. +1 −0  actionpack/lib/action_view/helpers/capture_helper.rb
  38. +89 −1 actionpack/lib/action_view/helpers/form_helper.rb
  39. +3 −0  actionpack/lib/action_view/helpers/form_options_helper.rb
  40. +55 −0 actionpack/lib/action_view/helpers/form_tag_helper.rb
  41. +1 −0  actionpack/lib/action_view/helpers/number_helper.rb
  42. +1 −0  actionpack/lib/action_view/helpers/output_safety_helper.rb
  43. +2 −0  actionpack/lib/action_view/helpers/record_tag_helper.rb
  44. +1 −0  actionpack/lib/action_view/helpers/rendering_helper.rb
  45. +12 −0 actionpack/lib/action_view/helpers/sanitize_helper.rb
  46. +1 −1  actionpack/lib/action_view/helpers/tag_helper.rb
  47. +5 −0 actionpack/lib/action_view/helpers/tags.rb
  48. +25 −0 actionpack/lib/action_view/helpers/tags/color_field.rb
  49. +6 −7 actionpack/lib/action_view/helpers/tags/date_field.rb
  50. +22 −0 actionpack/lib/action_view/helpers/tags/datetime_field.rb
  51. +19 −0 actionpack/lib/action_view/helpers/tags/datetime_local_field.rb
  52. +13 −0 actionpack/lib/action_view/helpers/tags/month_field.rb
  53. +1 −0  actionpack/lib/action_view/helpers/tags/select.rb
  54. +6 −7 actionpack/lib/action_view/helpers/tags/time_field.rb
  55. +13 −0 actionpack/lib/action_view/helpers/tags/week_field.rb
  56. +23 −11 actionpack/lib/action_view/helpers/text_helper.rb
  57. +2 −2 actionpack/lib/action_view/helpers/translation_helper.rb
  58. +1 −0  actionpack/lib/action_view/helpers/url_helper.rb
  59. +22 −10 actionpack/lib/action_view/template.rb
  60. +1 −0  actionpack/lib/action_view/template/resolver.rb
  61. +30 −1 actionpack/test/controller/caching_test.rb
  62. +8 −0 actionpack/test/controller/params_wrapper_test.rb
  63. +5 −5 actionpack/test/controller/resources_test.rb
  64. +10 −0 actionpack/test/controller/routing_test.rb
  65. +6 −0 actionpack/test/dispatch/debug_exceptions_test.rb
  66. +11 −0 actionpack/test/dispatch/request/query_string_parsing_test.rb
  67. +16 −0 actionpack/test/dispatch/request/session_test.rb
  68. +11 −0 actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
  69. +1 −1  actionpack/test/dispatch/request_test.rb
  70. +6 −6 actionpack/test/dispatch/routing_assertions_test.rb
  71. +32 −1 actionpack/test/dispatch/routing_test.rb
  72. +7 −0 actionpack/test/dispatch/test_request_test.rb
  73. +3 −0  actionpack/test/lib/controller/fake_models.rb
  74. +171 −0 actionpack/test/template/form_helper_test.rb
  75. +25 −0 actionpack/test/template/form_tag_helper_test.rb
  76. +53 −14 actionpack/test/template/text_helper_test.rb
  77. +13 −3 actionpack/test/template/translation_helper_test.rb
  78. +1 −1  actionpack/test/ts_isolated.rb
  79. +1 −0  activemodel/activemodel.gemspec
  80. +5 −4 activemodel/lib/active_model/attribute_methods.rb
  81. +1 −0  activemodel/lib/active_model/callbacks.rb
  82. +1 −0  activemodel/lib/active_model/conversion.rb
  83. +1 −0  activemodel/lib/active_model/errors.rb
  84. +2 −0  activemodel/lib/active_model/lint.rb
  85. +4 −2 activemodel/lib/active_model/mass_assignment_security.rb
  86. +2 −0  activemodel/lib/active_model/observing.rb
  87. +1 −0  activemodel/lib/active_model/serialization.rb
  88. +1 −1  activemodel/lib/active_model/serializers/xml.rb
  89. +2 −0  activemodel/lib/active_model/validations.rb
  90. +1 −0  activemodel/lib/active_model/validations/validates.rb
  91. +2 −0  activemodel/lib/active_model/validator.rb
  92. +22 −0 activemodel/test/cases/attribute_methods_test.rb
  93. +1 −1  activemodel/test/cases/serializers/xml_serialization_test.rb
  94. +1 −0  activemodel/test/cases/validations/i18n_validation_test.rb
  95. +1 −0  activerecord/activerecord.gemspec
  96. +9 −7 activerecord/lib/active_record/aggregations.rb
  97. +1 −0  activerecord/lib/active_record/associations/association.rb
  98. +596 −33 activerecord/lib/active_record/associations/collection_proxy.rb
  99. +1 −1  activerecord/lib/active_record/associations/preloader.rb
  100. +1 −0  activerecord/lib/active_record/callbacks.rb
  101. +23 −10 activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
  102. +1 −0  activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
  103. +1 −0  activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
  104. +1 −1  activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
  105. +1 −0  activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
  106. +20 −15 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  107. +1 −0  activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
  108. +4 −3 activerecord/lib/active_record/core.rb
  109. +1 −0  activerecord/lib/active_record/locking/optimistic.rb
  110. +1 −0  activerecord/lib/active_record/model.rb
  111. +1 −0  activerecord/lib/active_record/observer.rb
  112. +1 −0  activerecord/lib/active_record/persistence.rb
  113. +3 −2 activerecord/lib/active_record/railties/databases.rake
  114. +6 −0 activerecord/lib/active_record/reflection.rb
  115. +2 −1  activerecord/lib/active_record/relation/calculations.rb
  116. +1 −0  activerecord/lib/active_record/relation/finder_methods.rb
  117. +3 −0  activerecord/lib/active_record/relation/query_methods.rb
  118. +3 −0  activerecord/lib/active_record/relation/spawn_methods.rb
  119. +2 −2 activerecord/lib/active_record/serializers/xml_serializer.rb
  120. +27 −10 activerecord/lib/active_record/store.rb
  121. +3 −1 activerecord/lib/active_record/transactions.rb
  122. +1 −0  activerecord/lib/active_record/validations/uniqueness.rb
  123. +18 −0 activerecord/test/cases/aggregations_test.rb
  124. +1 −0  activerecord/test/cases/attribute_methods_test.rb
  125. +2 −2 activerecord/test/cases/connection_pool_test.rb
  126. +2 −2 activerecord/test/cases/pooled_connections_test.rb
  127. +1 −1  activerecord/test/cases/reaper_test.rb
  128. +1 −1  activerecord/test/cases/relations_test.rb
  129. +34 −0 activerecord/test/cases/store_test.rb
  130. +10 −0 activerecord/test/cases/transactions_test.rb
  131. +1 −0  activerecord/test/cases/validations/i18n_validation_test.rb
  132. +7 −7 activerecord/test/cases/xml_serialization_test.rb
  133. +4 −0 activerecord/test/models/customer.rb
  134. +1 −0  activerecord/test/models/subject.rb
  135. +12 −0 activesupport/CHANGELOG.md
  136. +1 −0  activesupport/activesupport.gemspec
  137. +1 −0  activesupport/lib/active_support.rb
  138. +1 −0  activesupport/lib/active_support/benchmarkable.rb
  139. +1 −1  activesupport/lib/active_support/cache.rb
  140. +2 −1  activesupport/lib/active_support/cache/file_store.rb
  141. +1 −0  activesupport/lib/active_support/callbacks.rb
  142. +1 −0  activesupport/lib/active_support/concern.rb
  143. +2 −0  activesupport/lib/active_support/configurable.rb
  144. +16 −8 activesupport/lib/active_support/core_ext/array/access.rb
  145. +52 −4 activesupport/lib/active_support/core_ext/array/conversions.rb
  146. +13 −10 activesupport/lib/active_support/core_ext/array/grouping.rb
  147. +1 −0  activesupport/lib/active_support/core_ext/array/uniq_by.rb
  148. +4 −2 activesupport/lib/active_support/core_ext/class/attribute.rb
  149. +10 −4 activesupport/lib/active_support/core_ext/class/subclasses.rb
  150. +1 −1  activesupport/lib/active_support/core_ext/date/calculations.rb
  151. +8 −2 activesupport/lib/active_support/core_ext/enumerable.rb
  152. +3 −3 activesupport/lib/active_support/core_ext/hash/conversions.rb
  153. +1 −0  activesupport/lib/active_support/core_ext/hash/except.rb
  154. +2 −0  activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
  155. +98 −20 activesupport/lib/active_support/core_ext/hash/keys.rb
  156. +2 −0  activesupport/lib/active_support/core_ext/integer/inflections.rb
  157. +2 −0  activesupport/lib/active_support/core_ext/kernel/reporting.rb
  158. +1 −0  activesupport/lib/active_support/core_ext/module/anonymous.rb
  159. +6 −6 activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
  160. +1 −0  activesupport/lib/active_support/core_ext/module/delegation.rb
  161. +2 −0  activesupport/lib/active_support/core_ext/module/introspection.rb
  162. +7 −0 activesupport/lib/active_support/core_ext/object/blank.rb
  163. +2 −0  activesupport/lib/active_support/core_ext/object/deep_dup.rb
  164. +5 −0 activesupport/lib/active_support/core_ext/object/duplicable.rb
  165. +4 −0 activesupport/lib/active_support/core_ext/object/try.rb
  166. +1 −0  activesupport/lib/active_support/core_ext/object/with_options.rb
  167. +1 −1  activesupport/lib/active_support/core_ext/string/filters.rb
  168. +1 −0  activesupport/lib/active_support/core_ext/string/inflections.rb
  169. +1 −0  activesupport/lib/active_support/core_ext/string/output_safety.rb
  170. +0 −1  activesupport/lib/active_support/dependencies/autoload.rb
  171. +1 −0  activesupport/lib/active_support/file_update_checker.rb
  172. +8 −0 activesupport/lib/active_support/hash_with_indifferent_access.rb
  173. +20 −2 activesupport/lib/active_support/inflector/methods.rb
  174. +1 −0  activesupport/lib/active_support/lazy_load_hooks.rb
  175. +1 −0  activesupport/lib/active_support/log_subscriber.rb
  176. +2 −0  activesupport/lib/active_support/log_subscriber/test_helper.rb
  177. +1 −0  activesupport/lib/active_support/message_encryptor.rb
  178. +1 −0  activesupport/lib/active_support/notifications.rb
  179. +1 −0  activesupport/lib/active_support/ordered_options.rb
  180. +1 −0  activesupport/lib/active_support/string_inquirer.rb
  181. +2 −0  activesupport/lib/active_support/time_with_zone.rb
  182. +5 −4 activesupport/lib/active_support/xml_mini.rb
  183. +9 −0 activesupport/test/caching_test.rb
  184. +37 −0 activesupport/test/constantize_test_cases.rb
  185. +7 −0 activesupport/test/core_ext/class/attribute_test.rb
  186. +5 −0 activesupport/test/core_ext/enumerable_test.rb
  187. +203 −2 activesupport/test/core_ext/hash_ext_test.rb
  188. +4 −0 activesupport/test/core_ext/string_ext_test.rb
  189. +1 −1  activesupport/test/ts_isolated.rb
  190. BIN  guides/assets/images/belongs_to.png
  191. BIN  guides/assets/images/book_icon.gif
  192. BIN  guides/assets/images/challenge.png
  193. BIN  guides/assets/images/chapters_icon.gif
  194. BIN  guides/assets/images/check_bullet.gif
  195. BIN  guides/assets/images/credits_pic_blank.gif
  196. BIN  guides/assets/images/csrf.png
  197. BIN  guides/assets/images/customized_error_messages.png
  198. BIN  guides/assets/images/edge_badge.png
  199. BIN  guides/assets/images/error_messages.png
  200. BIN  guides/assets/images/getting_started/confirm_dialog.png
  201. BIN  guides/assets/images/getting_started/form_with_errors.png
  202. BIN  guides/assets/images/getting_started/index_action_with_edit_link.png
  203. BIN  guides/assets/images/getting_started/new_post.png
  204. BIN  guides/assets/images/getting_started/post_with_comments.png
  205. BIN  guides/assets/images/getting_started/routing_error_no_controller.png
  206. BIN  guides/assets/images/getting_started/routing_error_no_route_matches.png
  207. BIN  guides/assets/images/getting_started/show_action_for_posts.png
  208. BIN  guides/assets/images/getting_started/template_is_missing_posts_new.png
  209. BIN  guides/assets/images/getting_started/undefined_method_post_path.png
  210. BIN  guides/assets/images/getting_started/unknown_action_create_for_posts.png
  211. BIN  guides/assets/images/getting_started/unknown_action_new_for_posts.png
  212. BIN  guides/assets/images/grey_bullet.gif
  213. BIN  guides/assets/images/habtm.png
  214. BIN  guides/assets/images/has_many.png
  215. BIN  guides/assets/images/has_many_through.png
  216. BIN  guides/assets/images/has_one.png
  217. BIN  guides/assets/images/has_one_through.png
  218. BIN  guides/assets/images/header_backdrop.png
  219. BIN  guides/assets/images/i18n/demo_html_safe.png
  220. BIN  guides/assets/images/i18n/demo_localized_pirate.png
  221. BIN  guides/assets/images/i18n/demo_translated_en.png
  222. BIN  guides/assets/images/i18n/demo_translated_pirate.png
  223. BIN  guides/assets/images/i18n/demo_translation_missing.png
  224. BIN  guides/assets/images/i18n/demo_untranslated.png
  225. BIN  guides/assets/images/icons/callouts/1.png
  226. BIN  guides/assets/images/icons/callouts/10.png
  227. BIN  guides/assets/images/icons/callouts/11.png
  228. BIN  guides/assets/images/icons/callouts/12.png
  229. BIN  guides/assets/images/icons/callouts/13.png
  230. BIN  guides/assets/images/icons/callouts/14.png
  231. BIN  guides/assets/images/icons/callouts/15.png
  232. BIN  guides/assets/images/icons/callouts/2.png
  233. BIN  guides/assets/images/icons/callouts/3.png
  234. BIN  guides/assets/images/icons/callouts/4.png
  235. BIN  guides/assets/images/icons/callouts/5.png
  236. BIN  guides/assets/images/icons/callouts/6.png
  237. BIN  guides/assets/images/icons/callouts/7.png
  238. BIN  guides/assets/images/icons/callouts/8.png
  239. BIN  guides/assets/images/icons/callouts/9.png
  240. BIN  guides/assets/images/icons/caution.png
  241. BIN  guides/assets/images/icons/example.png
  242. BIN  guides/assets/images/icons/home.png
  243. BIN  guides/assets/images/icons/important.png
  244. BIN  guides/assets/images/icons/next.png
  245. BIN  guides/assets/images/icons/note.png
  246. BIN  guides/assets/images/icons/prev.png
  247. BIN  guides/assets/images/icons/tip.png
  248. BIN  guides/assets/images/icons/up.png
  249. BIN  guides/assets/images/icons/warning.png
  250. BIN  guides/assets/images/nav_arrow.gif
  251. BIN  guides/assets/images/oscardelben.jpg
  252. BIN  guides/assets/images/polymorphic.png
  253. BIN  guides/assets/images/rails_guides_logo.gif
  254. BIN  guides/assets/images/rails_welcome.png
  255. BIN  guides/assets/images/session_fixation.png
  256. BIN  guides/assets/images/tab_grey.gif
  257. BIN  guides/assets/images/tab_info.gif
  258. BIN  guides/assets/images/tab_note.gif
  259. BIN  guides/assets/images/tab_red.gif
  260. BIN  guides/assets/images/tab_yellow.gif
  261. BIN  guides/assets/images/tab_yellow.png
  262. BIN  guides/assets/images/validation_error_messages.png
  263. +35 −31 guides/source/action_view_overview.textile
  264. +53 −0 guides/source/active_support_core_extensions.textile
  265. +1 −1  guides/source/active_support_instrumentation.textile
  266. +96 −102 guides/source/command_line.textile
  267. +1 −1  guides/source/configuring.textile
  268. +60 −1 guides/source/contributing_to_ruby_on_rails.textile
  269. +4 −0 guides/source/credits.html.erb
  270. +1 −1  guides/source/debugging_rails_applications.textile
  271. +6 −0 guides/source/engines.textile
  272. +12 −2 guides/source/form_helpers.textile
  273. +42 −12 guides/source/getting_started.textile
  274. +166 −97 guides/source/initialization.textile
  275. +41 −21 guides/source/rails_on_rack.textile
  276. +9 −1 guides/source/routing.textile
  277. +45 −34 guides/source/security.textile
  278. +4 −0 guides/source/upgrading_ruby_on_rails.textile
  279. +1 −0  rails.gemspec
  280. +2 −0  railties/CHANGELOG.md
  281. +9 −4 railties/lib/rails/application.rb
  282. +2 −0  railties/lib/rails/application/finisher.rb
  283. +1 −1  railties/lib/rails/application/route_inspector.rb
  284. +1 −1  railties/lib/rails/commands/console.rb
  285. +7 −2 railties/lib/rails/commands/dbconsole.rb
  286. +1 −1  railties/lib/rails/commands/runner.rb
  287. +1 −1  railties/lib/rails/commands/server.rb
  288. +6 −5 railties/lib/rails/configuration.rb
  289. +17 −6 railties/lib/rails/engine.rb
  290. +2 −1  railties/lib/rails/engine/configuration.rb
  291. +2 −3 railties/lib/rails/generators/actions.rb
  292. +2 −1  railties/lib/rails/generators/active_model.rb
  293. +1 −0  railties/lib/rails/generators/base.rb
  294. +5 −0 railties/lib/rails/generators/named_base.rb
  295. +4 −3 railties/lib/rails/generators/rails/app/templates/config/routes.rb
  296. +4 −0 railties/lib/rails/generators/rails/controller/templates/controller.rb
  297. +13 −13 railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb
  298. +4 −0 railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
  299. +2 −0  railties/lib/rails/generators/resource_helpers.rb
  300. +13 −0 railties/lib/rails/generators/test_case.rb
Sorry, we could not display the entire diff because too many files (320) changed.
View
1  Rakefile
@@ -179,6 +179,7 @@ end
# We publish a new version by tagging, and pushing a tag does not trigger
# that webhook. Stable docs would be updated by any subsequent regular
# push, but if you want that to happen right away just run this.
+#
desc 'Publishes docs, run this AFTER a new stable tag has been pushed'
task :publish_docs do
Net::HTTP.new('api.rubyonrails.org', 8080).start do |http|
View
1  actionmailer/actionmailer.gemspec
@@ -7,6 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Email composition, delivery, and receiving framework (part of Rails).'
s.description = 'Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.'
s.required_ruby_version = '>= 1.9.3'
+ s.license = 'MIT'
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
View
1  actionmailer/lib/action_mailer/delivery_methods.rb
@@ -50,6 +50,7 @@ module ClassMethods
# add_delivery_method :sendmail, Mail::Sendmail,
# :location => '/usr/sbin/sendmail',
# :arguments => '-i -t'
+ #
def add_delivery_method(symbol, klass, default_options={})
class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings")
send(:"#{symbol}_settings=", default_options)
View
1  actionmailer/lib/rails/generators/mailer/templates/mailer.rb
@@ -7,6 +7,7 @@ class <%= class_name %> < ActionMailer::Base
# with the following lookup:
#
# en.<%= file_path.tr("/",".") %>.<%= action %>.subject
+ #
def <%= action %>
@greeting = "Hi"
View
19 actionpack/CHANGELOG.md
@@ -1,5 +1,24 @@
## Rails 4.0.0 (unreleased) ##
+* `truncate` now always returns an escaped HTMl-safe string. The option `:escape` can be used as
+ false to not escape the result.
+
+ *Li Ellis Gallardo + Rafael Mendonça França*
+
+* `truncate` now accepts a block to show extra content when the text is truncated. *Li Ellis Gallardo*
+
+* Add `week_field`, `week_field_tag`, `month_field`, `month_field_tag`, `datetime_local_field`,
+ `datetime_local_field_tag`, `datetime_field` and `datetime_field_tag` helpers. *Carlos Galdino*
+
+* Add `color_field` and `color_field_tag` helpers. *Carlos Galdino*
+
+* `assert_generates`, `assert_recognizes`, and `assert_routing` all raise
+ `Assertion` instead of `RoutingError` *David Chelimsky*
+
+* URL path parameters with invalid encoding now raise ActionController::BadRequest. *Andrew White*
+
+* Malformed query and request parameter hashes now raise ActionController::BadRequest. *Andrew White*
+
* Add `divider` option to `grouped_options_for_select` to generate a separator
`optgroup` automatically, and deprecate `prompt` as third argument, in favor
of using an options hash. *Nicholas Greenfield*
View
1  actionpack/actionpack.gemspec
@@ -7,6 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).'
s.description = 'Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server.'
s.required_ruby_version = '>= 1.9.3'
+ s.license = 'MIT'
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
View
18 actionpack/examples/performance.rb
@@ -166,15 +166,7 @@ def run_all!(times, verbose)
Runner.run(:diff_100, times, verbose)
end
-unless ENV["PROFILE"]
- run_all!(1, false)
-
- (ENV["M"] || 1).to_i.times do
- $ran = []
- run_all!(N, true)
- Runner.done
- end
-else
+if ENV["PROFILE"]
Runner.run(ENV["PROFILE"].to_sym, 1, false)
require "ruby-prof"
RubyProf.start
@@ -182,4 +174,12 @@ def run_all!(times, verbose)
result = RubyProf.stop
printer = RubyProf::CallStackPrinter.new(result)
printer.print(File.open("output.html", "w"))
+else
+ run_all!(1, false)
+
+ (ENV["M"] || 1).to_i.times do
+ $ran = []
+ run_all!(N, true)
+ Runner.done
+ end
end
View
2  actionpack/lib/abstract_controller/base.rb
@@ -141,7 +141,7 @@ def action_methods
#
# Notice that <tt>action_methods.include?("foo")</tt> may return
# false and <tt>available_action?("foo")</tt> returns true because
- # available action consider actions that are also available
+ # this method considers actions that are also available
# through other means, for example, implicit render ones.
#
# ==== Parameters
View
1  actionpack/lib/abstract_controller/helpers.rb
@@ -90,6 +90,7 @@ def #{meth}(*args, &blk) # def current_user(*args,
# +symbols+, +strings+, +modules+ and blocks.
#
# helper(:three, BlindHelper) { def mice() 'mice' end }
+ #
def helper(*args, &block)
modules_for_helpers(args).each do |mod|
add_template_helper(mod)
View
3  actionpack/lib/abstract_controller/layouts.rb
@@ -203,8 +203,7 @@ module Layouts
include Rendering
included do
- class_attribute :_layout, :_layout_conditions,
- :instance_reader => false, :instance_writer => false
+ class_attribute :_layout, :_layout_conditions, :instance_accessor => false
self._layout = nil
self._layout_conditions = {}
_write_layout_method
View
1  actionpack/lib/action_controller/base.rb
@@ -167,6 +167,7 @@ module ActionController
# redirect_to(:action => "elsewhere") and return if monkeys.nil?
# render :action => "overthere" # won't be called if monkeys is nil
# end
+ #
class Base < Metal
abstract!
View
5 actionpack/lib/action_controller/caching/actions.rb
@@ -47,7 +47,7 @@ module Caching
# And you can also use <tt>:if</tt> (or <tt>:unless</tt>) to pass a
# proc that specifies when the action should be cached.
#
- # As of Rails 3.0, you can also pass <tt>:expires_in</tt> with a time
+ # As of Rails 3.0, you can also pass <tt>:expires_in</tt> with a time
# interval (in seconds) to schedule expiration of the cached item.
#
# The following example depicts some of the points made above:
@@ -178,8 +178,9 @@ def initialize(controller, options = {}, infer_extension = true)
private
def normalize!(path)
+ ext = URI.parser.escape(extension) if extension
path << 'index' if path[-1] == ?/
- path << ".#{extension}" if extension and !path.split('?', 2).first.ends_with?(".#{extension}")
+ path << ".#{ext}" if extension and !path.split('?', 2).first.ends_with?(".#{ext}")
URI.parser.unescape(path)
end
end
View
4 actionpack/lib/action_controller/log_subscriber.rb
@@ -33,9 +33,7 @@ def halted_callback(event)
end
def send_file(event)
- message = "Sent file %s"
- message << " (%.1fms)"
- info(message % [event.payload[:path], event.duration])
+ info("Sent file %s (%.1fms)" % [event.payload[:path], event.duration])
end
def redirect_to(event)
View
2  actionpack/lib/action_controller/metal.rb
@@ -9,6 +9,7 @@ module ActionController
# class PostsController < ApplicationController
# use AuthenticationMiddleware, :except => [:index, :show]
# end
+ #
class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc:
class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc:
def initialize(klass, *args, &block)
@@ -96,6 +97,7 @@ def build(action, app=nil, &block)
#
# You can refer to the modules included in <tt>ActionController::Base</tt> to see
# other features you can bring into your metal controller.
+ #
class Metal < AbstractController::Base
abstract!
View
5 actionpack/lib/action_controller/metal/exceptions.rb
@@ -2,6 +2,9 @@ module ActionController
class ActionControllerError < StandardError #:nodoc:
end
+ class BadRequest < ActionControllerError #:nodoc:
+ end
+
class RenderError < ActionControllerError #:nodoc:
end
@@ -38,7 +41,7 @@ def initialize(message = nil)
class UnknownHttpMethod < ActionControllerError #:nodoc:
end
-
+
class UnknownFormat < ActionControllerError #:nodoc:
end
end
View
1  actionpack/lib/action_controller/metal/helpers.rb
@@ -47,6 +47,7 @@ module ActionController
#
# 23 Aug 11:30 | Carolina Railhawks Soccer Match
# N/A | Carolina Railhaws Training Workshop
+ #
module Helpers
extend ActiveSupport::Concern
View
1  actionpack/lib/action_controller/metal/mime_responds.rb
@@ -52,6 +52,7 @@ def respond_to(*mimes)
end
# Clear all mime types in <tt>respond_to</tt>.
+ #
def clear_respond_to
self.mimes_for_respond_to = Hash.new.freeze
end
View
3  actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -193,7 +193,8 @@ def _set_wrapper_defaults(options, model=nil)
def process_action(*args)
if _wrapper_enabled?
wrapped_hash = _wrap_parameters request.request_parameters
- wrapped_filtered_hash = _wrap_parameters request.filtered_parameters
+ wrapped_keys = request.request_parameters.keys
+ wrapped_filtered_hash = _wrap_parameters request.filtered_parameters.slice(*wrapped_keys)
# This will make the wrapped hash accessible from controller and view
request.parameters.merge! wrapped_hash
View
10 actionpack/lib/action_controller/metal/responder.rb
@@ -142,11 +142,13 @@ def initialize(controller, resources, options={})
# Initializes a new responder an invoke the proper format. If the format is
# not defined, call to_format.
+ #
def self.call(*args)
new(*args).respond
end
# Main entry point for responder responsible to dispatch to the proper format.
+ #
def respond
method = "to_#{format}"
respond_to?(method) ? send(method) : to_format
@@ -154,6 +156,7 @@ def respond
# HTML format does not render the resource, it always attempt to render a
# template.
+ #
def to_html
default_render
rescue ActionView::MissingTemplate => e
@@ -168,6 +171,7 @@ def to_js
# All other formats follow the procedure below. First we try to render a
# template, if the template is not available, we verify if the resource
# responds to :to_format and display it.
+ #
def to_format
if get? || !has_errors? || response_overridden?
default_render
@@ -205,12 +209,14 @@ def api_behavior(error)
end
# Checks whether the resource responds to the current format or not.
+ #
def resourceful?
resource.respond_to?("to_#{format}")
end
# Returns the resource location by retrieving it from the options or
# returning the resources array.
+ #
def resource_location
options[:location] || resources
end
@@ -219,6 +225,7 @@ def resource_location
# If a response block was given, use it, otherwise call render on
# controller.
+ #
def default_render
if @default_response
@default_response.call(options)
@@ -243,6 +250,7 @@ def default_render
# Results in:
#
# render :xml => @user, :status => :created
+ #
def display(resource, given_options={})
controller.render given_options.merge!(options).merge!(format => resource)
end
@@ -252,12 +260,14 @@ def display_errors
end
# Check whether the resource has errors.
+ #
def has_errors?
resource.respond_to?(:errors) && !resource.errors.empty?
end
# By default, render the <code>:edit</code> action for HTML requests with errors, unless
# the verb was POST.
+ #
def default_action
@action ||= DEFAULT_ACTIONS_FOR_VERBS[request.request_method_symbol]
end
View
1  actionpack/lib/action_controller/metal/streaming.rb
@@ -194,6 +194,7 @@ module ActionController #:nodoc:
# ==== Passenger
#
# To be described.
+ #
module Streaming
extend ActiveSupport::Concern
View
2  actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -46,6 +46,7 @@ def accepts
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first
+ #
def format(view_path = [])
formats.first
end
@@ -81,6 +82,7 @@ def format=(extension)
# Receives an array of mimes and return the first user sent mime that
# matches the order array.
+ #
def negotiate_mime(order)
formats.each do |priority|
if priority == Mime::ALL
View
13 actionpack/lib/action_dispatch/http/request.rb
@@ -231,17 +231,24 @@ def session_options=(options)
# Override Rack's GET method to support indifferent access
def GET
- @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {})
+ begin
+ @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {})
+ rescue TypeError => e
+ raise ActionController::BadRequest, "Invalid query parameters: #{e.message}"
+ end
end
alias :query_parameters :GET
# Override Rack's POST method to support indifferent access
def POST
- @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {})
+ begin
+ @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {})
+ rescue TypeError => e
+ raise ActionController::BadRequest, "Invalid request parameters: #{e.message}"
+ end
end
alias :request_parameters :POST
-
# Returns the authorization header regardless of whether it was specified directly or through one of the
# proxy alternatives.
def authorization
View
3  actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -12,7 +12,8 @@ class ExceptionWrapper
'ActionController::MethodNotAllowed' => :method_not_allowed,
'ActionController::NotImplemented' => :not_implemented,
'ActionController::UnknownFormat' => :not_acceptable,
- 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
+ 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
+ 'ActionController::BadRequest' => :bad_request
)
cattr_accessor :rescue_templates
View
1  actionpack/lib/action_dispatch/middleware/reloader.rb
@@ -22,6 +22,7 @@ module ActionDispatch
# is false. Callbacks may be registered even when it is not included in the
# middleware stack, but are executed only when <tt>ActionDispatch::Reloader.prepare!</tt>
# or <tt>ActionDispatch::Reloader.cleanup!</tt> are called manually.
+ #
class Reloader
include ActiveSupport::Callbacks
View
8 actionpack/lib/action_dispatch/request/session.rb
@@ -87,6 +87,14 @@ def has_key?(key)
alias :key? :has_key?
alias :include? :has_key?
+ def keys
+ @delegate.keys
+ end
+
+ def values
+ @delegate.values
+ end
+
def []=(key, value)
load_for_write!
@delegate[key.to_s] = value
View
1  actionpack/lib/action_dispatch/routing.rb
@@ -277,6 +277,7 @@ module ActionDispatch
# rake routes
#
# Target specific controllers by prefixing the command with <tt>CONTROLLER=x</tt>.
+ #
module Routing
autoload :Mapper, 'action_dispatch/routing/mapper'
autoload :RouteSet, 'action_dispatch/routing/route_set'
View
7 actionpack/lib/action_dispatch/routing/mapper.rb
@@ -897,6 +897,7 @@ def defaults_from_constraints(constraints)
# resources :articles, :id => /[^\/]+/
#
# This allows any character other than a slash as part of your +:id+.
+ #
module Resources
# CANONICAL_ACTIONS holds all actions that does not need a prefix or
# a path appended since they fit properly in their scope level.
@@ -1317,7 +1318,7 @@ def shallow?
def draw(name)
path = @draw_paths.find do |_path|
- _path.join("#{name}.rb").file?
+ File.exists? "#{_path}/#{name}.rb"
end
unless path
@@ -1327,8 +1328,8 @@ def draw(name)
raise ArgumentError, msg
end
- route_path = path.join("#{name}.rb")
- instance_eval(route_path.read, route_path.to_s)
+ route_path = "#{path}/#{name}.rb"
+ instance_eval(File.read(route_path), route_path.to_s)
end
# match 'path' => 'controller#action'
View
2  actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -51,6 +51,7 @@ module Routing
#
# polymorphic_url([blog, @post]) # calls blog.post_path(@post)
# form_for([blog, @post]) # => "/blog/posts/1"
+ #
module PolymorphicRoutes
# Constructs a call to a named RESTful route for the given record and returns the
# resulting URL string. For example:
@@ -83,6 +84,7 @@ module PolymorphicRoutes
#
# # the class of a record will also map to the collection
# polymorphic_url(Comment) # same as comments_url()
+ #
def polymorphic_url(record_or_hash_or_array, options = {})
if record_or_hash_or_array.kind_of?(Array)
record_or_hash_or_array = record_or_hash_or_array.compact
View
10 actionpack/lib/action_dispatch/routing/redirection.rb
@@ -2,6 +2,7 @@
require 'active_support/core_ext/uri'
require 'active_support/core_ext/array/extract_options'
require 'rack/utils'
+require 'action_controller/metal/exceptions'
module ActionDispatch
module Routing
@@ -16,6 +17,14 @@ def initialize(status, block)
def call(env)
req = Request.new(env)
+ # If any of the path parameters has a invalid encoding then
+ # raise since it's likely to trigger errors further on.
+ req.symbolized_path_parameters.each do |key, value|
+ unless value.valid_encoding?
+ raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
+ end
+ end
+
uri = URI.parse(path(req.symbolized_path_parameters, req))
uri.scheme ||= req.scheme
uri.host ||= req.host
@@ -121,6 +130,7 @@ module Redirection
# a string.
#
# match 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
+ #
def redirect(*args, &block)
options = args.extract_options!
status = options.delete(:status) || 301
View
20 actionpack/lib/action_dispatch/routing/route_set.rb
@@ -26,6 +26,15 @@ def initialize(options={})
def call(env)
params = env[PARAMETERS_KEY]
+
+ # If any of the path parameters has a invalid encoding then
+ # raise since it's likely to trigger errors further on.
+ params.each do |key, value|
+ unless value.valid_encoding?
+ raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
+ end
+ end
+
prepare_params!(params)
# Just raise undefined constant errors if a controller was specified as default.
@@ -180,6 +189,7 @@ def define_named_route_methods(name, route)
# Also allow options hash, so you can do:
#
# foo_url(bar, baz, bang, :sort_by => 'baz')
+ #
def define_url_helper(route, name, options)
selector = url_helper_name(name, options[:only_path])
@@ -653,9 +663,13 @@ def recognize_path(path, environment = {})
dispatcher = dispatcher.app
end
- if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false)
- dispatcher.prepare_params!(params)
- return params
+ if dispatcher.is_a?(Dispatcher)
+ if dispatcher.controller(params, false)
+ dispatcher.prepare_params!(params)
+ return params
+ else
+ raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
+ end
end
end
View
1  actionpack/lib/action_dispatch/routing/url_for.rb
@@ -79,6 +79,7 @@ module Routing
# end
#
# User.find(1).base_uri # => "/users/1"
+ #
module UrlFor
extend ActiveSupport::Concern
include PolymorphicRoutes
View
2  actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -28,7 +28,7 @@ def assert_response(type, message = nil)
assert @response.send("#{type}?"), message
else
code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type]
- assert_equal @response.response_code, code, message
+ assert_equal code, @response.response_code, message
end
else
assert_equal type, @response.response_code, message
View
21 actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -69,11 +69,9 @@ def assert_recognizes(expected_options, path, extras={}, message=nil)
# assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" }
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
if expected_path =~ %r{://}
- begin
+ fail_on(URI::InvalidURIError) do
uri = URI.parse(expected_path)
expected_path = uri.path.to_s.empty? ? "/" : uri.path
- rescue URI::InvalidURIError => e
- raise ActionController::RoutingError, e.message
end
else
expected_path = "/#{expected_path}" unless expected_path.first == '/'
@@ -140,6 +138,7 @@ def assert_routing(path, options, defaults={}, extras={}, message=nil)
# end
# end
# end
+ #
def with_routing
old_routes, @routes = @routes, ActionDispatch::Routing::RouteSet.new
if defined?(@controller) && @controller
@@ -188,14 +187,12 @@ def recognized_request_for(path, extras = {})
request = ActionController::TestRequest.new
if path =~ %r{://}
- begin
+ fail_on(URI::InvalidURIError) do
uri = URI.parse(path)
request.env["rack.url_scheme"] = uri.scheme || "http"
request.host = uri.host if uri.host
request.port = uri.port if uri.port
request.path = uri.path.to_s.empty? ? "/" : uri.path
- rescue URI::InvalidURIError => e
- raise ActionController::RoutingError, e.message
end
else
path = "/#{path}" unless path.first == "/"
@@ -204,11 +201,21 @@ def recognized_request_for(path, extras = {})
request.request_method = method if method
- params = @routes.recognize_path(path, { :method => method, :extras => extras })
+ params = fail_on(ActionController::RoutingError) do
+ @routes.recognize_path(path, { :method => method, :extras => extras })
+ end
request.path_parameters = params.with_indifferent_access
request
end
+
+ def fail_on(exception_class)
+ begin
+ yield
+ rescue exception_class => e
+ raise MiniTest::Assertion, e.message
+ end
+ end
end
end
end
View
7 actionpack/lib/action_dispatch/testing/integration.rb
@@ -17,8 +17,8 @@ module RequestHelpers
# a Hash, or a String that is appropriately encoded
# (<tt>application/x-www-form-urlencoded</tt> or
# <tt>multipart/form-data</tt>).
- # - +headers+: Additional HTTP headers to pass, as a Hash. The keys will
- # automatically be upcased, with the prefix 'HTTP_' added if needed.
+ # - +headers+: Additional headers to pass, as a Hash. The headers will be
+ # merged into the Rack env hash.
#
# This method returns an Response object, which one can use to
# inspect the details of the response. Furthermore, if this method was
@@ -73,8 +73,7 @@ def options(path, parameters = nil, headers = nil)
#
# The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or
# +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart
- # string; the headers are a hash. Keys are automatically upcased and
- # prefixed with 'HTTP_' if not already.
+ # string; the headers are a hash.
def xml_http_request(request_method, path, parameters = nil, headers = nil)
headers ||= {}
headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
View
2  actionpack/lib/action_dispatch/testing/test_request.rb
@@ -11,7 +11,7 @@ def self.new(env = {})
end
def initialize(env = {})
- env = Rails.application.env_config.merge(env) if defined?(Rails.application)
+ env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
super(DEFAULT_ENV.merge(env))
self.host = 'test.host'
View
1  actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
@@ -139,6 +139,7 @@ def stylesheet_url(source)
# you have too many stylesheets for IE to load.
#
# stylesheet_link_tag :all, :concat => true
+ #
def stylesheet_link_tag(*sources)
@stylesheet_include ||= StylesheetIncludeTag.new(config, asset_paths)
@stylesheet_include.include_tag(*sources)
View
1  actionpack/lib/action_view/helpers/capture_helper.rb
@@ -33,6 +33,7 @@ module CaptureHelper
# <body>
# <b><%= @greeting %></b>
# </body></html>
+ #
def capture(*args)
value = nil
buffer = with_output_buffer { value = yield(*args) }
View
90 actionpack/lib/action_view/helpers/form_helper.rb
@@ -342,7 +342,7 @@ def convert_to_model(object)
# Example:
#
# <%= form_for(@post) do |f| %>
- # <% f.fields_for(:comments, :include_id => false) do |cf| %>
+ # <%= f.fields_for(:comments, :include_id => false) do |cf| %>
# ...
# <% end %>
# <% end %>
@@ -763,6 +763,7 @@ def label(object_name, method, content_or_options = nil, options = nil, &block)
#
# text_field(:snippet, :code, :size => 20, :class => 'code_input')
# # => <input type="text" id="snippet_code" name="snippet[code]" size="20" value="#{@snippet.code}" class="code_input" />
+ #
def text_field(object_name, method, options = {})
Tags::TextField.new(object_name, method, self, options).render
end
@@ -784,6 +785,7 @@ def text_field(object_name, method, options = {})
#
# password_field(:account, :pin, :size => 20, :class => 'form_input')
# # => <input type="password" id="account_pin" name="account[pin]" size="20" class="form_input" />
+ #
def password_field(object_name, method, options = {})
Tags::PasswordField.new(object_name, method, self, options).render
end
@@ -822,6 +824,7 @@ def hidden_field(object_name, method, options = {})
#
# file_field(:attachment, :file, :class => 'file_input')
# # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
+ #
def file_field(object_name, method, options = {})
Tags::FileField.new(object_name, method, self, options).render
end
@@ -910,6 +913,7 @@ def text_area(object_name, method, options = {})
# check_box("eula", "accepted", { :class => 'eula_check' }, "yes", "no")
# # => <input name="eula[accepted]" type="hidden" value="no" />
# # <input type="checkbox" class="eula_check" id="eula_accepted" name="eula[accepted]" value="yes" />
+ #
def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
Tags::CheckBox.new(object_name, method, self, checked_value, unchecked_value, options).render
end
@@ -935,6 +939,15 @@ def radio_button(object_name, method, tag_value, options = {})
Tags::RadioButton.new(object_name, method, self, tag_value, options).render
end
+ # Returns a text_field of type "color".
+ #
+ # color_field("car", "color")
+ # # => <input id="car_color" name="car[color]" type="color" value="#000000" />
+ #
+ def color_field(object_name, method, options = {})
+ Tags::ColorField.new(object_name, method, self, options).render
+ end
+
# Returns an input of type "search" for accessing a specified attribute (identified by +method+) on an object
# assigned to the template (identified by +object_name+). Inputs of type "search" may be styled differently by
# some browsers.
@@ -962,6 +975,7 @@ def search_field(object_name, method, options = {})
#
# telephone_field("user", "phone")
# # => <input id="user_phone" name="user[phone]" type="tel" />
+ #
def telephone_field(object_name, method, options = {})
Tags::TelField.new(object_name, method, self, options).render
end
@@ -980,6 +994,7 @@ def telephone_field(object_name, method, options = {})
# @user.born_on = Date.new(1984, 1, 27)
# date_field("user", "born_on", value: "1984-05-12")
# # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-05-12" />
+ #
def date_field(object_name, method, options = {})
Tags::DateField.new(object_name, method, self, options).render
end
@@ -996,14 +1011,84 @@ def date_field(object_name, method, options = {})
# === Example
# time_field("task", "started_at")
# # => <input id="task_started_at" name="task[started_at]" type="time" />
+ #
def time_field(object_name, method, options = {})
Tags::TimeField.new(object_name, method, self, options).render
end
+ # Returns a text_field of type "datetime".
+ #
+ # datetime_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T.%L%z"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 12)
+ # datetime_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime" value="1984-01-12T00:00:00.000+0000" />
+ #
+ def datetime_field(object_name, method, options = {})
+ Tags::DatetimeField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "datetime-local".
+ #
+ # datetime_local_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 12)
+ # datetime_local_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" value="1984-01-12T00:00:00" />
+ #
+ def datetime_local_field(object_name, method, options = {})
+ Tags::DatetimeLocalField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "month".
+ #
+ # month_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="month" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 27)
+ # month_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-01" />
+ #
+ def month_field(object_name, method, options = {})
+ Tags::MonthField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "week".
+ #
+ # week_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="week" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-W%W"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 5, 12)
+ # week_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-W19" />
+ #
+ def week_field(object_name, method, options = {})
+ Tags::WeekField.new(object_name, method, self, options).render
+ end
+
# Returns a text_field of type "url".
#
# url_field("user", "homepage")
# # => <input id="user_homepage" name="user[homepage]" type="url" />
+ #
def url_field(object_name, method, options = {})
Tags::UrlField.new(object_name, method, self, options).render
end
@@ -1012,6 +1097,7 @@ def url_field(object_name, method, options = {})
#
# email_field("user", "address")
# # => <input id="user_address" name="user[address]" type="email" />
+ #
def email_field(object_name, method, options = {})
Tags::EmailField.new(object_name, method, self, options).render
end
@@ -1191,6 +1277,7 @@ def file_field(method, options = {})
# submit:
# post:
# create: "Add %{model}"
+ #
def submit(value=nil, options={})
value, options = nil, value if value.is_a?(Hash)
value ||= submit_default_value
@@ -1223,6 +1310,7 @@ def submit(value=nil, options={})
# submit:
# post:
# create: "Add %{model}"
+ #
def button(value=nil, options={})
value, options = nil, value if value.is_a?(Hash)
value ||= submit_default_value
View
3  actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -98,6 +98,7 @@ module Helpers
# <option value="3">Jokes</option>
# <option value="4">Poems</option>
# </select>
+ #
module FormOptionsHelper
# ERB::Util can mask some helpers like textilize. Make sure to include them.
include TextHelper
@@ -153,6 +154,7 @@ module FormOptionsHelper
# key in the query string, that works for ordinary forms.
#
# In case if you don't want the helper to generate this hidden field you can specify <tt>:include_blank => false</tt> option.
+ #
def select(object, method, choices, options = {}, html_options = {})
Tags::Select.new(object, method, self, choices, options, html_options).render
end
@@ -239,6 +241,7 @@ def collection_select(object, method, collection, value_method, text_method, opt
# <option value="2">Ireland</option>
# </optgroup>
# </select>
+ #
def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
Tags::GroupedCollectionSelect.new(object, method, self, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options).render
end
View
55 actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -63,6 +63,7 @@ module FormTagHelper
#
# form_tag('http://far.away.com/form', :authenticity_token => "cf50faa3fe97702ca1ae")
# # form with custom authenticity token
+ #
def form_tag(url_for_options = {}, options = {}, &block)
html_options = html_options_for_form(url_for_options, options)
if block_given?
@@ -408,6 +409,7 @@ def radio_button_tag(name, value, checked = false, options = {})
#
# submit_tag "Save", :confirm => "Are you sure?"
# # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
+ #
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
@@ -444,6 +446,7 @@ def submit_tag(value = "Save changes", options = {})
# # => <button name="button" type="button">
# # <strong>Ask me!</strong>
# # </button>
+ #
def button_tag(content_or_options = nil, options = nil, &block)
options = content_or_options if block_given? && content_or_options.is_a?(Hash)
options ||= {}
@@ -521,6 +524,14 @@ def field_set_tag(legend = nil, options = nil, &block)
output.safe_concat("</fieldset>")
end
+ # Creates a text field of type "color".
+ #
+ # ==== Options
+ # * Accepts the same options as text_field_tag.
+ def color_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "color"))
+ end
+
# Creates a text field of type "search".
#
# ==== Options
@@ -557,6 +568,50 @@ def time_field_tag(name, value = nil, options = {})
text_field_tag(name, value, options.stringify_keys.update("type" => "time"))
end
+ # Creates a text field of type "datetime".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def datetime_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "datetime"))
+ end
+
+ # Creates a text field of type "datetime-local".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def datetime_local_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "datetime-local"))
+ end
+
+ # Creates a text field of type "month".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def month_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "month"))
+ end
+
+ # Creates a text field of type "week".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def week_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "week"))
+ end
+
# Creates a text field of type "url".
#
# ==== Options
View
1  actionpack/lib/action_view/helpers/number_helper.rb
@@ -514,6 +514,7 @@ def number_to_human_size(number, options = {})
# number_to_human(343, :units => :distance, :precision => 1) # => "300 meters"
# number_to_human(1, :units => :distance) # => "1 meter"
# number_to_human(0.34, :units => :distance) # => "34 centimeters"
+ #
def number_to_human(number, options = {})
options = options.symbolize_keys
View
1  actionpack/lib/action_view/helpers/output_safety_helper.rb
@@ -26,6 +26,7 @@ def raw(stringish)
#
# safe_join(["<p>foo</p>".html_safe, "<p>bar</p>".html_safe], "<br />".html_safe)
# # => "<p>foo</p><br /><p>bar</p>"
+ #
def safe_join(array, sep=$,)
sep = ERB::Util.html_escape(sep)
View
2  actionpack/lib/action_view/helpers/record_tag_helper.rb
@@ -29,6 +29,7 @@ module RecordTagHelper
#
# <div id="person_123" class="person foo"> Joe Bloggs </div>
# <div id="person_124" class="person foo"> Jane Bloggs </div>
+ #
def div_for(record, *args, &block)
content_tag_for(:div, record, *args, &block)
end
@@ -78,6 +79,7 @@ def div_for(record, *args, &block)
# produces:
#
# <li id="person_123" class="person bar">...
+ #
def content_tag_for(tag_name, single_or_multiple_records, prefix = nil, options = nil, &block)
options, prefix = prefix, nil if prefix.is_a?(Hash)
View
1  actionpack/lib/action_view/helpers/rendering_helper.rb
@@ -75,6 +75,7 @@ def render(options = {}, locals = {}, &block)
# <html>
# Hello David
# </html>
+ #
def _layout_for(*args, &block)
name = args.first
View
12 actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -55,6 +55,7 @@ module SanitizeHelper
# resulting markup is valid (conforming to a document type) or even well-formed.
# The output may still contain e.g. unescaped '<', '>', '&' characters and
# confuse browsers.
+ #
def sanitize(html, options = {})
self.class.white_list_sanitizer.sanitize(html, options).try(:html_safe)
end
@@ -143,6 +144,7 @@ def sanitized_protocol_separator=(value)
# class Application < Rails::Application
# config.action_view.full_sanitizer = MySpecialSanitizer.new
# end
+ #
def full_sanitizer
@full_sanitizer ||= HTML::FullSanitizer.new
end
@@ -153,6 +155,7 @@ def full_sanitizer
# class Application < Rails::Application
# config.action_view.link_sanitizer = MySpecialSanitizer.new
# end
+ #
def link_sanitizer
@link_sanitizer ||= HTML::LinkSanitizer.new
end
@@ -163,6 +166,7 @@ def link_sanitizer
# class Application < Rails::Application
# config.action_view.white_list_sanitizer = MySpecialSanitizer.new
# end
+ #
def white_list_sanitizer
@white_list_sanitizer ||= HTML::WhiteListSanitizer.new
end
@@ -172,6 +176,7 @@ def white_list_sanitizer
# class Application < Rails::Application
# config.action_view.sanitized_uri_attributes = 'lowsrc', 'target'
# end
+ #
def sanitized_uri_attributes=(attributes)
HTML::WhiteListSanitizer.uri_attributes.merge(attributes)
end
@@ -181,6 +186,7 @@ def sanitized_uri_attributes=(attributes)
# class Application < Rails::Application
# config.action_view.sanitized_bad_tags = 'embed', 'object'
# end
+ #
def sanitized_bad_tags=(attributes)
HTML::WhiteListSanitizer.bad_tags.merge(attributes)
end
@@ -190,6 +196,7 @@ def sanitized_bad_tags=(attributes)
# class Application < Rails::Application
# config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
# end
+ #
def sanitized_allowed_tags=(attributes)
HTML::WhiteListSanitizer.allowed_tags.merge(attributes)
end
@@ -199,6 +206,7 @@ def sanitized_allowed_tags=(attributes)
# class Application < Rails::Application
# config.action_view.sanitized_allowed_attributes = 'onclick', 'longdesc'
# end
+ #
def sanitized_allowed_attributes=(attributes)
HTML::WhiteListSanitizer.allowed_attributes.merge(attributes)
end
@@ -208,6 +216,7 @@ def sanitized_allowed_attributes=(attributes)
# class Application < Rails::Application
# config.action_view.sanitized_allowed_css_properties = 'expression'
# end
+ #
def sanitized_allowed_css_properties=(attributes)
HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes)
end
@@ -217,6 +226,7 @@ def sanitized_allowed_css_properties=(attributes)
# class Application < Rails::Application
# config.action_view.sanitized_allowed_css_keywords = 'expression'
# end
+ #
def sanitized_allowed_css_keywords=(attributes)
HTML::WhiteListSanitizer.allowed_css_keywords.merge(attributes)
end
@@ -226,6 +236,7 @@ def sanitized_allowed_css_keywords=(attributes)
# class Application < Rails::Application
# config.action_view.sanitized_shorthand_css_properties = 'expression'
# end
+ #
def sanitized_shorthand_css_properties=(attributes)
HTML::WhiteListSanitizer.shorthand_css_properties.merge(attributes)
end
@@ -235,6 +246,7 @@ def sanitized_shorthand_css_properties=(attributes)
# class Application < Rails::Application
# config.action_view.sanitized_allowed_protocols = 'ssh', 'feed'
# end
+ #
def sanitized_allowed_protocols=(attributes)
HTML::WhiteListSanitizer.allowed_protocols.merge(attributes)
end
View
2  actionpack/lib/action_view/helpers/tag_helper.rb
@@ -41,7 +41,7 @@ module TagHelper
# thus accessed as <tt>dataset.userId</tt>.
#
# Values are encoded to JSON, with the exception of strings and symbols.
- # This may come in handy when using jQuery's HTML5-aware <tt>.data()<tt>
+ # This may come in handy when using jQuery's HTML5-aware <tt>.data()</tt>
# from 1.4.3.
#
# ==== Examples
View
5 actionpack/lib/action_view/helpers/tags.rb
@@ -8,14 +8,18 @@ module Tags #:nodoc:
autoload :CollectionCheckBoxes
autoload :CollectionRadioButtons
autoload :CollectionSelect
+ autoload :ColorField
autoload :DateField
autoload :DateSelect
+ autoload :DatetimeField
+ autoload :DatetimeLocalField
autoload :DatetimeSelect
autoload :EmailField
autoload :FileField
autoload :GroupedCollectionSelect
autoload :HiddenField
autoload :Label
+ autoload :MonthField
autoload :NumberField
autoload :PasswordField
autoload :RadioButton
@@ -29,6 +33,7 @@ module Tags #:nodoc:
autoload :TimeSelect
autoload :TimeZoneSelect
autoload :UrlField
+ autoload :WeekField
end
end
end
View
25 actionpack/lib/action_view/helpers/tags/color_field.rb
@@ -0,0 +1,25 @@
+module ActionView
+ module Helpers
+ module Tags
+ class ColorField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["value"] = @options.fetch("value") { validate_color_string(value(object)) }
+ @options = options
+ super
+ end
+
+ private
+
+ def validate_color_string(string)
+ regex = /#[0-9a-fA-F]{6}/
+ if regex.match(string)
+ string.downcase
+ else
+ "#000000"
+ end
+ end
+ end
+ end
+ end
+end
View
13 actionpack/lib/action_view/helpers/tags/date_field.rb
@@ -1,13 +1,12 @@
module ActionView
module Helpers
module Tags
- class DateField < TextField #:nodoc:
- def render
- options = @options.stringify_keys
- options["value"] = @options.fetch("value") { value(object).try(:to_date) }
- @options = options
- super
- end
+ class DateField < DatetimeField #:nodoc:
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-%m-%d")
+ end
end
end
end
View
22 actionpack/lib/action_view/helpers/tags/datetime_field.rb
@@ -0,0 +1,22 @@
+module ActionView
+ module Helpers
+ module Tags
+ class DatetimeField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["value"] = @options.fetch("value") { format_date(value(object)) }
+ options["min"] = format_date(options["min"])
+ options["max"] = format_date(options["max"])
+ @options = options
+ super
+ end
+
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-%m-%dT%T.%L%z")
+ end
+ end
+ end
+ end
+end
View
19 actionpack/lib/action_view/helpers/tags/datetime_local_field.rb
@@ -0,0 +1,19 @@
+module ActionView
+ module Helpers
+ module Tags
+ class DatetimeLocalField < DatetimeField #:nodoc:
+ class << self
+ def field_type
+ @field_type ||= "datetime-local"
+ end
+ end
+
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-%m-%dT%T")
+ end
+ end
+ end
+ end
+end
View
13 actionpack/lib/action_view/helpers/tags/month_field.rb
@@ -0,0 +1,13 @@
+module ActionView
+ module Helpers
+ module Tags
+ class MonthField < DatetimeField #:nodoc:
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-%m")
+ end
+ end
+ end
+ end
+end
View
1  actionpack/lib/action_view/helpers/tags/select.rb
@@ -31,6 +31,7 @@ def render
#
# [nil, []]
# { nil => [] }
+ #
def grouped_choices?
!@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last
end
View
13 actionpack/lib/action_view/helpers/tags/time_field.rb
@@ -1,13 +1,12 @@
module ActionView
module Helpers
module Tags
- class TimeField < TextField #:nodoc:
- def render
- options = @options.stringify_keys
- options["value"] = @options.fetch("value") { value(object).try(:strftime, "%T.%L") }
- @options = options
- super
- end
+ class TimeField < DatetimeField #:nodoc:
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%T.%L")
+ end
end
end
end
View
13 actionpack/lib/action_view/helpers/tags/week_field.rb
@@ -0,0 +1,13 @@
+module ActionView
+ module Helpers
+ module Tags
+ class WeekField < DatetimeField #:nodoc:
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-W%W")
+ end
+ end
+ end
+ end
+end
View
34 actionpack/lib/action_view/helpers/text_helper.rb
@@ -62,9 +62,11 @@ def safe_concat(string)
#
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break.
#
- # The result is not marked as HTML-safe, so will be subject to the default escaping when
- # used in views, unless wrapped by <tt>raw()</tt>. Care should be taken if +text+ contains HTML tags
- # or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags).
+ # Pass a block if you want to show extra content when the text is truncated.
+ #
+ # The result is marked as HTML-safe, but it is escaped by default, unless <tt>:escape</tt> is
+ # +false+. Care should be taken if +text+ contains HTML tags or entities, because truncation
+ # may produce invalid HTML (such as unbalanced or incomplete tags).
#
# truncate("Once upon a time in a world far far away")
# # => "Once upon a time in a world..."
@@ -80,8 +82,18 @@ def safe_concat(string)
#
# truncate("<p>Once upon a time in a world far far away</p>")
# # => "<p>Once upon a time in a wo..."
- def truncate(text, options = {})
- text.truncate(options.fetch(:length, 30), options) if text
+ #
+ # truncate("Once upon a time in a world far far away") { link_to "Continue", "#" }
+ # # => "Once upon a time in a wo...<a href="#">Continue</a>"
+ def truncate(text, options = {}, &block)
+ if text
+ length = options.fetch(:length, 30)
+
+ content = text.truncate(length, options)
+ content = options[:escape] == false ? content.html_safe : ERB::Util.html_escape(content)
+ content << capture(&block) if block_given? && text.length > length
+ content
+ end
end
# Highlights one or more +phrases+ everywhere in +text+ by inserting it into
@@ -102,7 +114,7 @@ def truncate(text, options = {})
# # => You searched for: <a href="search?q=rails">rails</a>
def highlight(text, phrases, options = {})
highlighter = options.fetch(:highlighter, '<mark>\1</mark>')
-
+
text = sanitize(text) if options.fetch(:sanitize, true)
if text.blank? || phrases.blank?
text
@@ -165,12 +177,12 @@ def excerpt(text, phrase, options = {})
# pluralize(0, 'person')
# # => 0 people
def pluralize(count, singular, plural = nil)
- word = if (count == 1 || count =~ /^1(\.0+)?$/)
- singular
+ word = if (count == 1 || count =~ /^1(\.0+)?$/)
+ singular
else
plural || singular.pluralize
end
-
+
"#{count || 0} #{word}"
end
@@ -215,7 +227,7 @@ def word_wrap(text, options = {})
#
# simple_format(my_text)
# # => "<p>Here is some basic text...\n<br />...with a line break.</p>"
- #
+ #
# simple_format(my_text, {}, :wrapper_tag => "div")
# # => "<div>Here is some basic text...\n<br />...with a line break.</div>"
#
@@ -231,7 +243,7 @@ def word_wrap(text, options = {})
# # => "<p><span>I'm allowed!</span> It's true.</p>"
def simple_format(text, html_options = {}, options = {})
wrapper_tag = options.fetch(:wrapper_tag, :p)
-
+
text = sanitize(text) if options.fetch(:sanitize, true)
paragraphs = split_paragraphs(text)
View
4 actionpack/lib/action_view/helpers/translation_helper.rb
@@ -64,7 +64,7 @@ def translate(key, options = {})
# Delegates to <tt>I18n.localize</tt> with no additional functionality.
#
- # See http://rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
+ # See http://rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
# for more information.
def localize(*args)
I18n.localize(*args)
@@ -96,7 +96,7 @@ def wrap_translate_defaults(defaults)
new_defaults << lambda { |_, options| translate key, options.merge(:default => defaults) }
break
else
- new_defautls << key
+ new_defaults << key
end
end
View
1  actionpack/lib/action_view/helpers/url_helper.rb
@@ -586,6 +586,7 @@ def mail_to(email_address, name = nil, html_options = {})
#
# current_page?(:controller => 'product', :action => 'index')
# # => false
+ #
def current_page?(options)
unless request
raise "You cannot use helpers that need to determine the current " \
View
32 actionpack/lib/action_view/template.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/try'
require 'active_support/core_ext/kernel/singleton_class'
+require 'thread'
module ActionView
# = Action View Template
@@ -122,6 +123,7 @@ def initialize(source, identifier, handler, details)
@virtual_path = details[:virtual_path]
@updated_at = details[:updated_at] || Time.now
@formats = Array(format).map { |f| f.is_a?(Mime::Type) ? f.ref : f }
+ @compile_mutex = Mutex.new
end
# Returns if the underlying handler supports streaming. If so,
@@ -223,18 +225,28 @@ def encode!
def compile!(view) #:nodoc:
return if @compiled
- if view.is_a?(ActionView::CompiledTemplates)
- mod = ActionView::CompiledTemplates
- else
- mod = view.singleton_class
- end
+ # Templates can be used concurrently in threaded environments
+ # so compilation and any instance variable modification must
+ # be synchronized
+ @compile_mutex.synchronize do
+ # Any thread holding this lock will be compiling the template needed
+ # by the threads waiting. So re-check the @compiled flag to avoid
+ # re-compilation
+ return if @compiled
+
+ if view.is_a?(ActionView::CompiledTemplates)
+ mod = ActionView::CompiledTemplates
+ else
+ mod = view.singleton_class
+ end
- compile(view, mod)
+ compile(view, mod)
- # Just discard the source if we have a virtual path. This
- # means we can get the template back.
- @source = nil if @virtual_path
- @compiled = true
+ # Just discard the source if we have a virtual path. This
+ # means we can get the template back.
+ @source = nil if @virtual_path
+ @compiled = true
+ end
end
# Among other things, this method is responsible for properly setting
View
1  actionpack/lib/action_view/template/resolver.rb
@@ -215,6 +215,7 @@ def extract_handler_and_format(path, default_formats)
# * <tt>:locale</tt> - possible locale versions
# * <tt>:formats</tt> - possible request formats (for example html, json, xml...)
# * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
+ #
class FileSystemResolver < PathResolver
def initialize(path, pattern=nil)
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
View
31 actionpack/test/controller/caching_test.rb
@@ -223,6 +223,7 @@ def page_cached?(action)
class ActionCachingTestController < CachingController
rescue_from(Exception) { head 500 }
+ rescue_from(ActionController::UnknownFormat) { head :not_acceptable }
if defined? ActiveRecord
rescue_from(ActiveRecord::RecordNotFound) { head :not_found }
end
@@ -230,7 +231,7 @@ class ActionCachingTestController < CachingController
# Eliminate uninitialized ivar warning
before_filter { @title = nil }
- caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| !c.request.format.json? }, :expires_in => 1.hour
+ caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| c.request.format && !c.request.format.json? }, :expires_in => 1.hour
caches_action :show, :cache_path => 'http://test.host/custom/show'
caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" }
caches_action :with_layout
@@ -239,6 +240,7 @@ class ActionCachingTestController < CachingController
caches_action :with_layout_proc_param, :layout => Proc.new { |c| c.params[:layout] }
caches_action :record_not_found, :four_oh_four, :simple_runtime_error
caches_action :streaming
+ caches_action :invalid
layout 'talk_from_action'
@@ -303,6 +305,14 @@ def expire_with_url_string
def streaming
render :text => "streaming", :stream => true
end
+