Skip to content
Browse files

Bring abstract_controller up to date with rails/master

Resolved all the conflicts since 2.3.0 -> HEAD. Following is a list
of commits that could not be applied cleanly or are obviated with the
abstract_controller refactor. They all need to be revisited to ensure
that fixes made in 2.3 do not reappear in 3.0:

2259ecf
AR not available
  * This will be reimplemented with ActionORM or equivalent

06182ea
implicitly rendering a js response should not use the default layout
[#1844 state:resolved]
  * This will be handled generically

893e9eb
Improve view rendering performance in development mode and reinstate
template recompiling in production [#1909 state:resolved]
  * We will need to reimplement rails-dev-boost on top of the refactor;
    the changes here are very implementation specific and cannot be
    cleanly applied. The following commits are implicated:

      199e750
      3942cb4
      f8ea9f8
      e3b166a
      ae9f258
      4442312

0cb020b
workaround for picking layouts based on wrong view_paths
[#1974 state:resolved]
  * The specifics of this commit no longer apply. Since it is a two-line
    commit, we will reimplement this change.

8c5cc66
make action_controller/layouts pick templates from the current instance's
view_paths instead of the class view_paths [#1974 state:resolved]
  * This does not apply at all. It should be trivial to apply the feature
    to the reimplemented ActionController::Base.

87e8b16
fix HTML fallback for explicit templates [#2052 state:resolved]
  * There were a number of patches related to this that simply compounded
    each other. Basically none of them apply cleanly, and the underlying
    issue needs to be revisited. After discussing the underlying problem
    with Koz, we will defer these fixes for further discussion.
  • Loading branch information...
2 parents 2036d3b + c877857 commit 906aebceedb95d8caa6db6314bc90f605bdfaf2b @wycats wycats committed Apr 13, 2009
Showing with 12,927 additions and 4,572 deletions.
  1. +1 −0 .gitignore
  2. +3 −1 actionmailer/CHANGELOG
  3. +1 −1 actionmailer/Rakefile
  4. +2 −1 actionmailer/lib/action_mailer.rb
  5. +5 −3 actionmailer/lib/action_mailer/base.rb
  6. +4 −1 actionmailer/lib/action_mailer/part.rb
  7. +1 −1 actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb
  8. +1 −1 actionmailer/lib/action_mailer/version.rb
  9. +4 −8 actionmailer/test/abstract_unit.rb
  10. +29 −1 actionmailer/test/mail_layout_test.rb
  11. +3 −5 actionmailer/test/mail_service_test.rb
  12. +4 −4 actionmailer/test/test_helper_test.rb
  13. +32 −1 actionpack/CHANGELOG
  14. +1 −2 actionpack/Rakefile
  15. +11 −0 actionpack/lib/action_controller.rb
  16. +41 −9 actionpack/lib/action_controller/base/base.rb
  17. +1 −1 actionpack/lib/action_controller/base/cookies.rb
  18. +51 −21 actionpack/lib/action_controller/base/http_authentication.rb
  19. +1 −1 actionpack/lib/action_controller/base/redirect.rb
  20. +15 −3 actionpack/lib/action_controller/base/render.rb
  21. +1 −0 actionpack/lib/action_controller/base/responder.rb
  22. +12 −4 actionpack/lib/action_controller/base/streaming.rb
  23. +1 −1 actionpack/lib/action_controller/base/verification.rb
  24. +1 −0 actionpack/lib/action_controller/caching.rb
  25. +10 −17 actionpack/lib/action_controller/caching/actions.rb
  26. +5 −0 actionpack/lib/action_controller/cgi/process.rb
  27. +27 −25 actionpack/lib/action_controller/dispatch/dispatcher.rb
  28. +3 −11 actionpack/lib/action_controller/dispatch/middlewares.rb
  29. +11 −5 actionpack/lib/action_controller/dispatch/rescue.rb
  30. +14 −0 actionpack/lib/action_controller/reloader.rb
  31. +1 −1 actionpack/lib/action_controller/routing.rb
  32. +2 −1 actionpack/lib/action_controller/routing/builder.rb
  33. +5 −2 actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
  34. +5 −17 actionpack/lib/action_controller/routing/generation/url_rewriter.rb
  35. +0 −1 actionpack/lib/action_controller/routing/recognition_optimisation.rb
  36. +27 −23 actionpack/lib/action_controller/routing/resources.rb
  37. +23 −23 actionpack/lib/action_controller/routing/segments.rb
  38. +19 −6 actionpack/lib/action_controller/testing/integration.rb
  39. +17 −5 actionpack/lib/action_controller/testing/process.rb
  40. +8 −5 actionpack/lib/action_controller/testing/test_case.rb
  41. +1 −1 actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb
  42. +89 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack.rb
  43. +22 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb
  44. +37 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb
  45. +37 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb
  46. +58 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb
  47. +124 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb
  48. +51 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb
  49. +55 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb
  50. +40 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb
  51. +480 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb
  52. +63 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/builder.rb
  53. +36 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/cascade.rb
  54. +49 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/chunked.rb
  55. +61 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb
  56. +45 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb
  57. +29 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/content_length.rb
  58. +23 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/content_type.rb
  59. +85 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/deflater.rb
  60. +153 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/directory.rb
  61. +88 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/file.rb
  62. +48 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler.rb
  63. +61 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb
  64. +8 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb
  65. +89 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb
  66. +55 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb
  67. +84 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb
  68. +59 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb
  69. +8 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb
  70. +18 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb
  71. +67 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb
  72. +19 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/head.rb
  73. +462 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/lint.rb
  74. +65 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/lobster.rb
  75. +16 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/lock.rb
  76. +27 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb
  77. +204 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/mime.rb
  78. +160 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/mock.rb
  79. +57 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/recursive.rb
  80. +64 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/reloader.rb
  81. +241 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/request.rb
  82. +179 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/response.rb
  83. +142 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb
  84. +91 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb
  85. +109 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb
  86. +100 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb
  87. +349 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb
  88. +106 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb
  89. +38 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/static.rb
  90. +55 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb
  91. +392 −0 actionpack/lib/action_controller/vendor/rack-1.0/rack/utils.rb
  92. +29 −5 actionpack/lib/action_dispatch/http/request.rb
  93. +38 −42 actionpack/lib/action_dispatch/http/response.rb
  94. +37 −24 actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
  95. +5 −8 actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
  96. +3 −3 actionpack/lib/action_dispatch/rack.rb
  97. +0 −21 actionpack/lib/action_dispatch/rack/lock.rb
  98. +0 −22 actionpack/lib/action_dispatch/rack/multipart.rb
  99. +0 −18 actionpack/lib/action_dispatch/rack/parse_query.rb
  100. +13 −3 actionpack/lib/action_dispatch/utils/middleware_stack.rb
  101. +0 −155 actionpack/lib/action_dispatch/utils/url_encoded_pair_parser.rb
  102. +1 −1 actionpack/lib/action_pack/version.rb
  103. +31 −2 actionpack/lib/action_view/base.rb
  104. +3 −3 actionpack/lib/action_view/helpers/active_record_helper.rb
  105. +2 −1 actionpack/lib/action_view/helpers/asset_tag_helper.rb
  106. +1 −1 actionpack/lib/action_view/helpers/atom_feed_helper.rb
  107. +8 −0 actionpack/lib/action_view/helpers/capture_helper.rb
  108. +3 −3 actionpack/lib/action_view/helpers/date_helper.rb
  109. +309 −75 actionpack/lib/action_view/helpers/form_helper.rb
  110. +92 −15 actionpack/lib/action_view/helpers/form_options_helper.rb
  111. +2 −2 actionpack/lib/action_view/helpers/form_tag_helper.rb
  112. +4 −2 actionpack/lib/action_view/helpers/number_helper.rb
  113. +1 −1 actionpack/lib/action_view/helpers/prototype_helper.rb
  114. +7 −6 actionpack/lib/action_view/helpers/text_helper.rb
  115. +19 −1 actionpack/lib/action_view/helpers/translation_helper.rb
  116. +25 −2 actionpack/lib/action_view/helpers/url_helper.rb
  117. +12 −4 actionpack/lib/action_view/paths.rb
  118. +11 −14 actionpack/lib/action_view/render/rendering.rb
  119. +2 −0 actionpack/lib/action_view/template/renderable.rb
  120. +31 −24 actionpack/lib/action_view/template/template.rb
  121. +3 −6 actionpack/test/abstract_unit.rb
  122. +2 −1 actionpack/test/active_record_unit.rb
  123. +67 −10 actionpack/test/activerecord/active_record_store_test.rb
  124. +2 −2 actionpack/test/activerecord/render_partial_with_record_identification_test.rb
  125. +33 −28 actionpack/test/controller/assert_select_test.rb
  126. +24 −14 actionpack/test/controller/caching_test.rb
  127. +11 −1 actionpack/test/controller/cookie_test.rb
  128. +8 −9 actionpack/test/controller/dispatcher_test.rb
  129. +8 −0 actionpack/test/controller/fake_models.rb
  130. +1 −1 actionpack/test/controller/html-scanner/document_test.rb
  131. +53 −5 actionpack/test/controller/http_digest_authentication_test.rb
  132. +18 −8 actionpack/test/controller/integration_test.rb
  133. +25 −0 actionpack/test/controller/layout_test.rb
  134. +1 −1 actionpack/test/controller/mime_responds_test.rb
  135. +237 −154 actionpack/test/controller/polymorphic_routes_test.rb
  136. +2 −2 actionpack/test/controller/redirect_test.rb
  137. +118 −9 actionpack/test/controller/render_test.rb
  138. +35 −0 actionpack/test/controller/request/test_request_test.rb
  139. +9 −9 actionpack/test/controller/request_forgery_protection_test.rb
  140. +18 −3 actionpack/test/controller/rescue_test.rb
  141. +101 −26 actionpack/test/controller/resources_test.rb
  142. +1,468 −1,382 actionpack/test/controller/routing_test.rb
  143. +3 −3 actionpack/test/controller/selector_test.rb
  144. +3 −3 actionpack/test/controller/send_file_test.rb
  145. +36 −7 actionpack/test/controller/session/cookie_store_test.rb
  146. +35 −10 actionpack/test/controller/session/mem_cache_store_test.rb
  147. +1 −1 actionpack/test/controller/session/test_session_test.rb
  148. +8 −0 actionpack/test/controller/test_test.rb
  149. +1 −1 actionpack/test/controller/url_rewriter_test.rb
  150. +14 −0 actionpack/test/dispatch/middleware_stack_test.rb
  151. +19 −5 actionpack/test/dispatch/rack_test.rb
  152. +1 −1 actionpack/test/dispatch/request/multipart_params_parsing_test.rb
  153. +0 −36 actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
  154. +226 −230 actionpack/test/dispatch/request_test.rb
  155. 0 actionpack/test/fixtures/layout_tests/alt/layouts/alt.rhtml
  156. +2 −0 actionpack/test/fixtures/layouts/xhr.html.erb
  157. +1 −0 actionpack/test/fixtures/public/500.da.html
  158. +1 −0 actionpack/test/fixtures/quiz/questions/_question.html.erb
  159. +1 −0 actionpack/test/fixtures/test/hello_world.erb~
  160. +1 −0 actionpack/test/fixtures/test/hello_world.pt-BR.html.erb
  161. +1 −0 actionpack/test/fixtures/test/malformed/malformed.en.html.erb~
  162. +1 −0 actionpack/test/fixtures/test/malformed/malformed.erb~
  163. +1 −0 actionpack/test/fixtures/test/malformed/malformed.html.erb~
  164. +1 −0 actionpack/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb
  165. +2 −0 actionpack/test/fixtures/test/utf8.html.erb
  166. +39 −38 actionpack/test/template/active_record_helper_i18n_test.rb
  167. +34 −0 actionpack/test/template/active_record_helper_test.rb
  168. +12 −14 actionpack/test/template/asset_tag_helper_test.rb
  169. +22 −0 actionpack/test/template/body_parts_test.rb
  170. +66 −68 actionpack/test/template/compiled_templates_test.rb
  171. +86 −90 actionpack/test/template/date_helper_i18n_test.rb
  172. +46 −48 actionpack/test/template/date_helper_test.rb
  173. +242 −43 actionpack/test/template/form_helper_test.rb
  174. +626 −604 actionpack/test/template/form_options_helper_test.rb
  175. +9 −2 actionpack/test/template/form_tag_helper_test.rb
  176. +0 −5 actionpack/test/template/javascript_helper_test.rb
  177. +53 −55 actionpack/test/template/number_helper_i18n_test.rb
  178. +1 −0 actionpack/test/template/number_helper_test.rb
  179. +35 −0 actionpack/test/template/output_buffer_test.rb
  180. +58 −1 actionpack/test/template/render_test.rb
  181. +4 −6 actionpack/test/template/test_test.rb
  182. +6 −0 actionpack/test/template/text_helper_test.rb
  183. +23 −19 actionpack/test/template/translation_helper_test.rb
  184. +35 −2 actionpack/test/template/url_helper_test.rb
  185. +1 −1 activemodel/lib/active_model/validations/inclusion.rb
  186. +1 −1 activemodel/test/state_machine/event_test.rb
  187. +14 −1 activerecord/CHANGELOG
  188. +4 −2 activerecord/Rakefile
  189. +3 −0 activerecord/lib/active_record.rb
  190. +112 −200 activerecord/lib/active_record/associations.rb
  191. +37 −20 activerecord/lib/active_record/associations/association_collection.rb
  192. +2 −2 activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
  193. +2 −2 activerecord/lib/active_record/associations/has_many_association.rb
  194. +5 −5 activerecord/lib/active_record/associations/has_many_through_association.rb
  195. +11 −2 activerecord/lib/active_record/associations/has_one_association.rb
  196. +1 −0 activerecord/lib/active_record/attribute_methods.rb
  197. +349 −0 activerecord/lib/active_record/autosave_association.rb
  198. +56 −42 activerecord/lib/active_record/base.rb
  199. +81 −0 activerecord/lib/active_record/batches.rb
  200. +18 −8 activerecord/lib/active_record/calculations.rb
  201. +33 −5 activerecord/lib/active_record/callbacks.rb
  202. +16 −0 activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
  203. +1 −0 activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
  204. +30 −1 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  205. +1 −1 activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
  206. +40 −24 activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
  207. +46 −57 activerecord/lib/active_record/fixtures.rb
  208. +33 −0 activerecord/lib/active_record/locking/optimistic.rb
  209. +5 −1 activerecord/lib/active_record/migration.rb
  210. +23 −7 activerecord/lib/active_record/named_scope.rb
  211. +329 −0 activerecord/lib/active_record/nested_attributes.rb
  212. +6 −1 activerecord/lib/active_record/reflection.rb
  213. +19 −0 activerecord/lib/active_record/serializers/json_serializer.rb
  214. +12 −6 activerecord/lib/active_record/serializers/xml_serializer.rb
  215. +9 −5 activerecord/lib/active_record/session_store.rb
  216. +14 −0 activerecord/lib/active_record/test_case.rb
  217. +2 −0 activerecord/lib/active_record/transactions.rb
  218. +16 −12 activerecord/lib/active_record/validations.rb
  219. +1 −1 activerecord/lib/active_record/version.rb
  220. +35 −131 activerecord/test/cases/associations/belongs_to_associations_test.rb
  221. +29 −0 activerecord/test/cases/associations/eager_load_nested_include_test.rb
  222. +4 −4 activerecord/test/cases/associations/eager_test.rb
  223. +40 −7 activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
  224. +84 −148 activerecord/test/cases/associations/has_many_associations_test.rb
  225. +32 −7 activerecord/test/cases/associations/has_many_through_associations_test.rb
  226. +39 −92 activerecord/test/cases/associations/has_one_associations_test.rb
  227. +18 −2 activerecord/test/cases/associations/has_one_through_associations_test.rb
  228. +5 −7 activerecord/test/cases/associations/join_model_test.rb
  229. +13 −1 activerecord/test/cases/attribute_methods_test.rb
  230. +901 −0 activerecord/test/cases/autosave_association_test.rb
  231. +21 −23 activerecord/test/cases/base_test.rb
  232. +61 −0 activerecord/test/cases/batches_test.rb
  233. +37 −18 activerecord/test/cases/calculations_test.rb
  234. +2 −2 activerecord/test/cases/callbacks_test.rb
  235. +25 −0 activerecord/test/cases/connection_pool_test.rb
  236. +1 −0 activerecord/test/cases/datatype_test_postgresql.rb
  237. +2 −2 activerecord/test/cases/dirty_test.rb
  238. +72 −44 activerecord/test/cases/finder_test.rb
  239. +15 −19 activerecord/test/cases/fixtures_test.rb
  240. +4 −9 activerecord/test/cases/helper.rb
  241. +2 −2 activerecord/test/cases/inheritance_test.rb
  242. +23 −5 activerecord/test/cases/locking_test.rb
  243. +38 −8 activerecord/test/cases/method_scoping_test.rb
Sorry, we could not display the entire diff because too many files (685) changed.
View
1 .gitignore
@@ -15,6 +15,7 @@ railties/test/500.html
railties/doc/guides/html/images
railties/doc/guides/html/stylesheets
benches
+railties/guides/output
*.rbc
*.swp
*.swo
View
4 actionmailer/CHANGELOG
@@ -1,4 +1,6 @@
-*2.3.0 [Edge]*
+*2.3.2 [Final] (March 15, 2009)*
+
+* Fixed that ActionMailer should send correctly formatted Return-Path in MAIL FROM for SMTP #1842 [Matt Jones]
* Fixed RFC-2045 quoted-printable bug #1421 [squadette]
View
2 actionmailer/Rakefile
@@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
- s.add_dependency('actionpack', '= 2.3.0' + PKG_BUILD)
+ s.add_dependency('actionpack', '= 2.3.2' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'
View
3 actionmailer/lib/action_mailer.rb
@@ -58,4 +58,5 @@ module Net
end
autoload :MailHelper, 'action_mailer/mail_helper'
-autoload :TMail, 'action_mailer/vendor/tmail'
+
+require 'action_mailer/vendor/tmail'
View
8 actionmailer/lib/action_mailer/base.rb
@@ -254,6 +254,8 @@ class Base
private_class_method :new #:nodoc:
class_inheritable_accessor :view_paths
+ self.view_paths = []
+
cattr_accessor :logger
@@smtp_settings = {
@@ -485,7 +487,7 @@ def create!(method_name, *parameters) #:nodoc:
)
end
unless @parts.empty?
- @content_type = "multipart/alternative"
+ @content_type = "multipart/alternative" if @content_type !~ /^multipart/
@parts = sort_parts(@parts, @implicit_parts_order)
end
end
@@ -613,7 +615,7 @@ def template_path
end
def initialize_template_class(assigns)
- template = ActionView::Base.new(view_paths, assigns, self)
+ template = ActionView::Base.new(self.class.view_paths, assigns, self)
template.formats = [default_template_format]
template
end
@@ -691,7 +693,7 @@ def create_mail
def perform_delivery_smtp(mail)
destinations = mail.destinations
mail.ready_to_send
- sender = mail['return-path'] || mail.from
+ sender = (mail['return-path'] && mail['return-path'].spec) || mail.from
smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto)
View
5 actionmailer/lib/action_mailer/part.rb
@@ -88,7 +88,10 @@ def to_mail(defaults)
part.parts << prt
end
- part.set_content_type(real_content_type, nil, ctype_attrs) if real_content_type =~ /multipart/
+ if real_content_type =~ /multipart/
+ ctype_attrs.delete 'charset'
+ part.set_content_type(real_content_type, nil, ctype_attrs)
+ end
end
headers.each { |k,v| part[k] = v }
View
2 actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb
@@ -1150,7 +1150,7 @@ def test_format_style
assert_equal(Text::Format::JUSTIFY, @format_o.format_style)
assert_match(/^of freedom, and that government of the people, by the people, for the$/,
@format_o.format(GETTYSBURG).split("\n")[-3])
- assert_raises(ArgumentError) { @format_o.format_style = 33 }
+ assert_raise(ArgumentError) { @format_o.format_style = 33 }
end
def test_tag_paragraph
View
2 actionmailer/lib/action_mailer/version.rb
@@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
- TINY = 0
+ TINY = 2
STRING = [MAJOR, MINOR, TINY].join('.')
end
View
12 actionmailer/test/abstract_unit.rb
@@ -1,5 +1,9 @@
+require 'rubygems'
require 'test/unit'
+gem 'mocha', '>= 0.9.5'
+require 'mocha'
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
$:.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift "#{File.dirname(__FILE__)}/../../actionpack/lib"
@@ -43,21 +47,13 @@ def self.new(*args)
end
def uses_gem(gem_name, test_name, version = '> 0')
- require 'rubygems'
gem gem_name.to_s, version
require gem_name.to_s
yield
rescue LoadError
$stderr.puts "Skipping #{test_name} tests. `gem install #{gem_name}` and try again."
end
-# Wrap tests that use Mocha and skip if unavailable.
-unless defined? uses_mocha
- def uses_mocha(test_name, &block)
- uses_gem('mocha', test_name, '>= 0.5.5', &block)
- end
-end
-
def set_delivery_method(delivery_method)
@old_delivery_method = ActionMailer::Base.delivery_method
ActionMailer::Base.delivery_method = delivery_method
View
30 actionmailer/test/mail_layout_test.rb
@@ -21,10 +21,12 @@ def nolayout(recipient)
body render(:inline => "Hello, <%= @world %>", :layout => false, :body => { :world => "Earth" })
end
- def multipart(recipient)
+ def multipart(recipient, type = nil)
recipients recipient
subject "You have a mail"
from "tester@example.com"
+
+ content_type(type) if type
end
end
@@ -64,6 +66,19 @@ def test_should_pickup_default_layout
def test_should_pickup_multipart_layout
mail = AutoLayoutMailer.create_multipart(@recipient)
+ assert_equal "multipart/alternative", mail.content_type
+ assert_equal 2, mail.parts.size
+
+ assert_equal 'text/plain', mail.parts.first.content_type
+ assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
+
+ assert_equal 'text/html', mail.parts.last.content_type
+ assert_equal "Hello from layout text/html multipart", mail.parts.last.body
+ end
+
+ def test_should_pickup_multipartmixed_layout
+ mail = AutoLayoutMailer.create_multipart(@recipient, "multipart/mixed")
+ assert_equal "multipart/mixed", mail.content_type
assert_equal 2, mail.parts.size
assert_equal 'text/plain', mail.parts.first.content_type
@@ -73,6 +88,19 @@ def test_should_pickup_multipart_layout
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
end
+ def test_should_fix_multipart_layout
+ mail = AutoLayoutMailer.create_multipart(@recipient, "text/plain")
+ assert_equal "multipart/alternative", mail.content_type
+ assert_equal 2, mail.parts.size
+
+ assert_equal 'text/plain', mail.parts.first.content_type
+ assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
+
+ assert_equal 'text/html', mail.parts.last.content_type
+ assert_equal "Hello from layout text/html multipart", mail.parts.last.body
+ end
+
+
def test_should_pickup_layout_given_to_render
mail = AutoLayoutMailer.create_spam(@recipient)
assert_equal "Spammer layout Hello, Earth", mail.body.strip
View
8 actionmailer/test/mail_service_test.rb
@@ -289,8 +289,6 @@ def receive(mail)
end
end
-uses_mocha 'ActionMailerTest' do
-
class ActionMailerTest < Test::Unit::TestCase
include ActionMailer::Quoting
@@ -332,6 +330,7 @@ def test_nested_parts
assert_equal "multipart/mixed", created.content_type
assert_equal "multipart/alternative", created.parts.first.content_type
assert_equal "bar", created.parts.first.header['foo'].to_s
+ assert_nil created.parts.first.charset
assert_equal "text/plain", created.parts.first.parts.first.content_type
assert_equal "text/html", created.parts.first.parts[1].content_type
assert_equal "application/octet-stream", created.parts[1].content_type
@@ -958,6 +957,7 @@ def test_return_path_with_deliver
ActionMailer::Base.delivery_method = :smtp
TestMailer.deliver_return_path
assert_match %r{^Return-Path: <another@somewhere.test>}, MockSMTP.deliveries[0][0]
+ assert_equal "another@somewhere.test", MockSMTP.deliveries[0][1].to_s
end
def test_body_is_stored_as_an_ivar
@@ -992,8 +992,6 @@ def test_starttls_is_not_enabled
end
end
-end # uses_mocha
-
class InheritableTemplateRootTest < Test::Unit::TestCase
def test_attr
expected = "#{File.dirname(__FILE__)}/fixtures/path.with.dots"
@@ -1089,7 +1087,7 @@ def test_should_not_respond_to_method_where_deliver_is_not_a_suffix
end
def test_should_still_raise_exception_with_expected_message_when_calling_an_undefined_method
- error = assert_raises NoMethodError do
+ error = assert_raise NoMethodError do
RespondToMailer.not_a_method
end
View
8 actionmailer/test/test_helper_test.rb
@@ -26,7 +26,7 @@ def test_mailer_class_is_correctly_inferred
end
def test_determine_default_mailer_raises_correct_error
- assert_raises(ActionMailer::NonInferrableMailerError) do
+ assert_raise(ActionMailer::NonInferrableMailerError) do
self.class.determine_default_mailer("NotAMailerTest")
end
end
@@ -84,7 +84,7 @@ def test_assert_no_emails
end
def test_assert_emails_too_few_sent
- error = assert_raises ActiveSupport::TestCase::Assertion do
+ error = assert_raise ActiveSupport::TestCase::Assertion do
assert_emails 2 do
TestHelperMailer.deliver_test
end
@@ -94,7 +94,7 @@ def test_assert_emails_too_few_sent
end
def test_assert_emails_too_many_sent
- error = assert_raises ActiveSupport::TestCase::Assertion do
+ error = assert_raise ActiveSupport::TestCase::Assertion do
assert_emails 1 do
TestHelperMailer.deliver_test
TestHelperMailer.deliver_test
@@ -105,7 +105,7 @@ def test_assert_emails_too_many_sent
end
def test_assert_no_emails_failure
- error = assert_raises ActiveSupport::TestCase::Assertion do
+ error = assert_raise ActiveSupport::TestCase::Assertion do
assert_no_emails do
TestHelperMailer.deliver_test
end
View
33 actionpack/CHANGELOG
@@ -1,4 +1,35 @@
-*2.3.0 [Edge]*
+*Edge*
+
+* Fixed that TestResponse.cookies was returning cookies unescaped #1867 [Doug McInnes]
+
+
+*2.3.2 [Final] (March 15, 2009)*
+
+* Fixed that redirection would just log the options, not the final url (which lead to "Redirected to #<Post:0x23150b8>") [DHH]
+
+* Added ability to pass in :public => true to fresh_when, stale?, and expires_in to make the request proxy cachable #2095 [Gregg Pollack]
+
+* Fixed that passing a custom form builder would be forwarded to nested fields_for calls #2023 [Eloy Duran/Nate Wiger]
+
+* Form option helpers now support disabled option tags and the use of lambdas for selecting/disabling option tags from collections #837 [Tekin]
+
+* Added partial scoping to TranslationHelper#translate, so if you call translate(".foo") from the people/index.html.erb template, you'll actually be calling I18n.translate("people.index.foo") [DHH]
+
+* Fix a syntax error in current_page?() that was prevent matches against URL's with multiple query parameters #1385, #1868 [chris finne/Andrew White]
+
+* Added localized rescue template when I18n.locale is set (ex: public/404.da.html) #1835 [José Valim]
+
+* Make the form_for and fields_for helpers support the new Active Record nested update options. #1202 [Eloy Duran]
+
+ <% form_for @person do |person_form| %>
+ ...
+ <% person_form.fields_for :projects do |project_fields| %>
+ <% if project_fields.object.active? %>
+ Name: <%= project_fields.text_field :name %>
+ <% end %>
+ <% end %>
+ <% end %>
+
* Added grouped_options_for_select helper method for wrapping option tags in optgroups. #977 [Jon Crawford]
View
3 actionpack/Rakefile
@@ -80,8 +80,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true
s.requirements << 'none'
- s.add_dependency('activesupport', '= 2.3.0' + PKG_BUILD)
- s.add_dependency('rack', '>= 0.9.0')
+ s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'action_controller'
View
11 actionpack/lib/action_controller.rb
@@ -32,6 +32,13 @@
end
require File.join(File.dirname(__FILE__), "action_pack")
+$:.unshift "#{File.dirname(__FILE__)}/action_controller/vendor/rack-1.0"
+begin
+ gem 'rack', '~> 1.0.0'
+ require 'rack'
+rescue Gem::LoadError
+ require 'action_controller/vendor/rack-1.0/rack'
+end
module ActionController
# TODO: Review explicit to see if they will automatically be handled by
@@ -57,6 +64,7 @@ def self.load_all!
autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes'
autoload :RecordIdentifier, 'action_controller/record_identifier'
autoload :Redirector, 'action_controller/base/redirect'
+ autoload :Reloader, 'action_controller/reloader'
autoload :Renderer, 'action_controller/base/render'
autoload :RequestForgeryProtection, 'action_controller/base/request_forgery_protection'
autoload :Rescue, 'action_controller/dispatch/rescue'
@@ -72,6 +80,9 @@ def self.load_all!
autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter'
autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter'
autoload :Verification, 'action_controller/base/verification'
+ autoload :UploadedFile, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedStringIO, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedTempfile, 'action_dispatch/utils/uploaded_file'
module Assertions
autoload :DomAssertions, 'action_controller/testing/assertions/dom'
View
50 actionpack/lib/action_controller/base/base.rb
@@ -22,7 +22,7 @@ class MethodNotAllowed < ActionControllerError #:nodoc:
attr_reader :allowed_methods
def initialize(*allowed_methods)
- super("Only #{allowed_methods.to_sentence} requests are allowed.")
+ super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.")
@allowed_methods = allowed_methods
end
@@ -394,7 +394,7 @@ def controller_path
# Return an array containing the names of public methods that have been marked hidden from the action processor.
# By default, all methods defined in ActionController::Base and included modules are hidden.
- # More methods can be hidden using <tt>hide_actions</tt>.
+ # More methods can be hidden using <tt>hide_action</tt>.
def hidden_actions
read_inheritable_attribute(:hidden_actions) || write_inheritable_attribute(:hidden_actions, [])
end
@@ -690,6 +690,11 @@ def default_url_options(options = nil)
# request is considered stale and should be generated from scratch. Otherwise,
# it's fresh and we don't need to generate anything and a reply of "304 Not Modified" is sent.
#
+ # Parameters:
+ # * <tt>:etag</tt>
+ # * <tt>:last_modified</tt>
+ # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches).
+ #
# Example:
#
# def show
@@ -710,20 +715,34 @@ def stale?(options)
# Sets the etag, last_modified, or both on the response and renders a
# "304 Not Modified" response if the request is already fresh.
#
+ # Parameters:
+ # * <tt>:etag</tt>
+ # * <tt>:last_modified</tt>
+ # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches).
+ #
# Example:
#
# def show
# @article = Article.find(params[:id])
- # fresh_when(:etag => @article, :last_modified => @article.created_at.utc)
+ # fresh_when(:etag => @article, :last_modified => @article.created_at.utc, :public => true)
# end
#
# This will render the show template if the request isn't sending a matching etag or
# If-Modified-Since header and just a "304 Not Modified" response if there's a match.
+ #
def fresh_when(options)
- options.assert_valid_keys(:etag, :last_modified)
+ options.assert_valid_keys(:etag, :last_modified, :public)
response.etag = options[:etag] if options[:etag]
response.last_modified = options[:last_modified] if options[:last_modified]
+
+ if options[:public]
+ cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip }
+ cache_control.delete("private")
+ cache_control.delete("no-cache")
+ cache_control << "public"
+ response.headers["Cache-Control"] = cache_control.join(', ')
+ end
if request.fresh?(response)
head :not_modified
@@ -735,15 +754,26 @@ def fresh_when(options)
#
# Examples:
# expires_in 20.minutes
- # expires_in 3.hours, :private => false
- # expires in 3.hours, 'max-stale' => 5.hours, :private => nil, :public => true
+ # expires_in 3.hours, :public => true
+ # expires in 3.hours, 'max-stale' => 5.hours, :public => true
#
# This method will overwrite an existing Cache-Control header.
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
def expires_in(seconds, options = {}) #:doc:
- cache_options = { 'max-age' => seconds, 'private' => true }.symbolize_keys.merge!(options.symbolize_keys)
- cache_options.delete_if { |k,v| v.nil? or v == false }
- cache_control = cache_options.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"}
+ cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip }
+
+ cache_control << "max-age=#{seconds}"
+ cache_control.delete("no-cache")
+ if options[:public]
+ cache_control.delete("private")
+ cache_control << "public"
+ else
+ cache_control << "private"
+ end
+
+ # This allows for additional headers to be passed through like 'max-stale' => 5.hours
+ cache_control += options.symbolize_keys.reject{|k,v| k == :public || k == :private }.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"}
+
response.headers["Cache-Control"] = cache_control.join(', ')
end
@@ -839,6 +869,7 @@ def perform_action
end
end
+ # Returns true if a render or redirect has already been performed.
def performed?
@performed_render || @performed_redirect
end
@@ -857,6 +888,7 @@ def request_origin
@request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}"
end
+ # Returns the request URI used to get to the current location
def complete_request_uri
"#{request.protocol}#{request.host}#{request.request_uri}"
end
View
2 actionpack/lib/action_controller/base/cookies.rb
@@ -41,7 +41,7 @@ module ActionController #:nodoc:
# * <tt>:expires</tt> - The time at which this cookie expires, as a Time object.
# * <tt>:secure</tt> - Whether this cookie is a only transmitted to HTTPS servers.
# Default is +false+.
- # * <tt>:http_only</tt> - Whether this cookie is accessible via scripting or
+ # * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
# only HTTP. Defaults to +false+.
module Cookies
def self.included(base)
View
72 actionpack/lib/action_controller/base/http_authentication.rb
@@ -68,8 +68,11 @@ module HttpAuthentication
#
# Simple Digest example:
#
+ # require 'digest/md5'
# class PostsController < ApplicationController
- # USERS = {"dhh" => "secret"}
+ # REALM = "SuperSecret"
+ # USERS = {"dhh" => "secret", #plain text password
+ # "dap" => Digest:MD5::hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
#
# before_filter :authenticate, :except => [:index]
#
@@ -83,14 +86,18 @@ module HttpAuthentication
#
# private
# def authenticate
- # authenticate_or_request_with_http_digest(realm) do |username|
+ # authenticate_or_request_with_http_digest(REALM) do |username|
# USERS[username]
# end
# end
# end
#
- # NOTE: The +authenticate_or_request_with_http_digest+ block must return the user's password so the framework can appropriately
- # hash it to check the user's credentials. Returning +nil+ will cause authentication to fail.
+ # NOTE: The +authenticate_or_request_with_http_digest+ block must return the user's password or the ha1 digest hash so the framework can appropriately
+ # hash to check the user's credentials. Returning +nil+ will cause authentication to fail.
+ # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
+ # the password file or database is compromised, the attacker would be able to use the ha1 hash to
+ # authenticate as the user at this +realm+, but would not have the user's password to try using at
+ # other sites.
#
# On shared hosts, Apache sometimes doesn't pass authentication headers to
# FCGI instances. If your environment matches this description and you cannot
@@ -177,26 +184,37 @@ def authorization(request)
end
# Raises error unless the request credentials response value matches the expected value.
+ # First try the password as a ha1 digest password. If this fails, then try it as a plain
+ # text password.
def validate_digest_response(request, realm, &password_procedure)
credentials = decode_credentials_header(request)
valid_nonce = validate_nonce(request, credentials[:nonce])
- if valid_nonce && realm == credentials[:realm] && opaque(request.session.session_id) == credentials[:opaque]
+ if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque]
password = password_procedure.call(credentials[:username])
- expected = expected_response(request.env['REQUEST_METHOD'], request.url, credentials, password)
- expected == credentials[:response]
+
+ [true, false].any? do |password_is_ha1|
+ expected = expected_response(request.env['REQUEST_METHOD'], request.env['REQUEST_URI'], credentials, password, password_is_ha1)
+ expected == credentials[:response]
+ end
end
end
# Returns the expected response for a request of +http_method+ to +uri+ with the decoded +credentials+ and the expected +password+
- def expected_response(http_method, uri, credentials, password)
- ha1 = ::Digest::MD5.hexdigest([credentials[:username], credentials[:realm], password].join(':'))
+ # Optional parameter +password_is_ha1+ is set to +true+ by default, since best practice is to store ha1 digest instead
+ # of a plain-text password.
+ def expected_response(http_method, uri, credentials, password, password_is_ha1=true)
+ ha1 = password_is_ha1 ? password : ha1(credentials, password)
ha2 = ::Digest::MD5.hexdigest([http_method.to_s.upcase, uri].join(':'))
::Digest::MD5.hexdigest([ha1, credentials[:nonce], credentials[:nc], credentials[:cnonce], credentials[:qop], ha2].join(':'))
end
- def encode_credentials(http_method, credentials, password)
- credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password)
+ def ha1(credentials, password)
+ ::Digest::MD5.hexdigest([credentials[:username], credentials[:realm], password].join(':'))
+ end
+
+ def encode_credentials(http_method, credentials, password, password_is_ha1)
+ credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password, password_is_ha1)
"Digest " + credentials.sort_by {|x| x[0].to_s }.inject([]) {|a, v| a << "#{v[0]}='#{v[1]}'" }.join(', ')
end
@@ -213,8 +231,7 @@ def decode_credentials(header)
end
def authentication_header(controller, realm)
- session_id = controller.request.session.session_id
- controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce(session_id)}", opaque="#{opaque(session_id)}")
+ controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}")
end
def authentication_request(controller, realm, message = nil)
@@ -252,23 +269,36 @@ def authentication_request(controller, realm, message = nil)
# POST or PUT requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
# of this document.
#
- # The nonce is opaque to the client.
- def nonce(session_id, time = Time.now)
+ # The nonce is opaque to the client. Composed of Time, and hash of Time with secret
+ # key from the Rails session secret generated upon creation of project. Ensures
+ # the time cannot be modifed by client.
+ def nonce(time = Time.now)
t = time.to_i
- hashed = [t, session_id]
+ hashed = [t, secret_key]
digest = ::Digest::MD5.hexdigest(hashed.join(":"))
Base64.encode64("#{t}:#{digest}").gsub("\n", '')
end
- def validate_nonce(request, value)
+ # Might want a shorter timeout depending on whether the request
+ # is a PUT or POST, and if client is browser or web service.
+ # Can be much shorter if the Stale directive is implemented. This would
+ # allow a user to use new nonce without prompting user again for their
+ # username and password.
+ def validate_nonce(request, value, seconds_to_timeout=5*60)
t = Base64.decode64(value).split(":").first.to_i
- nonce(request.session.session_id, t) == value && (t - Time.now.to_i).abs <= 10 * 60
+ nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end
- # Opaque based on digest of session_id
- def opaque(session_id)
- Base64.encode64(::Digest::MD5::hexdigest(session_id)).gsub("\n", '')
+ # Opaque based on random generation - but changing each request?
+ def opaque()
+ ::Digest::MD5.hexdigest(secret_key)
end
+
+ # Set in /initializers/session_store.rb, and loaded even if sessions are not in use.
+ def secret_key
+ ActionController::Base.session_options[:secret]
+ end
+
end
end
end
View
2 actionpack/lib/action_controller/base/redirect.rb
@@ -49,7 +49,6 @@ def redirect_to(options = {}, response_status = {}) #:doc:
end
response.redirected_to = options
- logger.info("Redirected to #{options}") if logger && logger.info?
case options
# The scheme name consist of a letter followed by any combination of
@@ -72,6 +71,7 @@ def redirect_to(options = {}, response_status = {}) #:doc:
def redirect_to_full_url(url, status)
raise DoubleRenderError if performed?
+ logger.info("Redirected to #{url}") if logger && logger.info?
response.redirect(url, interpret_status(status))
@performed_redirect = true
end
View
18 actionpack/lib/action_controller/base/render.rb
@@ -197,7 +197,17 @@ def render(options = nil, extra_options = {}, &block) #:doc:
raise DoubleRenderError, "Can only render or redirect once per action" if performed?
options = { :layout => true } if options.nil?
- original, options = options, extra_options unless options.is_a?(Hash)
+
+ # This handles render "string", render :symbol, and render object
+ # render string and symbol are handled by render_for_name
+ # render object becomes render :partial => object
+ unless options.is_a?(Hash)
+ if options.is_a?(String) || options.is_a?(Symbol)
+ original, options = options, extra_options
+ else
+ extra_options[:partial], options = options, extra_options
+ end
+ end
layout_name = options.delete(:layout)
@@ -300,6 +310,7 @@ def action_name_base(name = action_name)
# of sending it as the response body to the browser.
def render_to_string(options = nil, &block) #:doc:
render(options, &block)
+ response.body
ensure
response.content_type = nil
erase_render_results
@@ -308,7 +319,7 @@ def render_to_string(options = nil, &block) #:doc:
# Clears the rendered results, allowing for another render to be performed.
def erase_render_results #:nodoc:
- response.body = nil
+ response.body = []
@performed_render = false
end
@@ -360,8 +371,9 @@ def render_for_name(name, layout, options)
def render_for_parts(parts, layout, options = {})
tmp = view_paths.find_by_parts(*parts)
- layout = _pick_layout(*layout) unless tmp.exempt_from_layout?
+ layout = _pick_layout(*layout) unless tmp.exempt_from_layout?
+
render_for_text(
@template._render_template_with_layout(tmp, layout, options, parts[3]))
end
View
1 actionpack/lib/action_controller/base/responder.rb
@@ -20,6 +20,7 @@ def render_for_text(text = nil, append_response = false) #:nodoc:
end
end
+ # Returns a set of the methods defined as actions in your controller
def action_methods
self.class.action_methods
end
View
16 actionpack/lib/action_controller/base/streaming.rb
@@ -1,5 +1,6 @@
module ActionController #:nodoc:
- # Methods for sending files and streams to the browser instead of rendering.
+ # Methods for sending arbitrary data and for streaming files to the browser,
+ # instead of rendering.
module Streaming
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
@@ -103,8 +104,11 @@ def send_file(path, options = {}) #:doc:
end
end
- # Send binary data to the user as a file download. May set content type, apparent file name,
- # and specify whether to show data inline or download as an attachment.
+ # Sends the given binary data to the browser. This method is similar to
+ # <tt>render :text => data</tt>, but also allows you to specify whether
+ # the browser should display the response as a file attachment (i.e. in a
+ # download dialog) or as inline data. You may also set the content type,
+ # the apparent file name, and other things.
#
# Options:
# * <tt>:filename</tt> - suggests a filename for the browser to use.
@@ -127,6 +131,10 @@ def send_file(path, options = {}) #:doc:
# send_data image.data, :type => image.content_type, :disposition => 'inline'
#
# See +send_file+ for more information on HTTP Content-* headers and caching.
+ #
+ # <b>Tip:</b> if you want to stream large amounts of on-the-fly generated
+ # data to the browser, then use <tt>render :text => proc { ... }</tt>
+ # instead. See ActionController::Base#render for more information.
def send_data(data, options = {}) #:doc:
logger.info "Sending data #{options[:filename]}" if logger
send_file_headers! options.merge(:length => data.size)
@@ -152,7 +160,7 @@ def send_file_headers!(options)
end
content_type = content_type.to_s.strip # fixes a problem with extra '\r' with some browsers
- headers.update(
+ headers.merge!(
'Content-Length' => options[:length],
'Content-Type' => content_type,
'Content-Disposition' => disposition,
View
2 actionpack/lib/action_controller/base/verification.rb
@@ -90,7 +90,7 @@ def verify(options={})
def verify_action(options) #:nodoc:
if prereqs_invalid?(options)
flash.update(options[:add_flash]) if options[:add_flash]
- response.headers.update(options[:add_headers]) if options[:add_headers]
+ response.headers.merge!(options[:add_headers]) if options[:add_headers]
apply_remaining_actions(options) unless performed?
end
end
View
1 actionpack/lib/action_controller/caching.rb
@@ -27,6 +27,7 @@ module Caching
autoload :Actions, 'action_controller/caching/actions'
autoload :Fragments, 'action_controller/caching/fragments'
autoload :Pages, 'action_controller/caching/pages'
+ autoload :Sweeper, 'action_controller/caching/sweeping'
autoload :Sweeping, 'action_controller/caching/sweeping'
def self.included(base) #:nodoc:
View
27 actionpack/lib/action_controller/caching/actions.rb
@@ -129,24 +129,23 @@ class ActionCachePath
attr_reader :path, :extension
class << self
- def path_for(controller, options, infer_extension=true)
+ def path_for(controller, options, infer_extension = true)
new(controller, options, infer_extension).path
end
end
# When true, infer_extension will look up the cache path extension from the request's path & format.
- # This is desirable when reading and writing the cache, but not when expiring the cache - expire_action should expire the same files regardless of the request format.
- def initialize(controller, options = {}, infer_extension=true)
- if infer_extension and options.is_a? Hash
- request_extension = extract_extension(controller.request)
- options = options.reverse_merge(:format => request_extension)
+ # This is desirable when reading and writing the cache, but not when expiring the cache -
+ # expire_action should expire the same files regardless of the request format.
+ def initialize(controller, options = {}, infer_extension = true)
+ if infer_extension
+ extract_extension(controller.request)
+ options = options.reverse_merge(:format => @extension) if options.is_a?(Hash)
end
+
path = controller.url_for(options).split('://').last
normalize!(path)
- if infer_extension
- @extension = request_extension
- add_extension!(path, @extension)
- end
+ add_extension!(path, @extension)
@path = URI.unescape(path)
end
@@ -162,13 +161,7 @@ def add_extension!(path, extension)
def extract_extension(request)
# Don't want just what comes after the last '.' to accommodate multi part extensions
# such as tar.gz.
- extension = request.path[/^[^.]+\.(.+)$/, 1]
-
- # If there's no extension in the path, check request.format
- if extension.nil?
- extension = request.cache_format
- end
- extension
+ @extension = request.path[/^[^.]+\.(.+)$/, 1] || request.cache_format
end
end
end
View
5 actionpack/lib/action_controller/cgi/process.rb
@@ -45,6 +45,11 @@ def self.dispatch_cgi(app, cgi, out = $stdout)
out.sync = false if out.respond_to?(:sync=)
headers['Status'] = status.to_s
+
+ if headers.include?('Set-Cookie')
+ headers['cookie'] = headers.delete('Set-Cookie').split("\n")
+ end
+
out.write(cgi.header(headers))
body.each { |part|
View
52 actionpack/lib/action_controller/dispatch/dispatcher.rb
@@ -5,15 +5,14 @@ class Dispatcher
class << self
def define_dispatcher_callbacks(cache_classes)
unless cache_classes
- # Development mode callbacks
- before_dispatch :reload_application
- after_dispatch :cleanup_application
+ unless self.middleware.include?(Reloader)
+ self.middleware.insert_after(ActionDispatch::Failsafe, Reloader)
+ end
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
end
if defined?(ActiveRecord)
- after_dispatch :checkin_connections
to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
end
@@ -42,6 +41,30 @@ def to_prepare(identifier = nil, &block)
callback = ActiveSupport::Callbacks::Callback.new(:prepare_dispatch, block, :identifier => identifier)
@prepare_dispatch_callbacks.replace_or_append!(callback)
end
+
+ def run_prepare_callbacks
+ if defined?(Rails) && Rails.logger
+ logger = Rails.logger
+ else
+ logger = Logger.new($stderr)
+ end
+
+ new(logger).send :run_callbacks, :prepare_dispatch
+ end
+
+ def reload_application
+ # Run prepare callbacks before every request in development mode
+ run_prepare_callbacks
+
+ Routing::Routes.reload
+ end
+
+ def cleanup_application
+ # Cleanup the application before processing the current request.
+ ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
+ ActiveSupport::Dependencies.clear
+ ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
+ end
end
cattr_accessor :middleware
@@ -88,29 +111,8 @@ def _call(env)
dispatch
end
- def reload_application
- # Run prepare callbacks before every request in development mode
- run_callbacks :prepare_dispatch
-
- Routing::Routes.reload
- end
-
- # Cleanup the application by clearing out loaded classes so they can
- # be reloaded on the next request without restarting the server.
- def cleanup_application
- ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
- ActiveSupport::Dependencies.clear
- ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
- end
-
def flush_logger
Base.logger.flush
end
-
- def checkin_connections
- # Don't return connection (and peform implicit rollback) if this request is a part of integration test
- return if @env.key?("rack.test")
- ActiveRecord::Base.clear_active_connections!
- end
end
end
View
14 actionpack/lib/action_controller/dispatch/middlewares.rb
@@ -4,18 +4,10 @@
use "ActionDispatch::Failsafe"
-["ActionDispatch::Session::CookieStore",
- "ActionDispatch::Session::MemCacheStore",
- "ActiveRecord::SessionStore"].each do |store|
- use(store, ActionController::Base.session_options,
- :if => lambda {
- if session_store = ActionController::Base.session_store
- session_store.name == store
- end
- }
- )
-end
+use lambda { ActionController::Base.session_store },
+ lambda { ActionController::Base.session_options }
use "ActionDispatch::RewindableInput"
use "ActionDispatch::ParamsParser"
use "Rack::MethodOverride"
+use "Rack::Head"
View
16 actionpack/lib/action_controller/dispatch/rescue.rb
@@ -99,13 +99,19 @@ def rescue_action_in_public(exception) #:doc:
# Attempts to render a static error page based on the
# <tt>status_code</tt> thrown, or just return headers if no such file
- # exists. For example, if a 500 error is being handled Rails will first
- # attempt to render the file at <tt>public/500.html</tt>. If the file
- # doesn't exist, the body of the response will be left empty.
+ # exists. At first, it will try to render a localized static page.
+ # For example, if a 500 error is being handled Rails and locale is :da,
+ # it will first attempt to render the file at <tt>public/500.da.html</tt>
+ # then attempt to render <tt>public/500.html</tt>. If none of them exist,
+ # the body of the response will be left empty.
def render_optional_error_file(status_code)
status = interpret_status(status_code)
- path = "#{Rails.public_path}/#{status.to_s[0,3]}.html"
- if File.exist?(path)
+ locale_path = "#{Rails.public_path}/#{status[0,3]}.#{I18n.locale}.html" if I18n.locale
+ path = "#{Rails.public_path}/#{status[0,3]}.html"
+
+ if locale_path && File.exist?(locale_path)
+ render :file => locale_path, :status => status, :content_type => Mime::HTML
+ elsif File.exist?(path)
render :file => path, :status => status, :content_type => Mime::HTML
else
head status
View
14 actionpack/lib/action_controller/reloader.rb
@@ -0,0 +1,14 @@
+module ActionController
+ class Reloader
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ Dispatcher.reload_application
+ @app.call(env)
+ ensure
+ Dispatcher.cleanup_application
+ end
+ end
+end
View
2 actionpack/lib/action_controller/routing.rb
@@ -267,7 +267,7 @@ module ActionController
module Routing
SEPARATORS = %w( / . ? )
- HTTP_METHODS = [:get, :head, :post, :put, :delete]
+ HTTP_METHODS = [:get, :head, :post, :put, :delete, :options]
ALLOWED_REQUIREMENTS_FOR_OPTIMISATION = [:controller, :action].to_set
View
3 actionpack/lib/action_controller/routing/builder.rb
@@ -159,7 +159,8 @@ def build(path, options)
path = "/#{path}" unless path[0] == ?/
path = "#{path}/" unless path[-1] == ?/
- path = "/#{options[:path_prefix].to_s.gsub(/^\//,'')}#{path}" if options[:path_prefix]
+ prefix = options[:path_prefix].to_s.gsub(/^\//,'')
+ path = "/#{prefix}#{path}" unless prefix.blank?
segments = segments_for_route_path(path)
defaults, requirements, conditions = divide_route_options(segments, options)
View
7 actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
@@ -163,15 +163,18 @@ def build_named_route_call(records, namespace, inflection, options = {})
if parent.is_a?(Symbol) || parent.is_a?(String)
string << "#{parent}_"
else
- string << "#{RecordIdentifier.__send__("singular_class_name", parent)}_"
+ string << "#{RecordIdentifier.__send__("plural_class_name", parent)}".singularize
+ string << "_"
end
end
end
if record.is_a?(Symbol) || record.is_a?(String)
route << "#{record}_"
else
- route << "#{RecordIdentifier.__send__("#{inflection}_class_name", record)}_"
+ route << "#{RecordIdentifier.__send__("plural_class_name", record)}"
+ route = route.singularize if inflection == :singular
+ route << "_"
end
action_prefix(options) + namespace + route + routing_type(options).to_s
View
22 actionpack/lib/action_controller/routing/generation/url_rewriter.rb
@@ -68,29 +68,17 @@ module ActionController
# This generates, among other things, the method <tt>users_path</tt>. By default,
# this method is accessible from your controllers, views and mailers. If you need
# to access this auto-generated method from other places (such as a model), then
- # you can do that in two ways.
- #
- # The first way is to include ActionController::UrlWriter in your class:
+ # you can do that by including ActionController::UrlWriter in your class:
#
# class User < ActiveRecord::Base
- # include ActionController::UrlWriter # !!!
+ # include ActionController::UrlWriter
#
- # def name=(value)
- # write_attribute('name', value)
- # write_attribute('base_uri', users_path) # !!!
+ # def base_uri
+ # user_path(self)
# end
# end
#
- # The second way is to access them through ActionController::UrlWriter.
- # The autogenerated named routes methods are available as class methods:
- #
- # class User < ActiveRecord::Base
- # def name=(value)
- # write_attribute('name', value)
- # path = ActionController::UrlWriter.users_path # !!!
- # write_attribute('base_uri', path) # !!!
- # end
- # end
+ # User.find(1).base_uri # => "/users/1"
module UrlWriter
def self.included(base) #:nodoc:
ActionController::Routing::Routes.install_helpers(base)
View
1 actionpack/lib/action_controller/routing/recognition_optimisation.rb
@@ -98,7 +98,6 @@ def generate_code(list, padding=' ', level = 0)
if Array === item
i += 1
start = (i == 1)
- final = (i == list.size)
tag, sub = item
if tag == :dynamic
body += padding + "#{start ? 'if' : 'elsif'} true\n"
View
50 actionpack/lib/action_controller/routing/resources.rb
@@ -42,7 +42,7 @@ module ActionController
#
# Read more about REST at http://en.wikipedia.org/wiki/Representational_State_Transfer
module Resources
- INHERITABLE_OPTIONS = :namespace, :shallow, :actions
+ INHERITABLE_OPTIONS = :namespace, :shallow
class Resource #:nodoc:
DEFAULT_ACTIONS = :index, :create, :new, :edit, :show, :update, :destroy
@@ -91,7 +91,7 @@ def new_path
end
def shallow_path_prefix
- @shallow_path_prefix ||= "#{path_prefix unless @options[:shallow]}"
+ @shallow_path_prefix ||= @options[:shallow] ? @options[:namespace].try(:sub, /\/$/, '') : path_prefix
end
def member_path
@@ -103,7 +103,7 @@ def nesting_path_prefix
end
def shallow_name_prefix
- @shallow_name_prefix ||= "#{name_prefix unless @options[:shallow]}"
+ @shallow_name_prefix ||= @options[:shallow] ? @options[:namespace].try(:gsub, /\//, '_') : name_prefix
end
def nesting_name_prefix
@@ -119,7 +119,7 @@ def uncountable?
end
def has_action?(action)
- !DEFAULT_ACTIONS.include?(action) || @options[:actions].nil? || @options[:actions].include?(action)
+ !DEFAULT_ACTIONS.include?(action) || action_allowed?(action)
end
protected
@@ -135,24 +135,29 @@ def add_default_actions
end
def set_allowed_actions
- only = @options.delete(:only)
- except = @options.delete(:except)
+ only, except = @options.values_at(:only, :except)
+ @allowed_actions ||= {}
- if only && except
- raise ArgumentError, 'Please supply either :only or :except, not both.'
- elsif only == :all || except == :none
- options[:actions] = DEFAULT_ACTIONS
+ if only == :all || except == :none
+ only = nil
+ except = []
elsif only == :none || except == :all
- options[:actions] = []
- elsif only
- options[:actions] = DEFAULT_ACTIONS & Array(only).map(&:to_sym)
+ only = []
+ except = nil
+ end
+
+ if only
+ @allowed_actions[:only] = Array(only).map(&:to_sym)
elsif except
- options[:actions] = DEFAULT_ACTIONS - Array(except).map(&:to_sym)
- else
- # leave options[:actions] alone
+ @allowed_actions[:except] = Array(except).map(&:to_sym)
end
end
+ def action_allowed?(action)
+ only, except = @allowed_actions.values_at(:only, :except)
+ (!only || only.include?(action)) && (!except || !except.include?(action))
+ end
+
def set_prefixes
@path_prefix = options.delete(:path_prefix)
@name_prefix = options.delete(:name_prefix)
@@ -403,8 +408,6 @@ def initialize(entity, options)
# # --> POST /posts/1/comments (maps to the CommentsController#create action)
# # --> PUT /posts/1/comments/1 (fails)
#
- # The <tt>:only</tt> and <tt>:except</tt> options are inherited by any nested resource(s).
- #
# If <tt>map.resources</tt> is called with multiple resources, they all get the same options applied.
#
# Examples:
@@ -627,7 +630,7 @@ def map_member_actions(map, resource)
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
action_path ||= Base.resources_path_names[action] || action
- map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m)
+ map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m, { :force_id => true })
end
end
end
@@ -638,9 +641,9 @@ def map_member_actions(map, resource)
map_resource_routes(map, resource, :destroy, resource.member_path, route_path)
end
- def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil)
+ def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil, resource_options = {} )
if resource.has_action?(action)
- action_options = action_options_for(action, resource, method)
+ action_options = action_options_for(action, resource, method, resource_options)
formatted_route_path = "#{route_path}.:format"
if route_name && @set.named_routes[route_name.to_sym].nil?
@@ -657,17 +660,18 @@ def add_conditions_for(conditions, method)
end
end
- def action_options_for(action, resource, method = nil)
+ def action_options_for(action, resource, method = nil, resource_options = {})
default_options = { :action => action.to_s }
require_id = !resource.kind_of?(SingletonResource)
+ force_id = resource_options[:force_id] && !resource.kind_of?(SingletonResource)
case default_options[:action]
when "index", "new"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements)
when "create"; default_options.merge(add_conditions_for(resource.conditions, method || :post)).merge(resource.requirements)
when "show", "edit"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements(require_id))
when "update"; default_options.merge(add_conditions_for(resource.conditions, method || :put)).merge(resource.requirements(require_id))
when "destroy"; default_options.merge(add_conditions_for(resource.conditions, method || :delete)).merge(resource.requirements(require_id))
- else default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements)
+ else default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements(force_id))
end
end
end
View
46 actionpack/lib/action_controller/routing/segments.rb
@@ -3,7 +3,11 @@ module Routing
class Segment #:nodoc:
RESERVED_PCHAR = ':@&=+$,;'
SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}"
- UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze
+ if RUBY_VERSION >= '1.9'
+ UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze
+ else
+ UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze
+ end
# TODO: Convert :is_optional accessor to read only
attr_accessor :is_optional
@@ -191,23 +195,19 @@ def value_regexp
end
def regexp_chunk
- if regexp
- if regexp_has_modifiers?
- "(#{regexp.to_s})"
- else
- "(#{regexp.source})"
- end
- else
- "([^#{Routing::SEPARATORS.join}]+)"
- end
+ regexp ? regexp_string : default_regexp_chunk
+ end
+
+ def regexp_string
+ regexp_has_modifiers? ? "(#{regexp.to_s})" : "(#{regexp.source})"
+ end
+
+ def default_regexp_chunk
+ "([^#{Routing::SEPARATORS.join}]+)"
end
def number_of_captures
- if regexp
- regexp.number_of_captures + 1
- else
- 1
- end
+ regexp ? regexp.number_of_captures + 1 : 1
end
def build_pattern(pattern)
@@ -244,10 +244,6 @@ def regexp_chunk
"(?i-:(#{(regexp || Regexp.union(*possible_names)).source}))"
end
- def number_of_captures
- 1
- end
-
# Don't URI.escape the controller name since it may contain slashes.
def interpolation_chunk(value_code = local_name)
"\#{#{value_code}.to_s}"
@@ -289,8 +285,8 @@ def match_extraction(next_capture)
"params[:#{key}] = PathSegment::Result.new_escaped((match[#{next_capture}]#{" || " + default.inspect if default}).split('/'))#{" if match[" + next_capture + "]" if !default}"
end
- def regexp_chunk
- regexp || "(.*)"
+ def default_regexp_chunk
+ "(.*)"
end
def number_of_captures
@@ -322,13 +318,17 @@ def interpolation_chunk
end
def regexp_chunk
- '(\.[^/?\.]+)?'
+ '/|(\.[^/?\.]+)?'
end
def to_s
'(.:format)?'
end
-
+
+ def extract_value
+ "#{local_name} = options[:#{key}] && options[:#{key}].to_s.downcase"
+ end
+
#the value should not include the period (.)
def match_extraction(next_capture)
%[
View
25 actionpack/lib/action_controller/testing/integration.rb
@@ -5,7 +5,7 @@
module ActionController
module Integration #:nodoc:
# An integration Session instance represents a set of requests and responses
- # performed sequentially by some virtual user. Becase you can instantiate
+ # performed sequentially by some virtual user. Because you can instantiate
# multiple sessions and run them side-by-side, you can also mimic (to some
# limited extent) multiple simultaneous users interacting with your system.
#
@@ -26,6 +26,9 @@ class Session
# The status message that accompanied the status code of the last request.
attr_reader :status_message
+ # The body of the last request.
+ attr_reader :body
+
# The URI of the last request.
attr_reader :path
@@ -308,7 +311,11 @@ def process(method, path, parameters = nil, headers = nil)
ActionController::Base.clear_last_instantiation!
- app = Rack::Lint.new(@application)
+ app = @application
+ # Rack::Lint doesn't accept String headers or bodies in Ruby 1.9
+ unless RUBY_VERSION >= '1.9.0' && Rack.release <= '0.9.0'
+ app = Rack::Lint.new(app)
+ end
status, headers, body = app.call(env)
@request_count += 1
@@ -320,13 +327,19 @@ def process(method, path, parameters = nil, headers = nil)
@headers = Rack::Utils::HeaderHash.new(headers)
- (@headers['Set-Cookie'] || []).each do |cookie|
+ (@headers['Set-Cookie'] || "").split("\n").each do |cookie|
name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
@cookies[name] = value
end
- @body = ""
- body.each { |part| @body << part }
+ if body.is_a?(String)
+ @body_parts = [body]
+ @body = body
+ else
+ @body_parts = []
+ body.each { |part| @body_parts << part.to_s }
+ @body = @body_parts.join
+ end
if @controller = ActionController::Base.last_instantiation
@request = @controller.request
@@ -338,7 +351,7 @@ def process(method, path, parameters = nil, headers = nil)
@response = ActionDispatch::Response.new
@response.status = status.to_s
@response.headers.replace(@headers)
- @response.body = @body
+ @response.body = @body_parts
end