Permalink
Browse files

Merge commit 'rails/master'

  • Loading branch information...
2 parents aa55122 + 2f59066 commit b3d40546923b194a89be0d9e00758864fa60b9e8 @miloops miloops committed May 26, 2009
Showing with 2,852 additions and 1,409 deletions.
  1. +2 −4 {actionpack → actionmailer}/test/adv_attr_test.rb
  2. +29 −6 actionpack/Rakefile
  3. +38 −19 actionpack/examples/minimal.rb
  4. +1 −0 actionpack/lib/action_controller.rb
  5. +3 −3 actionpack/lib/action_controller/abstract/base.rb
  6. +11 −0 actionpack/lib/action_controller/abstract/callbacks.rb
  7. +23 −4 actionpack/lib/action_controller/abstract/helpers.rb
  8. +36 −16 actionpack/lib/action_controller/abstract/layouts.rb
  9. +15 −9 actionpack/lib/action_controller/abstract/renderer.rb
  10. +1 −58 actionpack/lib/action_controller/base/base.rb
  11. +52 −22 actionpack/lib/action_controller/base/chained/flash.rb
  12. +97 −0 actionpack/lib/action_controller/base/filter_parameter_logging.rb
  13. +9 −13 actionpack/lib/action_controller/base/helpers.rb
  14. +104 −106 actionpack/lib/action_controller/base/mime_responds.rb
  15. +19 −5 actionpack/lib/action_controller/base/request_forgery_protection.rb
  16. +8 −0 actionpack/lib/action_controller/base/streaming.rb
  17. +6 −3 actionpack/lib/action_controller/base/verification.rb
  18. +15 −15 actionpack/lib/action_controller/caching.rb
  19. +25 −7 actionpack/lib/action_controller/caching/actions.rb
  20. +18 −3 actionpack/lib/action_controller/new_base.rb
  21. +39 −11 actionpack/lib/action_controller/new_base/base.rb
  22. +29 −9 actionpack/lib/action_controller/new_base/compatibility.rb
  23. +1 −1 actionpack/lib/action_controller/new_base/conditional_get.rb
  24. +130 −0 actionpack/lib/action_controller/new_base/helpers.rb
  25. +1 −2 actionpack/lib/action_controller/new_base/http.rb
  26. +9 −12 actionpack/lib/action_controller/new_base/layouts.rb
  27. +107 −0 actionpack/lib/action_controller/new_base/render_options.rb
  28. +37 −29 actionpack/lib/action_controller/new_base/renderer.rb
  29. +11 −0 actionpack/lib/action_controller/new_base/session.rb
  30. +18 −5 actionpack/lib/action_controller/new_base/testing.rb
  31. +5 −0 actionpack/lib/action_controller/new_base/url_for.rb
  32. +23 −25 actionpack/lib/action_controller/testing/integration.rb
  33. +1 −0 actionpack/lib/action_controller/testing/process.rb
  34. +4 −1 actionpack/lib/action_controller/testing/process2.rb
  35. +4 −1 actionpack/lib/action_dispatch.rb
  36. +1 −1 actionpack/lib/action_dispatch/http/mime_type.rb
  37. +1 −1 actionpack/lib/action_dispatch/http/mime_types.rb
  38. +16 −2 actionpack/lib/action_dispatch/http/request.rb
  39. +9 −2 actionpack/lib/action_dispatch/http/response.rb
  40. +1 −1 actionpack/lib/action_dispatch/middleware/show_exceptions.rb
  41. +50 −0 actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb
  42. +239 −0 actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb
  43. +169 −0 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb
  44. +45 −0 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb
  45. +27 −0 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb
  46. +36 −0 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb
  47. +75 −0 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb
  48. +14 −10 actionpack/lib/action_view/base.rb
  49. +2 −0 actionpack/lib/action_view/helpers/prototype_helper.rb
  50. +6 −0 actionpack/lib/action_view/template/handler.rb
  51. +2 −0 actionpack/lib/action_view/template/handlers/builder.rb
  52. +2 −0 actionpack/lib/action_view/template/handlers/erb.rb
  53. +6 −0 actionpack/lib/action_view/template/handlers/rjs.rb
  54. +9 −7 actionpack/lib/action_view/template/template.rb
  55. +10 −1 actionpack/lib/action_view/template/text.rb
  56. +1 −1 actionpack/lib/action_view/test_case.rb
  57. +6 −4 actionpack/test/abstract_unit.rb
  58. +3 −3 actionpack/test/controller/action_pack_assertions_test.rb
  59. +2 −0 actionpack/test/controller/caching_test.rb
  60. +2 −1 actionpack/test/controller/content_type_test.rb
  61. +27 −13 actionpack/test/controller/cookie_test.rb
  62. +42 −3 actionpack/test/controller/filter_params_test.rb
  63. +62 −84 actionpack/test/controller/filters_test.rb
  64. +25 −24 actionpack/test/controller/flash_test.rb
  65. +3 −3 actionpack/test/controller/helper_test.rb
  66. +9 −4 actionpack/test/controller/http_digest_authentication_test.rb
  67. +4 −3 actionpack/test/controller/integration_test.rb
  68. +27 −16 actionpack/test/controller/layout_test.rb
  69. +2 −2 actionpack/test/controller/logging_test.rb
  70. +29 −19 actionpack/test/controller/mime_responds_test.rb
  71. +2 −0 actionpack/test/controller/render_js_test.rb
  72. +19 −3 actionpack/test/controller/render_other_test.rb
  73. +1 −3 actionpack/test/controller/render_test.rb
  74. +1 −0 actionpack/test/controller/routing_test.rb
  75. +1 −0 actionpack/test/controller/selector_test.rb
  76. +22 −15 actionpack/test/controller/send_file_test.rb
  77. +7 −9 actionpack/test/controller/verification_test.rb
  78. +2 −2 actionpack/test/controller/webservice_test.rb
  79. +3 −0 actionpack/test/dispatch/session/cookie_store_test.rb
  80. +1 −1 actionpack/test/fixtures/layout_tests/layouts/third_party_template_library.mab
  81. 0 actionpack/test/fixtures/test/{greeting.erb → greeting.html.erb}
  82. 0 actionpack/test/{controller → }/html-scanner/cdata_node_test.rb
  83. 0 actionpack/test/{controller → }/html-scanner/document_test.rb
  84. 0 actionpack/test/{controller → }/html-scanner/node_test.rb
  85. 0 actionpack/test/{controller → }/html-scanner/sanitizer_test.rb
  86. 0 actionpack/test/{controller → }/html-scanner/tag_node_test.rb
  87. 0 actionpack/test/{controller → }/html-scanner/text_node_test.rb
  88. 0 actionpack/test/{controller → }/html-scanner/tokenizer_test.rb
  89. +3 −3 actionpack/test/{ → lib}/active_record_unit.rb
  90. 0 actionpack/test/{ → lib}/controller/fake_controllers.rb
  91. 0 actionpack/test/{ → lib}/controller/fake_models.rb
  92. +1 −1 actionpack/test/lib/fixture_template.rb
  93. 0 actionpack/test/{ → lib}/testing_sandbox.rb
  94. +31 −4 actionpack/test/{abstract_unit2.rb → new_base/abstract_unit.rb}
  95. +31 −49 actionpack/test/new_base/base_test.rb
  96. +60 −60 actionpack/test/new_base/content_type_test.rb
  97. +12 −13 actionpack/test/new_base/etag_test.rb
  98. +183 −205 actionpack/test/new_base/render_action_test.rb
  99. +14 −14 actionpack/test/new_base/render_implicit_action_test.rb
  100. +62 −34 actionpack/test/new_base/render_layout_test.rb
  101. +43 −44 actionpack/test/new_base/render_template_test.rb
  102. +21 −24 actionpack/test/new_base/render_test.rb
  103. +73 −83 actionpack/test/new_base/render_text_test.rb
  104. +13 −44 actionpack/test/new_base/test_helper.rb
  105. +4 −0 actionpack/test/template/javascript_helper_test.rb
  106. +4 −0 actionpack/test/template/prototype_helper_test.rb
  107. +1 −1 activerecord/lib/active_record/base.rb
  108. +1 −1 activerecord/test/cases/associations/eager_test.rb
  109. +1 −1 activesupport/CHANGELOG
  110. +9 −25 activesupport/lib/active_support.rb
  111. +3 −0 activesupport/lib/active_support/all.rb
  112. +25 −0 activesupport/lib/active_support/autoload.rb
  113. +1 −1 activesupport/lib/active_support/cache/mem_cache_store.rb
  114. +0 −7 activesupport/lib/active_support/core.rb
  115. +0 −5 activesupport/lib/active_support/core/all.rb
  116. +0 −4 activesupport/lib/active_support/core/time.rb
  117. +1 −2 activesupport/lib/active_support/core_ext/hash/conversions.rb
  118. +3 −80 activesupport/lib/active_support/core_ext/object/misc.rb
  119. +42 −0 activesupport/lib/active_support/core_ext/object/returning.rb
  120. +16 −0 activesupport/lib/active_support/core_ext/object/tap.rb
  121. +24 −0 activesupport/lib/active_support/core_ext/object/with_options.rb
  122. +1 −14 activesupport/lib/active_support/core_ext/symbol.rb
  123. +14 −0 activesupport/lib/active_support/core_ext/symbol/to_proc.rb
  124. +6 −4 activesupport/lib/active_support/dependency_module.rb
  125. +2 −2 activesupport/lib/active_support/json.rb
  126. +26 −2 activesupport/lib/active_support/new_callbacks.rb
  127. +24 −0 activesupport/lib/active_support/ruby/shim.rb
  128. +5 −0 activesupport/lib/active_support/test_case.rb
  129. +5 −0 activesupport/lib/active_support/testing/pending.rb
  130. +14 −0 activesupport/lib/active_support/time.rb
  131. 0 activesupport/lib/active_support/{core → }/time/autoload.rb
  132. 0 activesupport/memcached_get_multi.diff
  133. +6 −0 activesupport/test/caching_test.rb
  134. +1 −1 activesupport/test/core_ext/duration_test.rb
  135. +1 −1 activesupport/test/core_ext/numeric_ext_test.rb
  136. +1 −1 activesupport/test/core_ext/object_and_class_ext_test.rb
  137. +1 −1 activesupport/test/core_ext/time_ext_test.rb
  138. +11 −0 activesupport/test/dependency_module_test.rb
  139. +1 −1 activesupport/test/i18n_test.rb
  140. +62 −0 activesupport/test/new_callbacks_test.rb
  141. +1 −1 activesupport/test/time_zone_test.rb
  142. +1 −2 railties/lib/console_app.rb
  143. +1 −2 railties/lib/initializer.rb
  144. +3 −10 railties/lib/rails_generator.rb
  145. +2 −2 railties/lib/tasks/misc.rake
  146. +27 −33 tools/profile_requires
View
6 actionpack/test/adv_attr_test.rb → actionmailer/test/adv_attr_test.rb
@@ -1,4 +1,4 @@
-require File.dirname(__FILE__) + '/abstract_unit'
+require 'abstract_unit'
require 'action_mailer/adv_attr_accessor'
class AdvAttrTest < Test::Unit::TestCase
@@ -15,6 +15,4 @@ def test_adv_attr
assert_raise(ArgumentError) {bob.name 'x', 'y'}
end
-
-
-end
+end
View
35 actionpack/Rakefile
@@ -22,39 +22,62 @@ task :default => [ :test ]
# Run the unit tests
desc "Run all unit tests"
-task :test => [:test_action_pack, :test_active_record_integration, :test_new_base]
+task :test => [:test_action_pack, :test_active_record_integration, :test_new_base, :test_new_base_on_old_tests]
+test_lib_dirs = [ENV["NEW"] ? "test/new_base" : "test", "test/lib"]
Rake::TestTask.new(:test_action_pack) do |t|
- t.libs << "test"
+ t.libs.concat test_lib_dirs
# make sure we include the tests in alphabetical order as on some systems
# this will not happen automatically and the tests (as a whole) will error
- t.test_files = Dir.glob( "test/{controller,dispatch,template}/**/*_test.rb" ).sort
+ t.test_files = Dir.glob( "test/{controller,dispatch,template,html-scanner}/**/*_test.rb" ).sort
t.verbose = true
#t.warning = true
end
task :isolated_test do
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir.glob("test/{controller,dispatch,template}/**/*_test.rb").all? do |file|
- system(ruby, '-Ilib:test', file)
+ system(ruby, "-Ilib:#{test_lib_dirs * ':'}", file)
end or raise "Failures"
end
desc 'ActiveRecord Integration Tests'
Rake::TestTask.new(:test_active_record_integration) do |t|
- t.libs << "test"
+ t.libs.concat test_lib_dirs
t.test_files = Dir.glob("test/activerecord/*_test.rb")
t.verbose = true
end
desc 'New Controller Tests'
Rake::TestTask.new(:test_new_base) do |t|
- t.libs << "test"
+ t.libs << "test/new_base" << "test/lib"
t.test_files = Dir.glob("test/{abstract_controller,new_base}/*_test.rb")
t.verbose = true
end
+desc 'Old Controller Tests on New Base'
+Rake::TestTask.new(:test_new_base_on_old_tests) do |t|
+ t.libs << "test/new_base" << "test/lib"
+ # layout
+ # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort +
+
+ # ==== Not ported
+ # * filters
+ # * integration
+ # * test
+ # * view_paths
+ t.test_files = %w(
+ action_pack_assertions addresses_render assert_select
+ base benchmark caching capture content_type cookie dispatcher
+ filter_params flash helper http_basic_authentication
+ http_digest_authentication layout logging mime_responds
+ record_identifier redirect render render_js render_json
+ render_other render_xml request_forgery_protection rescue
+ resources routing selector send_file url_rewriter verification webservice
+ ).map { |name| "test/controller/#{name}_test.rb" }
+ t.verbose = true
+end
# Genereate the RDoc documentation
View
57 actionpack/examples/minimal.rb
@@ -1,34 +1,53 @@
+# Pass NEW=1 to run with the new Base
+ENV['RAILS_ENV'] ||= 'production'
+ENV['NO_RELOAD'] ||= '1'
+
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
require 'action_controller'
require 'action_controller/new_base' if ENV['NEW']
require 'benchmark'
-class BaseController < ActionController::Base
- def index
- render :text => ''
+class Runner
+ def initialize(app)
+ @app = app
end
-end
-n = (ENV['N'] || 10000).to_i
-input = StringIO.new('')
+ def call(env)
+ env['n'].to_i.times { @app.call(env) }
+ @app.call(env).tap { |response| report(env, response) }
+ end
+
+ def report(env, response)
+ out = env['rack.errors']
+ out.puts response[0], response[1].to_yaml, '---'
+ response[2].each { |part| out.puts part }
+ out.puts '---'
+ end
-def call_index(controller, input, n)
- n.times do
- controller.action(:index).call({ 'rack.input' => input })
+ def self.run(app, n)
+ env = { 'n' => n, 'rack.input' => StringIO.new(''), 'rack.errors' => $stdout }
+ t = Benchmark.realtime { new(app).call(env) }
+ puts "%d ms / %d req = %d usec/req" % [10**3 * t, n, 10**6 * t / n]
end
+end
+
- puts controller.name
- status, headers, body = controller.action(:index).call({ 'rack.input' => input })
+N = (ENV['N'] || 1000).to_i
- puts status
- puts headers.to_yaml
- puts '---'
- body.each do |part|
- puts part
+class BasePostController < ActionController::Base
+ def index
+ render :text => ''
end
- puts '---'
+
+ Runner.run(action(:index), N)
end
-elapsed = Benchmark.realtime { call_index BaseController, input, n }
+if ActionController.const_defined?(:Http)
+ class HttpPostController < ActionController::Http
+ def index
+ self.response_body = ''
+ end
-puts "%dms elapsed, %d requests/sec" % [1000 * elapsed, n / elapsed]
+ Runner.run(action(:index), N)
+ end
+end
View
1 actionpack/lib/action_controller.rb
@@ -66,6 +66,7 @@ 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 :FilterParameterLogging, 'action_controller/base/filter_parameter_logging'
module Assertions
autoload :DomAssertions, 'action_controller/testing/assertions/dom'
View
6 actionpack/lib/action_controller/abstract/base.rb
@@ -68,11 +68,11 @@ def initialize
self.response_obj = {}
end
- def process(action_name)
- @_action_name = action_name = action_name.to_s
+ def process(action)
+ @_action_name = action_name = action.to_s
unless action_name = method_for_action(action_name)
- raise ActionNotFound, "The action '#{action_name}' could not be found"
+ raise ActionNotFound, "The action '#{action}' could not be found"
end
process_action(action_name)
View
11 actionpack/lib/action_controller/abstract/callbacks.rb
@@ -36,6 +36,17 @@ def #{filter}_filter(*names, &blk)
process_action_callback(:#{filter}, name, options)
end
end
+
+ def skip_#{filter}_filter(*names, &blk)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+ _normalize_callback_options(options)
+ names.push(blk) if block_given?
+ names.each do |name|
+ skip_process_action_callback(:#{filter}, name, options)
+ end
+ end
+
+ alias_method :append_#{filter}_filter, :#{filter}_filter
RUBY_EVAL
end
end
View
27 actionpack/lib/action_controller/abstract/helpers.rb
@@ -24,11 +24,30 @@ def inherited(klass)
super
end
-
+
+ # Makes all the (instance) methods in the helper module available to templates rendered through this controller.
+ # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
+ # available to the templates.
def add_template_helper(mod)
master_helper_module.module_eval { include mod }
end
-
+
+ # Declare a controller method as a helper. For example, the following
+ # makes the +current_user+ controller method available to the view:
+ # class ApplicationController < ActionController::Base
+ # helper_method :current_user, :logged_in?
+ #
+ # def current_user
+ # @current_user ||= User.find_by_id(session[:user])
+ # end
+ #
+ # def logged_in?
+ # current_user != nil
+ # end
+ # end
+ #
+ # In a view:
+ # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
def helper_method(*meths)
meths.flatten.each do |meth|
master_helper_module.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
@@ -39,14 +58,14 @@ def #{meth}(*args, &blk)
end
end
- def helper(*args, &blk)
+ def helper(*args, &block)
args.flatten.each do |arg|
case arg
when Module
add_template_helper(arg)
end
end
- master_helper_module.module_eval(&blk) if block_given?
+ master_helper_module.module_eval(&block) if block_given?
end
end
View
52 actionpack/lib/action_controller/abstract/layouts.rb
@@ -4,11 +4,19 @@ module Layouts
depends_on Renderer
+ included do
+ extlib_inheritable_accessor :_layout_conditions
+ self._layout_conditions = {}
+ end
+
module ClassMethods
- def layout(layout)
+ def layout(layout, conditions = {})
unless [String, Symbol, FalseClass, NilClass].include?(layout.class)
raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
end
+
+ conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
+ self._layout_conditions = conditions
@_layout = layout || false # Converts nil to false
_write_layout_method
@@ -31,15 +39,15 @@ def _implied_layout_name
def _write_layout_method
case @_layout
when String
- self.class_eval %{def _layout() #{@_layout.inspect} end}
+ self.class_eval %{def _layout(details) #{@_layout.inspect} end}
when Symbol
- self.class_eval %{def _layout() #{@_layout} end}
+ self.class_eval %{def _layout(details) #{@_layout} end}
when false
- self.class_eval %{def _layout() end}
+ self.class_eval %{def _layout(details) end}
else
self.class_eval %{
- def _layout
- if view_paths.find_by_parts?("#{_implied_layout_name}", {:formats => formats}, "layouts")
+ def _layout(details)
+ if view_paths.find_by_parts?("#{_implied_layout_name}", details, "layouts")
"#{_implied_layout_name}"
else
super
@@ -49,38 +57,50 @@ def _layout
end
end
end
-
- def _render_template(template, options)
- _action_view._render_template_from_controller(template, options[:_layout], options, options[:_partial])
- end
private
- def _layout() end # This will be overwritten
+ def _layout(details) end # This will be overwritten
# :api: plugin
# ====
# Override this to mutate the inbound layout name
- def _layout_for_name(name)
+ def _layout_for_name(name, details = {:formats => formats})
unless [String, FalseClass, NilClass].include?(name.class)
raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}"
end
- name && view_paths.find_by_parts(name, {:formats => formats}, "layouts")
+ name && view_paths.find_by_parts(name, details, _layout_prefix(name))
+ end
+
+ # TODO: Decide if this is the best hook point for the feature
+ def _layout_prefix(name)
+ "layouts"
end
- def _default_layout(require_layout = false)
- if require_layout && !_layout
+ def _default_layout(require_layout = false, details = {:formats => formats})
+ if require_layout && _action_has_layout? && !_layout(details)
raise ArgumentError,
"There was no default layout for #{self.class} in #{view_paths.inspect}"
end
begin
- layout = _layout_for_name(_layout)
+ _layout_for_name(_layout(details), details) if _action_has_layout?
rescue NameError => e
raise NoMethodError,
"You specified #{@_layout.inspect} as the layout, but no such method was found"
end
end
+
+ def _action_has_layout?
+ conditions = _layout_conditions
+ if only = conditions[:only]
+ only.include?(action_name)
+ elsif except = conditions[:except]
+ !except.include?(action_name)
+ else
+ true
+ end
+ end
end
end
View
24 actionpack/lib/action_controller/abstract/renderer.rb
@@ -33,16 +33,12 @@ def render(*args)
#
# :api: plugin
def render_to_body(options = {})
- name = options[:_template_name] || action_name
-
# TODO: Refactor so we can just use the normal template logic for this
if options[:_partial_object]
_action_view._render_partial_from_controller(options)
- else
- options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats},
- options[:_prefix], options[:_partial])
-
- _render_template(options[:_template], options)
+ else
+ _determine_template(options)
+ _render_template(options)
end
end
@@ -56,8 +52,8 @@ def render_to_string(options = {})
AbstractController::Renderer.body_to_s(render_to_body(options))
end
- def _render_template(template, options)
- _action_view._render_template_from_controller(template, nil, options, options[:_partial])
+ def _render_template(options)
+ _action_view._render_template_from_controller(options[:_template], options[:_layout], options, options[:_partial])
end
def view_paths() _view_paths end
@@ -74,6 +70,16 @@ def self.body_to_s(body)
end
end
+ private
+
+ def _determine_template(options)
+ name = (options[:_template_name] || action_name).to_s
+
+ options[:_template] ||= view_paths.find_by_parts(
+ name, { :formats => formats }, options[:_prefix], options[:_partial]
+ )
+ end
+
module ClassMethods
def append_view_path(path)
View
59 actionpack/lib/action_controller/base/base.rb
@@ -242,7 +242,6 @@ class Base
# Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
# and images to a dedicated asset server away from the main web server. Example:
# ActionController::Base.asset_host = "http://assets.example.com"
- @@asset_host = ""
cattr_accessor :asset_host
# All requests are considered local by default, so everyone will be exposed to detailed debugging screens on errors.
@@ -448,55 +447,6 @@ def append_view_path(path)
@view_paths = superclass.view_paths.dup if @view_paths.nil?
@view_paths.push(*path)
end
-
- # Replace sensitive parameter data from the request log.
- # Filters parameters that have any of the arguments as a substring.
- # Looks in all subhashes of the param hash for keys to filter.
- # If a block is given, each key and value of the parameter hash and all
- # subhashes is passed to it, the value or key
- # can be replaced using String#replace or similar method.
- #
- # Examples:
- # filter_parameter_logging
- # => Does nothing, just slows the logging process down
- #
- # filter_parameter_logging :password
- # => replaces the value to all keys matching /password/i with "[FILTERED]"
- #
- # filter_parameter_logging :foo, "bar"
- # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
- #
- # filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
- # => reverses the value to all keys matching /secret/i
- #
- # filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
- # => reverses the value to all keys matching /secret/i, and
- # replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
- def filter_parameter_logging(*filter_words, &block)
- parameter_filter = Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true) if filter_words.length > 0
-
- define_method(:filter_parameters) do |unfiltered_parameters|
- filtered_parameters = {}
-
- unfiltered_parameters.each do |key, value|
- if key =~ parameter_filter
- filtered_parameters[key] = '[FILTERED]'
- elsif value.is_a?(Hash)
- filtered_parameters[key] = filter_parameters(value)
- elsif block_given?
- key = key.dup
- value = value.dup if value
- yield key, value
- filtered_parameters[key] = value
- else
- filtered_parameters[key] = value
- end
- end
-
- filtered_parameters
- end
- protected :filter_parameters
- end
@@exempt_from_layout = [ActionView::TemplateHandlers::RJS]
@@ -853,13 +803,6 @@ def log_processing_for_request_id
logger.info(request_id)
end
- def log_processing_for_parameters
- parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
- parameters = parameters.except!(:controller, :action, :format, :_method)
-
- logger.info " Parameters: #{parameters.inspect}" unless parameters.empty?
- end
-
def default_render #:nodoc:
render
end
@@ -933,7 +876,7 @@ def process_cleanup
[ Filters, Layout, Renderer, Redirector, Responder, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
Cookies, Caching, Verification, Streaming, SessionManagement,
HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods, RecordIdentifier,
- RequestForgeryProtection, Translation
+ RequestForgeryProtection, Translation, FilterParameterLogging
].each do |mod|
include mod
end
View
74 actionpack/lib/action_controller/base/chained/flash.rb
@@ -26,9 +26,18 @@ module ActionController #:nodoc:
#
# See docs on the FlashHash class for more details about the flash.
module Flash
- def self.included(base)
- base.class_eval do
- include InstanceMethods
+ extend ActiveSupport::DependencyModule
+
+ # TODO : Remove the defined? check when new base is the main base
+ depends_on Session if defined?(ActionController::Http)
+
+ included do
+ # TODO : Remove the defined? check when new base is the main base
+ if defined?(ActionController::Http)
+ include InstanceMethodsForNewBase
+ else
+ include InstanceMethodsForBase
+
alias_method_chain :perform_action, :flash
alias_method_chain :reset_session, :flash
end
@@ -135,29 +144,50 @@ def use(k=nil, v=true)
end
end
- module InstanceMethods #:nodoc:
+ module InstanceMethodsForBase #:nodoc:
protected
- def perform_action_with_flash
- perform_action_without_flash
- remove_instance_variable(:@_flash) if defined? @_flash
- end
- def reset_session_with_flash
- reset_session_without_flash
- remove_instance_variable(:@_flash) if defined? @_flash
- end
+ def perform_action_with_flash
+ perform_action_without_flash
+ remove_instance_variable(:@_flash) if defined?(@_flash)
+ end
- # Access the contents of the flash. Use <tt>flash["notice"]</tt> to
- # read a notice you put there or <tt>flash["notice"] = "hello"</tt>
- # to put a new one.
- def flash #:doc:
- unless defined? @_flash
- @_flash = session["flash"] ||= FlashHash.new
- @_flash.sweep
- end
+ def reset_session_with_flash
+ reset_session_without_flash
+ remove_instance_variable(:@_flash) if defined?(@_flash)
+ end
+ end
- @_flash
- end
+ module InstanceMethodsForNewBase #:nodoc:
+ protected
+
+ def reset_session
+ super
+ remove_flash_instance_variable
+ end
+
+ def process_action(method_name)
+ super
+ remove_flash_instance_variable
+ end
+
+ def remove_flash_instance_variable
+ remove_instance_variable(:@_flash) if defined?(@_flash)
+ end
+ end
+
+ protected
+
+ # Access the contents of the flash. Use <tt>flash["notice"]</tt> to
+ # read a notice you put there or <tt>flash["notice"] = "hello"</tt>
+ # to put a new one.
+ def flash #:doc:
+ unless defined?(@_flash)
+ @_flash = session["flash"] ||= FlashHash.new
+ @_flash.sweep
+ end
+
+ @_flash
end
end
end
View
97 actionpack/lib/action_controller/base/filter_parameter_logging.rb
@@ -0,0 +1,97 @@
+module ActionController
+ module FilterParameterLogging
+ extend ActiveSupport::DependencyModule
+
+ # TODO : Remove the defined? check when new base is the main base
+ if defined?(ActionController::Http)
+ depends_on AbstractController::Logger
+ end
+
+ included do
+ if defined?(ActionController::Http)
+ include InstanceMethodsForNewBase
+ end
+ end
+
+ module ClassMethods
+ # Replace sensitive parameter data from the request log.
+ # Filters parameters that have any of the arguments as a substring.
+ # Looks in all subhashes of the param hash for keys to filter.
+ # If a block is given, each key and value of the parameter hash and all
+ # subhashes is passed to it, the value or key
+ # can be replaced using String#replace or similar method.
+ #
+ # Examples:
+ # filter_parameter_logging
+ # => Does nothing, just slows the logging process down
+ #
+ # filter_parameter_logging :password
+ # => replaces the value to all keys matching /password/i with "[FILTERED]"
+ #
+ # filter_parameter_logging :foo, "bar"
+ # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
+ #
+ # filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
+ # => reverses the value to all keys matching /secret/i
+ #
+ # filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
+ # => reverses the value to all keys matching /secret/i, and
+ # replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
+ def filter_parameter_logging(*filter_words, &block)
+ parameter_filter = Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true) if filter_words.length > 0
+
+ define_method(:filter_parameters) do |unfiltered_parameters|
+ filtered_parameters = {}
+
+ unfiltered_parameters.each do |key, value|
+ if key =~ parameter_filter
+ filtered_parameters[key] = '[FILTERED]'
+ elsif value.is_a?(Hash)
+ filtered_parameters[key] = filter_parameters(value)
+ elsif block_given?
+ key = key.dup
+ value = value.dup if value
+ yield key, value
+ filtered_parameters[key] = value
+ else
+ filtered_parameters[key] = value
+ end
+ end
+
+ filtered_parameters
+ end
+ protected :filter_parameters
+ end
+ end
+
+ module InstanceMethodsForNewBase
+ # TODO : Fix the order of information inside such that it's exactly same as the old base
+ def process(*)
+ ret = super
+
+ if logger
+ parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
+ parameters = parameters.except!(:controller, :action, :format, :_method, :only_path)
+
+ unless parameters.empty?
+ # TODO : Move DelayedLog to AS
+ log = AbstractController::Logger::DelayedLog.new { " Parameters: #{parameters.inspect}" }
+ logger.info(log)
+ end
+ end
+
+ ret
+ end
+ end
+
+ private
+
+ # TODO : This method is not needed for the new base
+ def log_processing_for_parameters
+ parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
+ parameters = parameters.except!(:controller, :action, :format, :_method)
+
+ logger.info " Parameters: #{parameters.inspect}" unless parameters.empty?
+ end
+ end
+end
View
22 actionpack/lib/action_controller/base/helpers.rb
@@ -3,23 +3,19 @@
# FIXME: helper { ... } is broken on Ruby 1.9
module ActionController #:nodoc:
module Helpers #:nodoc:
- def self.included(base)
+ extend ActiveSupport::DependencyModule
+
+ included do
# Initialize the base module to aggregate its helpers.
- base.class_inheritable_accessor :master_helper_module
- base.master_helper_module = Module.new
+ class_inheritable_accessor :master_helper_module
+ self.master_helper_module = Module.new
# Set the default directory for helpers
- base.class_inheritable_accessor :helpers_dir
- base.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
-
- # Extend base with class methods to declare helpers.
- base.extend(ClassMethods)
+ class_inheritable_accessor :helpers_dir
+ self.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
- base.class_eval do
- # Wrap inherited to create a new master helper module for subclasses.
- class << self
- alias_method_chain :inherited, :helper
- end
+ class << self
+ alias_method_chain :inherited, :helper
end
end
View
210 actionpack/lib/action_controller/base/mime_responds.rb
@@ -1,111 +1,103 @@
module ActionController #:nodoc:
module MimeResponds #:nodoc:
- def self.included(base)
- base.module_eval do
- include ActionController::MimeResponds::InstanceMethods
- end
- end
-
- module InstanceMethods
- # Without web-service support, an action which collects the data for displaying a list of people
- # might look something like this:
- #
- # def index
- # @people = Person.find(:all)
- # end
- #
- # Here's the same action, with web-service support baked in:
- #
- # def index
- # @people = Person.find(:all)
- #
- # respond_to do |format|
- # format.html
- # format.xml { render :xml => @people.to_xml }
- # end
- # end
- #
- # What that says is, "if the client wants HTML in response to this action, just respond as we
- # would have before, but if the client wants XML, return them the list of people in XML format."
- # (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
- #
- # Supposing you have an action that adds a new person, optionally creating their company
- # (by name) if it does not already exist, without web-services, it might look like this:
- #
- # def create
- # @company = Company.find_or_create_by_name(params[:company][:name])
- # @person = @company.people.create(params[:person])
- #
- # redirect_to(person_list_url)
- # end
- #
- # Here's the same action, with web-service support baked in:
- #
- # def create
- # company = params[:person].delete(:company)
- # @company = Company.find_or_create_by_name(company[:name])
- # @person = @company.people.create(params[:person])
- #
- # respond_to do |format|
- # format.html { redirect_to(person_list_url) }
- # format.js
- # format.xml { render :xml => @person.to_xml(:include => @company) }
- # end
- # end
- #
- # If the client wants HTML, we just redirect them back to the person list. If they want Javascript
- # (format.js), then it is an RJS request and we render the RJS template associated with this action.
- # Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also
- # include the person's company in the rendered XML, so you get something like this:
- #
- # <person>
- # <id>...</id>
- # ...
- # <company>
- # <id>...</id>
- # <name>...</name>
- # ...
- # </company>
- # </person>
- #
- # Note, however, the extra bit at the top of that action:
- #
- # company = params[:person].delete(:company)
- # @company = Company.find_or_create_by_name(company[:name])
- #
- # This is because the incoming XML document (if a web-service request is in process) can only contain a
- # single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
- #
- # person[name]=...&person[company][name]=...&...
- #
- # And, like this (xml-encoded):
- #
- # <person>
- # <name>...</name>
- # <company>
- # <name>...</name>
- # </company>
- # </person>
- #
- # In other words, we make the request so that it operates on a single entity's person. Then, in the action,
- # we extract the company data from the request, find or create the company, and then create the new person
- # with the remaining data.
- #
- # Note that you can define your own XML parameter parser which would allow you to describe multiple entities
- # in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
- # and accept Rails' defaults, life will be much easier.
- #
- # If you need to use a MIME type which isn't supported by default, you can register your own handlers in
- # environment.rb as follows.
- #
- # Mime::Type.register "image/jpg", :jpg
- def respond_to(*types, &block)
- raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block
- block ||= lambda { |responder| types.each { |type| responder.send(type) } }
- responder = Responder.new(self)
- block.call(responder)
- responder.respond
- end
+ # Without web-service support, an action which collects the data for displaying a list of people
+ # might look something like this:
+ #
+ # def index
+ # @people = Person.find(:all)
+ # end
+ #
+ # Here's the same action, with web-service support baked in:
+ #
+ # def index
+ # @people = Person.find(:all)
+ #
+ # respond_to do |format|
+ # format.html
+ # format.xml { render :xml => @people.to_xml }
+ # end
+ # end
+ #
+ # What that says is, "if the client wants HTML in response to this action, just respond as we
+ # would have before, but if the client wants XML, return them the list of people in XML format."
+ # (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
+ #
+ # Supposing you have an action that adds a new person, optionally creating their company
+ # (by name) if it does not already exist, without web-services, it might look like this:
+ #
+ # def create
+ # @company = Company.find_or_create_by_name(params[:company][:name])
+ # @person = @company.people.create(params[:person])
+ #
+ # redirect_to(person_list_url)
+ # end
+ #
+ # Here's the same action, with web-service support baked in:
+ #
+ # def create
+ # company = params[:person].delete(:company)
+ # @company = Company.find_or_create_by_name(company[:name])
+ # @person = @company.people.create(params[:person])
+ #
+ # respond_to do |format|
+ # format.html { redirect_to(person_list_url) }
+ # format.js
+ # format.xml { render :xml => @person.to_xml(:include => @company) }
+ # end
+ # end
+ #
+ # If the client wants HTML, we just redirect them back to the person list. If they want Javascript
+ # (format.js), then it is an RJS request and we render the RJS template associated with this action.
+ # Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also
+ # include the person's company in the rendered XML, so you get something like this:
+ #
+ # <person>
+ # <id>...</id>
+ # ...
+ # <company>
+ # <id>...</id>
+ # <name>...</name>
+ # ...
+ # </company>
+ # </person>
+ #
+ # Note, however, the extra bit at the top of that action:
+ #
+ # company = params[:person].delete(:company)
+ # @company = Company.find_or_create_by_name(company[:name])
+ #
+ # This is because the incoming XML document (if a web-service request is in process) can only contain a
+ # single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
+ #
+ # person[name]=...&person[company][name]=...&...
+ #
+ # And, like this (xml-encoded):
+ #
+ # <person>
+ # <name>...</name>
+ # <company>
+ # <name>...</name>
+ # </company>
+ # </person>
+ #
+ # In other words, we make the request so that it operates on a single entity's person. Then, in the action,
+ # we extract the company data from the request, find or create the company, and then create the new person
+ # with the remaining data.
+ #
+ # Note that you can define your own XML parameter parser which would allow you to describe multiple entities
+ # in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
+ # and accept Rails' defaults, life will be much easier.
+ #
+ # If you need to use a MIME type which isn't supported by default, you can register your own handlers in
+ # environment.rb as follows.
+ #
+ # Mime::Type.register "image/jpg", :jpg
+ def respond_to(*types, &block)
+ raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block
+ block ||= lambda { |responder| types.each { |type| responder.send(type) } }
+ responder = Responder.new(self)
+ block.call(responder)
+ responder.respond
end
class Responder #:nodoc:
@@ -127,8 +119,14 @@ def custom(mime_type, &block)
@order << mime_type
@responses[mime_type] ||= Proc.new do
+ # TODO: Remove this when new base is merged in
+ if defined?(Http)
+ @controller.formats = [mime_type.to_sym]
+ end
+
@controller.template.formats = [mime_type.to_sym]
@response.content_type = mime_type.to_s
+
block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
end
end
View
24 actionpack/lib/action_controller/base/request_forgery_protection.rb
@@ -3,12 +3,26 @@ class InvalidAuthenticityToken < ActionControllerError #:nodoc:
end
module RequestForgeryProtection
- def self.included(base)
- base.class_eval do
- helper_method :form_authenticity_token
- helper_method :protect_against_forgery?
+ extend ActiveSupport::DependencyModule
+
+ # TODO : Remove the defined? check when new base is the main base
+ if defined?(ActionController::Http)
+ depends_on AbstractController::Helpers, Session
+ end
+
+ included do
+ if defined?(ActionController::Http)
+ # Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
+ # sets it to <tt>:authenticity_token</tt> by default.
+ cattr_accessor :request_forgery_protection_token
+
+ # Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
+ class_inheritable_accessor :allow_forgery_protection
+ self.allow_forgery_protection = true
end
- base.extend(ClassMethods)
+
+ helper_method :form_authenticity_token
+ helper_method :protect_against_forgery?
end
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current web application, not a
View
8 actionpack/lib/action_controller/base/streaming.rb
@@ -2,6 +2,13 @@ module ActionController #:nodoc:
# Methods for sending arbitrary data and for streaming files to the browser,
# instead of rendering.
module Streaming
+ extend ActiveSupport::DependencyModule
+
+ # TODO : Remove the defined? check when new base is the main base
+ if defined?(ActionController::Http)
+ depends_on ActionController::Renderer
+ end
+
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
:disposition => 'attachment'.freeze,
@@ -88,6 +95,7 @@ def send_file(path, options = {}) #:doc:
head options[:status], X_SENDFILE_HEADER => path
else
if options[:stream]
+ # TODO : Make render :text => proc {} work with the new base
render :status => options[:status], :text => Proc.new { |response, output|
logger.info "Streaming file #{path}" unless logger.nil?
len = options[:buffer_size] || 4096
View
9 actionpack/lib/action_controller/base/verification.rb
@@ -1,7 +1,10 @@
module ActionController #:nodoc:
module Verification #:nodoc:
- def self.included(base) #:nodoc:
- base.extend(ClassMethods)
+ extend ActiveSupport::DependencyModule
+
+ # TODO : Remove the defined? check when new base is the main base
+ if defined?(ActionController::Http)
+ depends_on AbstractController::Callbacks, Session, Flash, Renderer
end
# This module provides a class-level method for specifying that certain
@@ -102,7 +105,7 @@ def prereqs_invalid?(options) # :nodoc:
end
def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc:
- [*options[:params] ].find { |v| params[v].nil? } ||
+ [*options[:params] ].find { |v| v && params[v.to_sym].nil? } ||
[*options[:session]].find { |v| session[v].nil? } ||
[*options[:flash] ].find { |v| flash[v].nil? }
end
View
30 actionpack/lib/action_controller/caching.rb
@@ -24,31 +24,31 @@ module ActionController #:nodoc:
# ActionController::Base.cache_store = :mem_cache_store, "localhost"
# ActionController::Base.cache_store = MyOwnStore.new("parameter")
module Caching
+ extend ActiveSupport::DependencyModule
+
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:
- base.class_eval do
- @@cache_store = nil
- cattr_reader :cache_store
+ included do
+ @@cache_store = nil
+ cattr_reader :cache_store
- # Defines the storage option for cached fragments
- def self.cache_store=(store_option)
- @@cache_store = ActiveSupport::Cache.lookup_store(store_option)
- end
+ # Defines the storage option for cached fragments
+ def self.cache_store=(store_option)
+ @@cache_store = ActiveSupport::Cache.lookup_store(store_option)
+ end
- include Pages, Actions, Fragments
- include Sweeping if defined?(ActiveRecord)
+ include Pages, Actions, Fragments
+ include Sweeping if defined?(ActiveRecord)
- @@perform_caching = true
- cattr_accessor :perform_caching
+ @@perform_caching = true
+ cattr_accessor :perform_caching
- def self.cache_configured?
- perform_caching && cache_store
- end
+ def self.cache_configured?
+ perform_caching && cache_store
end
end
View
32 actionpack/lib/action_controller/caching/actions.rb
@@ -61,8 +61,14 @@ def caches_action(*actions)
filter_options = { :only => actions, :if => options.delete(:if), :unless => options.delete(:unless) }
cache_filter = ActionCacheFilter.new(:layout => options.delete(:layout), :cache_path => options.delete(:cache_path), :store_options => options)
- around_filter(filter_options) do |controller, action|
- cache_filter.filter(controller, action)
+
+ # TODO: Remove this once new base is swapped in.
+ if defined?(ActionController::Http)
+ around_filter cache_filter, filter_options
+ else
+ around_filter(filter_options) do |controller, action|
+ cache_filter.filter(controller, action)
+ end
end
end
end
@@ -85,14 +91,24 @@ def initialize(options, &block)
@options = options
end
- def filter(controller, action)
- should_continue = before(controller)
- action.call if should_continue
- after(controller)
+ # TODO: Remove once New Base is merged
+ if defined?(ActionController::Http)
+ def around_process_action(controller)
+ should_continue = before(controller)
+ yield if should_continue
+ after(controller)
+ end
+ else
+ def filter(controller, action)
+ should_continue = before(controller)
+ action.call if should_continue
+ after(controller)
+ end
end
def before(controller)
cache_path = ActionCachePath.new(controller, path_options_for(controller, @options.slice(:cache_path)))
+
if cache = controller.read_fragment(cache_path.path, @options[:store_options])
controller.rendered_action_cache = true
set_content_type!(controller, cache_path.extension)
@@ -129,7 +145,9 @@ def cache_layout?
end
def content_for_layout(controller)
- controller.template.layout && controller.template.instance_variable_get('@cached_content_for_layout')
+ # TODO: Remove this when new base is merged in
+ template = controller.respond_to?(:template) ? controller.template : controller._action_view
+ template.layout && template.instance_variable_get('@cached_content_for_layout')
end
end
View
21 actionpack/lib/action_controller/new_base.rb
@@ -7,23 +7,38 @@ module ActionController
autoload :Rails2Compatibility, "action_controller/new_base/compatibility"
autoload :Redirector, "action_controller/new_base/redirector"
autoload :Renderer, "action_controller/new_base/renderer"
+ autoload :RenderOptions, "action_controller/new_base/render_options"
+ autoload :Renderers, "action_controller/new_base/render_options"
autoload :Rescue, "action_controller/new_base/rescuable"
autoload :Testing, "action_controller/new_base/testing"
autoload :UrlFor, "action_controller/new_base/url_for"
-
+ autoload :Session, "action_controller/new_base/session"
+ autoload :Helpers, "action_controller/new_base/helpers"
+
# Ported modules
# require 'action_controller/routing'
+ autoload :Caching, 'action_controller/caching'
autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
+ autoload :MimeResponds, 'action_controller/base/mime_responds'
autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes'
autoload :RecordIdentifier, 'action_controller/record_identifier'
autoload :Resources, 'action_controller/routing/resources'
autoload :SessionManagement, 'action_controller/base/session_management'
autoload :TestCase, 'action_controller/testing/test_case'
autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter'
autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter'
-
+
+ autoload :Verification, 'action_controller/base/verification'
+ autoload :Flash, 'action_controller/base/chained/flash'
+ autoload :RequestForgeryProtection, 'action_controller/base/request_forgery_protection'
+ autoload :Streaming, 'action_controller/base/streaming'
+ autoload :HttpAuthentication, 'action_controller/base/http_authentication'
+ autoload :FilterParameterLogging, 'action_controller/base/filter_parameter_logging'
+ autoload :Translation, 'action_controller/translation'
+ autoload :Cookies, 'action_controller/base/cookies'
+
require 'action_controller/routing'
end
require 'action_dispatch'
-require 'action_view'
+require 'action_view'
View
50 actionpack/lib/action_controller/new_base/base.rb
@@ -4,40 +4,54 @@ class Base < Http
include AbstractController::Benchmarker
include AbstractController::Callbacks
- include AbstractController::Helpers
include AbstractController::Logger
-
+
+ include ActionController::Helpers
include ActionController::HideActions
include ActionController::UrlFor
include ActionController::Redirector
include ActionController::Renderer
+ include ActionController::Renderers::All
include ActionController::Layouts
include ActionController::ConditionalGet
# Legacy modules
include SessionManagement
include ActionDispatch::StatusCodes
+ include ActionController::Caching
+ include ActionController::MimeResponds
# Rails 2.x compatibility
include ActionController::Rails2Compatibility
+ include ActionController::Cookies
+ include ActionController::Session
+ include ActionController::Flash
+ include ActionController::Verification
+ include ActionController::RequestForgeryProtection
+ include ActionController::Streaming
+ include ActionController::HttpAuthentication::Basic::ControllerMethods
+ include ActionController::HttpAuthentication::Digest::ControllerMethods
+ include ActionController::FilterParameterLogging
+ include ActionController::Translation
+
# TODO: Extract into its own module
# This should be moved together with other normalizing behavior
module ImplicitRender
def process_action(method_name)
ret = super
- render if response_body.nil?
+ default_render if response_body.nil?
ret
end
- def _implicit_render
+ def default_render
render
end
def method_for_action(action_name)
super || begin
if view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
- "_implicit_render"
+ "default_render"
end
end
end
@@ -62,7 +76,7 @@ def self.app_loaded!
end
end
- def render_to_body(action = nil, options = {})
+ def _normalize_options(action = nil, options = {}, &blk)
if action.is_a?(Hash)
options, action = action, nil
elsif action.is_a?(String) || action.is_a?(Symbol)
@@ -79,11 +93,25 @@ def render_to_body(action = nil, options = {})
if options.key?(:action) && options[:action].to_s.index("/")
options[:template] = options.delete(:action)
end
-
- # options = {:template => options.to_s} if options.is_a?(String) || options.is_a?(Symbol)
- super(options) || " "
+
+ if options[:status]
+ options[:status] = interpret_status(options[:status]).to_i
+ end
+
+ options[:update] = blk if block_given?
+ options
end
-
+
+ def render(action = nil, options = {}, &blk)
+ options = _normalize_options(action, options, &blk)
+ super(options)
+ end
+
+ def render_to_string(action = nil, options = {}, &blk)
+ options = _normalize_options(action, options, &blk)
+ super(options)
+ end
+
# Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
#
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
@@ -141,4 +169,4 @@ def redirect_to(options = {}, response_status = {}) #:doc:
super(url, status)
end
end
-end
+end
View
38 actionpack/lib/action_controller/new_base/compatibility.rb
@@ -1,7 +1,10 @@
module ActionController
module Rails2Compatibility
extend ActiveSupport::DependencyModule
-
+
+ class ::ActionController::ActionControllerError < StandardError #:nodoc:
+ end
+
# Temporary hax
included do
::ActionController::UnknownAction = ::AbstractController::ActionNotFound
@@ -53,10 +56,23 @@ module Rails2Compatibility
cattr_accessor :consider_all_requests_local
self.consider_all_requests_local = true
+
+ # Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
+ # and images to a dedicated asset server away from the main web server. Example:
+ # ActionController::Base.asset_host = "http://assets.example.com"
+ cattr_accessor :asset_host
end
+ # For old tests
+ def initialize_template_class(*) end
+ def assign_shortcuts(*) end
+
+ # TODO: Remove this after we flip
+ def template
+ _action_view
+ end
+
module ClassMethods
- def protect_from_forgery() end
def consider_all_requests_local() end
def rescue_action(env)
raise env["action_dispatch.rescue.exception"]
@@ -67,7 +83,7 @@ def cache_store=(store_option)
@@cache_store = ActiveSupport::Cache.lookup_store(store_option)
end
end
-
+
def initialize(*)
super
@template = _action_view
@@ -80,7 +96,9 @@ def render_to_body(options)
options[:text] = nil if options[:nothing] == true
- super
+ body = super
+ body = [' '] if body.blank?
+ body
end
def _handle_method_missing
@@ -91,10 +109,12 @@ def method_for_action(action_name)
super || (respond_to?(:method_missing) && "_handle_method_missing")
end
- def _layout_for_name(name)
- name &&= name.sub(%r{^/?layouts/}, '')
- super
+ def _layout_prefix(name)
+ super unless name =~ /\blayouts/
+ end
+
+ def performed?
+ response_body
end
-
end
-end
+end
View
2 actionpack/lib/action_controller/new_base/conditional_get.rb
@@ -57,7 +57,7 @@ def head(*args)
raise ArgumentError, "too few arguments to head"
end
options = args.extract_options!
- status = interpret_status(args.shift || options.delete(:status) || :ok)
+ status = args.shift || options.delete(:status) || :ok
options.each do |key, value|
headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
View
130 actionpack/lib/action_controller/new_base/helpers.rb
@@ -0,0 +1,130 @@
+require 'active_support/core_ext/load_error'
+require 'active_support/core_ext/name_error'
+require 'active_support/dependencies'
+
+module ActionController
+ module Helpers
+ extend ActiveSupport::DependencyModule
+
+ depends_on AbstractController::Helpers
+
+ included do
+ # Set the default directory for helpers
+ class_inheritable_accessor :helpers_dir
+ self.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
+ end
+
+ module ClassMethods
+ def inherited(klass)
+ klass.__send__ :default_helper_module!
+ super
+ end
+
+ # The +helper+ class method can take a series of helper module names, a block, or both.
+ #
+ # * <tt>*args</tt>: One or more modules, strings or symbols, or the special symbol <tt>:all</tt>.
+ # * <tt>&block</tt>: A block defining helper methods.
+ #
+ # ==== Examples
+ # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file
+ # and include the module in the template class. The second form illustrates how to include custom helpers
+ # when working with namespaced controllers, or other cases where the file containing the helper definition is not
+ # in one of Rails' standard load paths:
+ # helper :foo # => requires 'foo_helper' and includes FooHelper
+ # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
+ #
+ # When the argument is a module it will be included directly in the template class.
+ # helper FooHelper # => includes FooHelper
+ #
+ # When the argument is the symbol <tt>:all</tt>, the controller will include all helpers beneath
+ # <tt>ActionController::Base.helpers_dir</tt> (defaults to <tt>app/helpers/**/*.rb</tt> under RAILS_ROOT).
+ # helper :all
+ #
+ # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
+ # to the template.
+ # # One line
+ # helper { def hello() "Hello, world!" end }
+ # # Multi-line
+ # helper do
+ # def foo(bar)
+ # "#{bar} is the very best"
+ # end
+ # end
+ #
+ # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
+ # +symbols+, +strings+, +modules+ and blocks.
+ # helper(:three, BlindHelper) { def mice() 'mice' end }
+ #
+ def helper(*args, &block)
+ args.flatten.each do |arg|
+ case arg
+ when :all
+ helper all_application_helpers
+ when String, Symbol
+ file_name = arg.to_s.underscore + '_helper'
+ class_name = file_name.camelize
+
+ begin
+ require_dependency(file_name)
+ rescue LoadError => load_error
+ requiree = / -- (.*?)(\.rb)?$/.match(load_error.message).to_a[1]
+ if requiree == file_name
+ msg = "Missing helper file helpers/#{file_name}.rb"
+ raise LoadError.new(msg).copy_blame!(load_error)
+ else
+ raise
+ end
+ end
+
+ super class_name.constantize
+ else
+ super args
+ end
+ end
+
+ # Evaluate block in template class if given.
+ master_helper_module.module_eval(&block) if block_given?
+ end
+
+ # Declares helper accessors for controller attributes. For example, the
+ # following adds new +name+ and <tt>name=</tt> instance methods to a
+ # controller and makes them available to the view:
+ # helper_attr :name
+ # attr_accessor :name
+ def helper_attr(*attrs)
+ attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
+ end
+
+ # Provides a proxy to access helpers methods from outside the view.
+ def helpers
+ unless @helper_proxy
+ @helper_proxy = ActionView::Base.new
+ @helper_proxy.extend master_helper_module
+ else
+ @helper_proxy
+ end
+ end
+
+ private
+
+ def default_helper_module!
+ unless name.blank?
+ module_name = name.sub(/Controller$|$/, 'Helper')
+ module_path = module_name.split('::').map { |m| m.underscore }.join('/')
+ require_dependency module_path
+ helper module_name.constantize
+ end
+ rescue MissingSourceFile => e
+ raise unless e.is_missing? module_path
+ rescue NameError => e
+ raise unless e.missing_name? module_name
+ end
+
+ # Extract helper names from files in app/helpers/**/*.rb
+ def all_application_helpers
+ extract = /^#{Regexp.quote(helpers_dir)}\/?(.*)_helper.rb$/
+ Dir["#{helpers_dir}/**/*_helper.rb"].map { |file| file.sub extract, '\1' }
+ end
+ end # ClassMethods
+ end
+end
View
3 actionpack/lib/action_controller/new_base/http.rb
@@ -37,7 +37,7 @@ def self.call(env)
end
delegate :headers, :to => "@_response"
-
+
def params
@_params ||= @_request.parameters
end
@@ -60,7 +60,6 @@ def self.action(name)
# :api: private
def to_rack
- @_response.body = response_body
@_response.prepare!
@_response.to_a
end
View
21 actionpack/lib/action_controller/new_base/layouts.rb
@@ -11,23 +11,20 @@ def _implied_layout_name
end
end
- def render_to_body(options)
- # render :text => ..., :layout => ...
- # or
- # render :anything_else
+ private
+
+ def _determine_template(options)
+ super
if (!options.key?(:text) && !options.key?(:inline) && !options.key?(:partial)) || options.key?(:layout)
- options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout
+ options[:_layout] = _layout_for_option(options.key?(:layout) ? options[:layout] : :none, options[:_template].details)
end
-
- super
end
-
- private
- def _layout_for_option(name)
+ def _layout_for_option(name, details)
case name
- when String then _layout_for_name(name)
- when true then _default_layout(true)
+ when String then _layout_for_name(name, details)
+ when true then _default_layout(true, details)
+ when :none then _default_layout(false, details)
when false, nil then nil
else
raise ArgumentError,
View
107 actionpack/lib/action_controller/new_base/render_options.rb
@@ -0,0 +1,107 @@
+module ActionController
+ module RenderOptions
+ extend ActiveSupport::DependencyModule
+
+ included do
+ extlib_inheritable_accessor :_renderers
+ self._renderers = []
+ end
+
+ module ClassMethods
+ def _write_render_options
+ renderers = _renderers.map do |r|
+ <<-RUBY_EVAL
+ if options.key?(:#{r})
+ _process_options(options)
+ return _render_#{r}(options[:#{r}], options)
+ end
+ RUBY_EVAL
+ end
+
+ class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def _handle_render_options(options)
+ #{renderers.join}
+ end
+ RUBY_EVAL
+ end
+
+ def _add_render_option(name)
+ _renderers << name
+ _write_render_options
+ end
+ end
+
+ def render_to_body(options)
+ _handle_render_options(options) || super
+ end
+ end
+
+ module RenderOption
+ extend ActiveSupport::DependencyModule
+
+ included do
+ extend ActiveSupport::DependencyModule
+ depends_on ::ActionController::RenderOptions
+
+ def self.register_renderer(name)
+ included { _add_render_option(name) }
+ end
+ end
+ end
+
+ module Renderers
+ module Json
+ include RenderOption
+ register_renderer :json
+
+ def _render_json(json, options)
+ json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str)
+ json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
+ response.content_type ||= Mime::JSON
+ self.response_body = json
+ end
+ end
+
+ module Js
+ include RenderOption
+ register_renderer :js
+
+ def _render_js(js, options)
+ response.content_type ||= Mime::JS
+ self.response_body = js
+ end
+ end
+
+ module Xml
+ include RenderOption
+ register_renderer :xml
+
+ def _render_xml(xml, options)
+ response.content_type ||= Mime::XML
+ self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml
+ end
+ end
+
+ module Rjs
+ include RenderOption
+ register_renderer :update
+
+ def _render_update(proc, options)
+ generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(_action_view, &proc)
+ response.content_type = Mime::JS
+ self.response_body = generator.to_s
+ end
+ end
+
+ module All
+ extend ActiveSupport::DependencyModule
+
+ included do
+ include ::ActionController::Renderers::Json
+ include ::ActionController::Renderers::Js
+ include ::ActionController::Renderers::Xml
+ include ::ActionController::Renderers::Rjs
+ end
+ end
+ end
+end
View
66 actionpack/lib/action_controller/new_base/renderer.rb
@@ -4,17 +4,45 @@ module Renderer
depends_on AbstractController::Renderer
- def initialize(*)
- self.formats = [:html]
+ def process_action(*)
+ self.formats = request.formats.map {|x| x.to_sym}
super
end
+ def response_body=(body)
+ response.body = body if response
+ super
+ end
+
+ def render(options)
+ super
+ options[:_template] ||= _action_view._partial
+ response.content_type ||= begin
+ mime = options[:_template].mime_type
+ formats.include?(mime && mime.to_sym) || formats.include?(:all) ? mime : Mime::Type.lookup_by_extension(formats.first)
+ end
+ response_body
+ end
+
def render_to_body(options)
_process_options(options)
+ if options.key?(:partial)
+ _render_partial(options[:partial], options)
+ end
+
+ super
+ end
+
+ private
+
+ def _prefix
+ controller_path
+ end
+
+ def _determine_template(options)
if options.key?(:text)
- options[:_template] = ActionView::TextTemplate.new(_text(options))
- template = nil
+ options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first)
elsif options.key?(:inline)
handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
@@ -23,35 +51,14 @@ def render_to_body(options)
options[:_template_name] = options[:template]
elsif options.key?(:file)
options[:_template_name] = options[:file]
- elsif options.key?(:partial)
- _render_partial(options[:partial], options)
- else
+ elsif !options.key?(:partial)
options[:_template_name] = (options[:action] || action_name).to_s
options[:_prefix] = _prefix
end
- ret = super(options)
-
- options[:_template] ||= _action_view._partial
- response.content_type ||= options[:_template].mime_type
- ret
+ super
end
-
- private
-
- def _prefix
- controller_path
- end
-
- def _text(options)
- text = options[:text]
- case text
- when nil then " "
- else text.to_s
- end
- end
-
def _render_partial(partial, options)
case partial
when true
@@ -68,9 +75,10 @@ def _render_partial(partial, options)
end
def _process_options(options)
- status, content_type = options.values_at(:status, :content_type)
- response.status = status.to_i if status
+ status, content_type, location = options.values_at(:status, :content_type, :location)
+ response.status = status if status
response.content_type = content_type if content_type
+ response.headers["Location"] = url_for(location) if location
end
end
end
View
11 actionpack/lib/action_controller/new_base/session.rb
@@ -0,0 +1,11 @@
+module ActionController
+ module Session
+ def session
+ @_request.session
+ end
+
+ def reset_session
+ @_request.reset_session
+ end
+ end
+end
View
23 actionpack/lib/action_controller/new_base/testing.rb
@@ -1,13 +1,14 @@
module ActionController
module Testing
-
+ extend ActiveSupport::DependencyModule
+
# OMG MEGA HAX
- def process_with_test(request, response)
+ def process_with_new_base_test(request, response)
@_request = request
@_response = response
@_response.request = request
ret = process(request.parameters[:action])
- @_response.body = self.response_body || " "
+ @_response.body ||= self.response_body
@_response.prepare!
set_test_assigns
ret
@@ -20,6 +21,18 @@ def set_test_assigns
@assigns[name] = value
end
end
-
+
+ # TODO : Rewrite tests using controller.headers= to use Rack env
+ def headers=(new_headers)
+ @_response ||= ActionDispatch::Response.new
+ @_response.headers.replace(new_headers)
+ end
+
+ module ClassMethods
+ def before_filters
+ _process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name}
+ end
+ end
+
end
-end
+end
View
5 actionpack/lib/action_controller/new_base/url_for.rb
@@ -1,5 +1,10 @@
module ActionController
module UrlFor
+ def process_action(*)
+ initialize_current_url
+ super
+ end
+
def initialize_current_url
@url = UrlRewriter.new(request, params.clone)
end
View
48 actionpack/lib/action_controller/testing/integration.rb