aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2010-03-12 16:00:01 +0000
committerPratik Naik <pratiknaik@gmail.com>2010-03-12 16:00:01 +0000
commite68bfaf1fe1a7890a67af6f444281185f507cf9e (patch)
tree5e73caccdcdd65d0ac97f9eb92195928f30925f2 /actionpack
parentef6462c73003b28c8e060a06120abb9cd67b6d52 (diff)
parent16846553b8866eab2aa3b128a2a23a221a25f7e3 (diff)
downloadrails-e68bfaf1fe1a7890a67af6f444281185f507cf9e.tar.gz
rails-e68bfaf1fe1a7890a67af6f444281185f507cf9e.tar.bz2
rails-e68bfaf1fe1a7890a67af6f444281185f507cf9e.zip
Merge remote branch 'mainstream/master'
Conflicts: activerecord/lib/active_record/base.rb railties/lib/rails/configuration.rb railties/lib/rails/log_subscriber.rb
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/Rakefile32
-rw-r--r--actionpack/actionpack.gemspec12
-rw-r--r--actionpack/lib/abstract_controller.rb6
-rw-r--r--actionpack/lib/abstract_controller/base.rb18
-rw-r--r--actionpack/lib/abstract_controller/collector.rb2
-rw-r--r--actionpack/lib/abstract_controller/compatibility.rb18
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb8
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb134
-rw-r--r--actionpack/lib/abstract_controller/localized_cache.rb49
-rw-r--r--actionpack/lib/abstract_controller/logger.rb4
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb212
-rw-r--r--actionpack/lib/abstract_controller/view_paths.rb73
-rw-r--r--actionpack/lib/action_controller.rb3
-rw-r--r--actionpack/lib/action_controller/base.rb34
-rw-r--r--actionpack/lib/action_controller/caching.rb37
-rw-r--r--actionpack/lib/action_controller/caching/fragments.rb4
-rw-r--r--actionpack/lib/action_controller/caching/pages.rb48
-rw-r--r--actionpack/lib/action_controller/caching/sweeping.rb4
-rw-r--r--actionpack/lib/action_controller/deprecated.rb2
-rw-r--r--actionpack/lib/action_controller/deprecated/base.rb131
-rw-r--r--actionpack/lib/action_controller/metal.rb43
-rw-r--r--actionpack/lib/action_controller/metal/compatibility.rb98
-rw-r--r--actionpack/lib/action_controller/metal/configuration.rb28
-rw-r--r--actionpack/lib/action_controller/metal/head.rb1
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb4
-rw-r--r--actionpack/lib/action_controller/metal/hide_actions.rb10
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb50
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb21
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb2
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb5
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb1
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb2
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb68
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb45
-rw-r--r--actionpack/lib/action_controller/metal/session_management.rb36
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb67
-rw-r--r--actionpack/lib/action_controller/metal/testing.rb1
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb167
-rw-r--r--actionpack/lib/action_controller/middleware.rb3
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb3
-rw-r--r--actionpack/lib/action_controller/railtie.rb70
-rw-r--r--actionpack/lib/action_controller/railties/log_subscriber.rb (renamed from actionpack/lib/action_controller/railties/subscriber.rb)12
-rw-r--r--actionpack/lib/action_controller/railties/url_helpers.rb14
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb21
-rw-r--r--actionpack/lib/action_controller/test_case.rb31
-rw-r--r--actionpack/lib/action_controller/url_rewriter.rb76
-rw-r--r--actionpack/lib/action_dispatch.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb21
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb65
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb15
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb39
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb49
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb37
-rw-r--r--actionpack/lib/action_dispatch/middleware/callbacks.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb51
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb13
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb8
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb3
-rw-r--r--actionpack/lib/action_dispatch/routing.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/deprecated_mapper.rb40
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb54
-rw-r--r--actionpack/lib/action_dispatch/routing/route.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb358
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb139
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/response.rb23
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb27
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb57
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb2
-rw-r--r--actionpack/lib/action_pack/version.rb7
-rw-r--r--actionpack/lib/action_view.rb15
-rw-r--r--actionpack/lib/action_view/base.rb94
-rw-r--r--actionpack/lib/action_view/helpers.rb1
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb20
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb17
-rw-r--r--actionpack/lib/action_view/helpers/atom_feed_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb14
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb11
-rw-r--r--actionpack/lib/action_view/helpers/deprecated_block_helpers.rb52
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb48
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb7
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb26
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb86
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb28
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb28
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb9
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb23
-rw-r--r--actionpack/lib/action_view/lookup_context.rb154
-rw-r--r--actionpack/lib/action_view/paths.rb85
-rw-r--r--actionpack/lib/action_view/railtie.rb8
-rw-r--r--actionpack/lib/action_view/railties/log_subscriber.rb (renamed from actionpack/lib/action_view/railties/subscriber.rb)2
-rw-r--r--actionpack/lib/action_view/render/layouts.rb65
-rw-r--r--actionpack/lib/action_view/render/partials.rb48
-rw-r--r--actionpack/lib/action_view/render/rendering.rb115
-rw-r--r--actionpack/lib/action_view/template.rb32
-rw-r--r--actionpack/lib/action_view/template/handlers/erb.rb25
-rw-r--r--actionpack/lib/action_view/template/resolver.rb136
-rw-r--r--actionpack/lib/action_view/template/text.rb13
-rw-r--r--actionpack/lib/action_view/test_case.rb9
-rw-r--r--actionpack/test/abstract/abstract_controller_test.rb4
-rw-r--r--actionpack/test/abstract/layouts_test.rb118
-rw-r--r--actionpack/test/abstract/localized_cache_test.rb57
-rw-r--r--actionpack/test/abstract/render_test.rb61
-rw-r--r--actionpack/test/abstract_unit.rb105
-rw-r--r--actionpack/test/activerecord/controller_runtime_test.rb22
-rw-r--r--actionpack/test/activerecord/polymorphic_routes_test.rb8
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb24
-rw-r--r--actionpack/test/controller/assert_select_test.rb13
-rw-r--r--actionpack/test/controller/base_test.rb59
-rw-r--r--actionpack/test/controller/caching_test.rb35
-rw-r--r--actionpack/test/controller/content_type_test.rb12
-rw-r--r--actionpack/test/controller/cookie_test.rb2
-rw-r--r--actionpack/test/controller/http_digest_authentication_test.rb18
-rw-r--r--actionpack/test/controller/integration_test.rb48
-rw-r--r--actionpack/test/controller/log_subscriber_test.rb (renamed from actionpack/test/controller/subscriber_test.rb)28
-rw-r--r--actionpack/test/controller/mime_responds_test.rb8
-rw-r--r--actionpack/test/controller/new_base/render_rjs_test.rb2
-rw-r--r--actionpack/test/controller/record_identifier_test.rb1
-rw-r--r--actionpack/test/controller/redirect_test.rb18
-rw-r--r--actionpack/test/controller/render_json_test.rb10
-rw-r--r--actionpack/test/controller/render_test.rb24
-rw-r--r--actionpack/test/controller/render_xml_test.rb3
-rw-r--r--actionpack/test/controller/rescue_test.rb4
-rw-r--r--actionpack/test/controller/resources_test.rb27
-rw-r--r--actionpack/test/controller/routing_test.rb38
-rw-r--r--actionpack/test/controller/send_file_test.rb62
-rw-r--r--actionpack/test/controller/test_test.rb16
-rw-r--r--actionpack/test/controller/url_for_test.rb26
-rw-r--r--actionpack/test/controller/url_rewriter_test.rb69
-rw-r--r--actionpack/test/controller/view_paths_test.rb3
-rw-r--r--actionpack/test/controller/webservice_test.rb2
-rw-r--r--actionpack/test/dispatch/mount_test.rb36
-rw-r--r--actionpack/test/dispatch/request_test.rb159
-rw-r--r--actionpack/test/dispatch/response_test.rb24
-rw-r--r--actionpack/test/dispatch/routing_test.rb35
-rw-r--r--actionpack/test/dispatch/url_generation_test.rb38
-rw-r--r--actionpack/test/fixtures/hello.html1
-rw-r--r--actionpack/test/fixtures/test/layout_render_file.erb2
-rw-r--r--actionpack/test/lib/controller/fake_models.rb33
-rw-r--r--actionpack/test/lib/fixture_template.rb17
-rw-r--r--actionpack/test/template/active_model_helper_test.rb4
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb96
-rw-r--r--actionpack/test/template/atom_feed_helper_test.rb8
-rw-r--r--actionpack/test/template/compiled_templates_test.rb5
-rw-r--r--actionpack/test/template/date_helper_test.rb110
-rw-r--r--actionpack/test/template/erb/tag_helper_test.rb82
-rw-r--r--actionpack/test/template/form_helper_test.rb157
-rw-r--r--actionpack/test/template/form_options_helper_test.rb22
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb43
-rw-r--r--actionpack/test/template/javascript_helper_test.rb17
-rw-r--r--actionpack/test/template/log_subscriber_test.rb (renamed from actionpack/test/template/subscriber_test.rb)14
-rw-r--r--actionpack/test/template/lookup_context_test.rb165
-rw-r--r--actionpack/test/template/prototype_helper_test.rb8
-rw-r--r--actionpack/test/template/record_tag_helper_test.rb1
-rw-r--r--actionpack/test/template/render_test.rb23
-rw-r--r--actionpack/test/template/tag_helper_test.rb18
-rw-r--r--actionpack/test/template/test_case_test.rb35
-rw-r--r--actionpack/test/template/translation_helper_test.rb5
-rw-r--r--actionpack/test/template/url_helper_test.rb96
160 files changed, 3245 insertions, 2848 deletions
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index c45f88ed04..b9ace8658a 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -4,17 +4,6 @@ require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/packagetask'
require 'rake/gempackagetask'
-require File.join(File.dirname(__FILE__), 'lib', 'action_pack', 'version')
-
-PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
-PKG_NAME = 'actionpack'
-PKG_VERSION = ActionPack::VERSION::STRING + PKG_BUILD
-PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
-
-RELEASE_NAME = "REL #{PKG_VERSION}"
-
-RUBY_FORGE_PROJECT = "actionpack"
-RUBY_FORGE_USER = "webster132"
desc "Default Task"
task :default => :test
@@ -115,26 +104,7 @@ task :update_js => [ :update_scriptaculous ]
# Publishing ------------------------------------------------------
desc "Publish the API documentation"
-task :pgem => [:package] do
- require 'rake/contrib/sshpublisher'
- Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
- `ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
-end
-
-desc "Publish the API documentation"
task :pdoc => [:rdoc] do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload
-end
-
-desc "Publish the release files to RubyForge."
-task :release => [ :package ] do
- require 'rubyforge'
- require 'rake/contrib/rubyforgepublisher'
-
- packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
-
- rubyforge = RubyForge.new
- rubyforge.login
- rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
-end
+end \ No newline at end of file
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 8a7169bfa1..ed5b7e1e93 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -1,9 +1,11 @@
+version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip
+
Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = 'actionpack'
- s.version = '3.0.0.beta1'
+ s.version = version
s.summary = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).'
- s.description = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).'
+ s.description = 'Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server.'
s.required_ruby_version = '>= 1.8.7'
s.author = 'David Heinemeier Hansson'
@@ -17,10 +19,10 @@ Gem::Specification.new do |s|
s.has_rdoc = true
- s.add_dependency('activesupport', '= 3.0.0.beta1')
- s.add_dependency('activemodel', '= 3.0.0.beta1')
+ s.add_dependency('activesupport', version)
+ s.add_dependency('activemodel', version)
s.add_dependency('rack', '~> 1.1.0')
s.add_dependency('rack-test', '~> 0.5.0')
- s.add_dependency('rack-mount', '~> 0.4.7')
+ s.add_dependency('rack-mount', '~> 0.6.0')
s.add_dependency('erubis', '~> 2.6.5')
end
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 1e15ab090c..2da4dc052c 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -3,8 +3,11 @@ $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.inc
require 'active_support/ruby/shim'
require 'active_support/dependencies/autoload'
+require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
+require 'active_support/core_ext/module/anonymous'
+require 'active_support/i18n'
module AbstractController
extend ActiveSupport::Autoload
@@ -12,11 +15,10 @@ module AbstractController
autoload :Base
autoload :Callbacks
autoload :Collector
- autoload :Compatibility
autoload :Helpers
autoload :Layouts
- autoload :LocalizedCache
autoload :Logger
autoload :Rendering
autoload :Translation
+ autoload :ViewPaths
end
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index 3119ee498b..c12b584144 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -1,3 +1,5 @@
+require 'active_support/ordered_options'
+
module AbstractController
class Error < StandardError; end
class ActionNotFound < StandardError; end
@@ -5,7 +7,6 @@ module AbstractController
class Base
attr_internal :response_body
attr_internal :action_name
- attr_internal :formats
class << self
attr_reader :abstract
@@ -28,6 +29,14 @@ module AbstractController
@descendants ||= []
end
+ def config
+ @config ||= ActiveSupport::InheritableOptions.new(superclass < Base ? superclass.config : {})
+ end
+
+ def configure
+ yield config
+ end
+
# A list of all internal methods for a controller. This finds the first
# abstract superclass of a controller, and gets a list of all public
# instance methods on that abstract class. Public instance methods of
@@ -84,15 +93,14 @@ module AbstractController
# ==== Returns
# String
def controller_path
- @controller_path ||= name && name.sub(/Controller$/, '').underscore
+ @controller_path ||= name.sub(/Controller$/, '').underscore unless anonymous?
end
end
abstract!
- # Initialize controller with nil formats.
- def initialize #:nodoc:
- @_formats = nil
+ def config
+ @config ||= ActiveSupport::InheritableOptions.new(self.class.config)
end
# Calls the action going through the entire action dispatch stack.
diff --git a/actionpack/lib/abstract_controller/collector.rb b/actionpack/lib/abstract_controller/collector.rb
index d429333661..81fb514770 100644
--- a/actionpack/lib/abstract_controller/collector.rb
+++ b/actionpack/lib/abstract_controller/collector.rb
@@ -1,3 +1,5 @@
+require "action_dispatch/http/mime_type"
+
module AbstractController
module Collector
def self.generate_method_for_mime(mime)
diff --git a/actionpack/lib/abstract_controller/compatibility.rb b/actionpack/lib/abstract_controller/compatibility.rb
deleted file mode 100644
index 7fb93a0eb5..0000000000
--- a/actionpack/lib/abstract_controller/compatibility.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module AbstractController
- module Compatibility
- extend ActiveSupport::Concern
-
- def _find_layout(name, details)
- details[:prefix] = nil if name =~ /\blayouts/
- super
- end
-
- # Move this into a "don't run in production" module
- def _default_layout(details, require_layout = false)
- super
- rescue ActionView::MissingTemplate
- _find_layout(_layout({}), {})
- nil
- end
- end
-end
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index 578b884a4d..f875213afb 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -1,6 +1,4 @@
require 'active_support/dependencies'
-require 'active_support/core_ext/class/attribute'
-require 'active_support/core_ext/module/delegation'
module AbstractController
module Helpers
@@ -27,7 +25,7 @@ module AbstractController
def inherited(klass)
helpers = _helpers
klass._helpers = Module.new { include helpers }
- klass.class_eval { default_helper_module! unless name.blank? }
+ klass.class_eval { default_helper_module! unless anonymous? }
super
end
@@ -99,7 +97,7 @@ module AbstractController
def helper(*args, &block)
self._helper_serial = AbstractController::Helpers.next_serial + 1
- _modules_for_helpers(args).each do |mod|
+ modules_for_helpers(args).each do |mod|
add_template_helper(mod)
end
@@ -134,7 +132,7 @@ module AbstractController
# ==== Returns
# Array[Module]:: A normalized list of modules for the list of
# helpers provided.
- def _modules_for_helpers(args)
+ def modules_for_helpers(args)
args.flatten.map! do |arg|
case arg
when String, Symbol
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index 0d214396aa..2f9616124a 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -1,6 +1,3 @@
-require 'active_support/core_ext/class/attribute'
-require 'active_support/core_ext/module/delegation'
-
module AbstractController
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
# repeated setups. The inclusion pattern has pages that look like this:
@@ -173,27 +170,7 @@ module AbstractController
module ClassMethods
def inherited(klass)
super
- klass.class_eval do
- _write_layout_method
- @found_layouts = {}
- end
- end
-
- def clear_template_caches!
- @found_layouts.clear if defined? @found_layouts
- super
- end
-
- def cache_layout(details)
- layout = @found_layouts
- key = Thread.current[:format_locale_key]
-
- # Cache nil
- if layout.key?(key)
- return layout[key]
- else
- layout[key] = yield
- end
+ klass._write_layout_method
end
# This module is mixed in if layout conditions are provided. This means
@@ -262,10 +239,10 @@ module AbstractController
def _write_layout_method
case defined?(@_layout) ? @_layout : nil
when String
- self.class_eval %{def _layout(details) #{@_layout.inspect} end}
+ self.class_eval %{def _layout; #{@_layout.inspect} end}
when Symbol
self.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
- def _layout(details)
+ def _layout
#{@_layout}.tap do |layout|
unless layout.is_a?(String) || !layout
raise ArgumentError, "Your layout method :#{@_layout} returned \#{layout}. It " \
@@ -276,21 +253,21 @@ module AbstractController
ruby_eval
when Proc
define_method :_layout_from_proc, &@_layout
- self.class_eval %{def _layout(details) _layout_from_proc(self) end}
+ self.class_eval %{def _layout; _layout_from_proc(self) end}
when false
- self.class_eval %{def _layout(details) end}
+ self.class_eval %{def _layout; end}
when true
raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
when nil
if name
+ _prefix = "layouts" unless _implied_layout_name =~ /\blayouts/
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def _layout(details)
- self.class.cache_layout(details) do
- if template_exists?("#{_implied_layout_name}", details, :_prefix => "layouts")
- "#{_implied_layout_name}"
- else
- super
- end
+ def _layout
+ if template_exists?("#{_implied_layout_name}", #{_prefix.inspect})
+ "#{_implied_layout_name}"
+ else
+ super
end
end
RUBY
@@ -300,42 +277,20 @@ module AbstractController
end
end
- def render_to_body(options = {})
- # In the case of a partial with a layout, handle the layout
- # here, and make sure the view does not try to handle it
- layout = options.delete(:layout) if options.key?(:partial)
-
- response = super
+ def _normalize_options(options)
+ super
- # This is a little bit messy. We need to explicitly handle partial
- # layouts here since the core lookup logic is in the view, but
- # we need to determine the layout based on the controller
- #
- # TODO: An easier way to handle this would probably be to override
- # render_template
- if layout
- layout = _layout_for_option(layout, options[:_template].details)
- response = layout.render(view_context, options[:locals] || {}) { response }
+ if _include_layout?(options)
+ layout = options.key?(:layout) ? options.delete(:layout) : :default
+ value = _layout_for_option(layout)
+ options[:layout] = (value =~ /\blayouts/ ? value : "layouts/#{value}") if value
end
-
- response
end
private
# This will be overwritten by _write_layout_method
- def _layout(details) end
-
- # Determine the layout for a given name and details.
- #
- # ==== Parameters
- # name<String>:: The name of the template
- # details<Hash{Symbol => Object}>:: A list of details to restrict
- # the lookup to. By default, layout lookup is limited to the
- # formats specified for the current request.
- def _layout_for_name(name, details)
- name && _find_layout(name, details)
- end
+ def _layout; end
# Determine the layout for a given name and details, taking into account
# the name type.
@@ -345,11 +300,11 @@ module AbstractController
# details<Hash{Symbol => Object}>:: A list of details to restrict
# the lookup to. By default, layout lookup is limited to the
# formats specified for the current request.
- def _layout_for_option(name, details)
+ def _layout_for_option(name)
case name
- when String then _layout_for_name(name, details)
- when true then _default_layout(details, true)
- when :default then _default_layout(details, false)
+ when String then name
+ when true then _default_layout(true)
+ when :default then _default_layout(false)
when false, nil then nil
else
raise ArgumentError,
@@ -357,29 +312,6 @@ module AbstractController
end
end
- def _determine_template(options)
- super
-
- return unless (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout)
- layout = options.key?(:layout) ? options[:layout] : :default
- options[:_layout] = _layout_for_option(layout, options[:_template].details)
- end
-
- # Take in the name and details and find a Template.
- #
- # ==== Parameters
- # name<String>:: The name of the template to retrieve
- # details<Hash>:: A list of details to restrict the search by. This
- # might include details like the format or locale of the template.
- #
- # ==== Returns
- # Template:: A template object matching the name and details
- def _find_layout(name, details)
- # TODO: Make prefix actually part of details in ViewPath#find_by_parts
- prefix = details.key?(:prefix) ? details.delete(:prefix) : "layouts"
- find_template(name, details, :_prefix => prefix)
- end
-
# Returns the default layout for this controller and a given set of details.
# Optionally raises an exception if the layout could not be found.
#
@@ -392,18 +324,24 @@ module AbstractController
#
# ==== Returns
# Template:: The template object for the default layout (or nil)
- def _default_layout(details, require_layout = false)
- if require_layout && _action_has_layout? && !_layout(details)
- raise ArgumentError,
- "There was no default layout for #{self.class} in #{view_paths.inspect}"
- end
-
+ def _default_layout(require_layout = false)
begin
- _layout_for_name(_layout(details), details) if _action_has_layout?
+ layout_name = _layout if _action_has_layout?
rescue NameError => e
raise NoMethodError,
"You specified #{@_layout.inspect} as the layout, but no such method was found"
end
+
+ if require_layout && _action_has_layout? && !layout_name
+ raise ArgumentError,
+ "There was no default layout for #{self.class} in #{view_paths.inspect}"
+ end
+
+ layout_name
+ end
+
+ def _include_layout?(options)
+ (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout)
end
def _action_has_layout?
diff --git a/actionpack/lib/abstract_controller/localized_cache.rb b/actionpack/lib/abstract_controller/localized_cache.rb
deleted file mode 100644
index 5e3efa002c..0000000000
--- a/actionpack/lib/abstract_controller/localized_cache.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-module AbstractController
- class HashKey
- @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|sh,sk| sh[sk] = {} } }
-
- def self.get(klass, formats, locale)
- @hash_keys[klass][formats][locale] ||= new(klass, formats, locale)
- end
-
- attr_accessor :hash
- def initialize(klass, formats, locale)
- @formats, @locale = formats, locale
- @hash = [formats, locale].hash
- end
-
- alias_method :eql?, :equal?
-
- def inspect
- "#<HashKey -- formats: #{@formats.inspect} locale: #{@locale.inspect}>"
- end
- end
-
- module LocalizedCache
- extend ActiveSupport::Concern
-
- module ClassMethods
- def clear_template_caches!
- ActionView::Partials::PartialRenderer::TEMPLATES.clear
- template_cache.clear
- super
- end
-
- def template_cache
- @template_cache ||= Hash.new {|h,k| h[k] = {} }
- end
- end
-
- def render(*args)
- Thread.current[:format_locale_key] = HashKey.get(self.class, formats, I18n.locale)
- super
- end
-
- private
-
- def with_template_cache(name)
- self.class.template_cache[Thread.current[:format_locale_key]][name] ||= super
- end
-
- end
-end
diff --git a/actionpack/lib/abstract_controller/logger.rb b/actionpack/lib/abstract_controller/logger.rb
index a23a13e1d6..9318f5e369 100644
--- a/actionpack/lib/abstract_controller/logger.rb
+++ b/actionpack/lib/abstract_controller/logger.rb
@@ -1,5 +1,5 @@
-require 'active_support/core_ext/logger'
-require 'active_support/benchmarkable'
+require "active_support/core_ext/logger"
+require "active_support/benchmarkable"
module AbstractController
module Logger
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index 619a49571b..42f4939108 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -1,7 +1,4 @@
require "abstract_controller/base"
-require 'active_support/core_ext/class/attribute'
-require 'active_support/core_ext/module/delegation'
-require 'active_support/core_ext/array/wrap'
module AbstractController
class DoubleRenderError < Error
@@ -12,32 +9,47 @@ module AbstractController
end
end
+ # This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
+ # it will trigger the lookup_context and consequently expire the cache.
+ # TODO Add some deprecation warnings to remove I18n.locale from controllers
+ class I18nProxy < ::I18n::Config #:nodoc:
+ attr_reader :i18n_config, :lookup_context
+
+ def initialize(i18n_config, lookup_context)
+ @i18n_config, @lookup_context = i18n_config, lookup_context
+ end
+
+ def locale
+ @i18n_config.locale
+ end
+
+ def locale=(value)
+ @i18n_config.locale = value
+ @lookup_context.update_details(:locale => @i18n_config.locale)
+ end
+ end
+
module Rendering
extend ActiveSupport::Concern
+ include AbstractController::ViewPaths
- included do
- class_attribute :_view_paths
- delegate :_view_paths, :to => :'self.class'
- self._view_paths = ActionView::PathSet.new
+ # Overwrite process to setup I18n proxy.
+ def process(*) #:nodoc:
+ old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
+ super
+ ensure
+ I18n.config = old_config
end
# An instance of a view class. The default view class is ActionView::Base
#
# The view class must have the following methods:
- # View.for_controller[controller] Create a new ActionView instance for a
- # controller
- # View#render_partial[options]
- # - responsible for setting options[:_template]
- # - Returns String with the rendered partial
- # options<Hash>:: see _render_partial in ActionView::Base
- # View#render_template[template, layout, options, partial]
- # - Returns String with the rendered template
- # template<ActionView::Template>:: The template to render
- # layout<ActionView::Template>:: The layout to render around the template
- # options<Hash>:: See _render_template_with_layout in ActionView::Base
- # partial<Boolean>:: Whether or not the template to render is a partial
+ # View.for_controller[controller]
+ # Create a new ActionView instance for a controller
+ # View#render_template[options]
+ # Returns String with the rendered template
#
- # Override this method in a to change the default behavior.
+ # Override this method in a module to change the default behavior.
def view_context
@_view_context ||= ActionView::Base.for_controller(self)
end
@@ -45,57 +57,29 @@ module AbstractController
# Mostly abstracts the fact that calling render twice is a DoubleRenderError.
# Delegates render_to_body and sticks the result in self.response_body.
def render(*args, &block)
- options = _normalize_options(*args, &block)
+ options = _normalize_args(*args, &block)
+ _normalize_options(options)
self.response_body = render_to_body(options)
end
# Raw rendering of a template to a Rack-compatible body.
- #
- # ==== Options
- # _partial_object<Object>:: The object that is being rendered. If this
- # exists, we are in the special case of rendering an object as a partial.
- #
# :api: plugin
def render_to_body(options = {})
- # TODO: Refactor so we can just use the normal template logic for this
- if options.key?(:partial)
- _render_partial(options)
- else
- _determine_template(options)
- _render_template(options)
- end
+ _process_options(options)
+ _render_template(options)
end
# Raw rendering of a template to a string. Just convert the results of
# render_to_body into a String.
- #
# :api: plugin
- def render_to_string(*args)
- options = _normalize_options(*args)
+ def render_to_string(options={})
+ _normalize_options(options)
AbstractController::Rendering.body_to_s(render_to_body(options))
end
- # Renders the template from an object.
- #
- # ==== Options
- # _template<ActionView::Template>:: The template to render
- # _layout<ActionView::Template>:: The layout to wrap the template in (optional)
+ # Find and renders a template based on the options given.
def _render_template(options)
- view_context.render_template(options)
- end
-
- # Renders the given partial.
- #
- # ==== Options
- # partial<String|Object>:: The partial name or the object to be rendered
- def _render_partial(options)
- view_context.render_partial(options)
- end
-
- # The list of view paths for this controller. See ActionView::ViewPathSet for
- # more details about writing custom view paths.
- def view_paths
- _view_paths
+ view_context.render_template(options) { |template| _with_template_hook(template) }
end
# The prefix used in render "foo" shortcuts.
@@ -117,122 +101,42 @@ module AbstractController
private
- # Normalize options, by converting render "foo" to render :template => "prefix/foo"
- # and render "/foo" to render :file => "/foo".
- def _normalize_options(action=nil, options={})
+ # Normalize options by converting render "foo" to render :action => "foo" and
+ # render "foo/bar" to render :file => "foo/bar".
+ def _normalize_args(action=nil, options={})
case action
+ when NilClass
when Hash
options, action = action, nil
when String, Symbol
action = action.to_s
- case action.index("/")
- when NilClass
- options[:_prefix] = _prefix
- options[:_template_name] = action
- when 0
- options[:file] = action
- else
- options[:template] = action
- end
+ key = action.include?(?/) ? :file : :action
+ options[key] = action
+ else
+ options.merge!(:partial => action)
end
options
end
- # Take in a set of options and determine the template to render
- #
- # ==== Options
- # _template<ActionView::Template>:: If this is provided, the search is over
- # _template_name<#to_s>:: The name of the template to look up. Otherwise,
- # use the current action name.
- # _prefix<String>:: The prefix to look inside of. In a file system, this corresponds
- # to a directory.
- # _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial
- def _determine_template(options)
- if options.key?(:text)
- options[:_template] = ActionView::Template::Text.new(options[:text], format_for_text)
- elsif options.key?(:inline)
- handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
- template = ActionView::Template.new(options[:inline], "inline template", handler, {})
- options[:_template] = template
- elsif options.key?(:template)
- options[:_template_name] = options[:template]
- elsif options.key?(:file)
- options[:_template_name] = options[:file]
+ def _normalize_options(options)
+ if options[:partial] == true
+ options[:partial] = action_name
end
- name = (options[:_template_name] || options[:action] || action_name).to_s
- options[:_prefix] ||= _prefix if (options.keys & [:partial, :file, :template]).empty?
-
- details = _normalize_details(options)
- options[:_template] ||= with_template_cache(name) do
- find_template(name, details, options)
+ if (options.keys & [:partial, :file, :template]).empty?
+ options[:prefix] ||= _prefix
end
- end
-
- def _normalize_details(options)
- details = { :formats => formats }
- details[:formats] = Array(options[:format]) if options[:format]
- details[:locale] = Array(options[:locale]) if options[:locale]
- details
- end
- def find_template(name, details, options)
- view_paths.find(name, details, options[:_prefix], options[:_partial])
- end
-
- def template_exists?(name, details, options)
- view_paths.exists?(name, details, options[:_prefix], options[:_partial])
- end
-
- def with_template_cache(name)
- yield
+ options[:template] ||= (options[:action] || action_name).to_s
+ options
end
- def format_for_text
- Mime[:text]
+ def _process_options(options)
end
- module ClassMethods
- def clear_template_caches!
- end
-
- # Append a path to the list of view paths for this controller.
- #
- # ==== Parameters
- # path<String, ViewPath>:: If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
- # (see ActionView::ViewPathSet for more information)
- def append_view_path(path)
- self.view_paths = view_paths.dup + Array.wrap(path)
- end
-
- # Prepend a path to the list of view paths for this controller.
- #
- # ==== Parameters
- # path<String, ViewPath>:: If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
- # (see ActionView::ViewPathSet for more information)
- def prepend_view_path(path)
- clear_template_caches!
- self.view_paths = Array.wrap(path) + view_paths.dup
- end
-
- # A list of all of the default view paths for this controller.
- def view_paths
- _view_paths
- end
-
- # Set the view paths.
- #
- # ==== Parameters
- # paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
- # otherwise, process the parameter into a ViewPathSet.
- def view_paths=(paths)
- clear_template_caches!
- self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
- _view_paths.freeze
- end
+ def _with_template_hook(template)
+ self.formats = template.formats
end
end
end
diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb
new file mode 100644
index 0000000000..c2a9f6336d
--- /dev/null
+++ b/actionpack/lib/abstract_controller/view_paths.rb
@@ -0,0 +1,73 @@
+module AbstractController
+ module ViewPaths
+ extend ActiveSupport::Concern
+
+ included do
+ class_attribute :_view_paths
+ self._view_paths = ActionView::PathSet.new
+ end
+
+ delegate :template_exists?, :view_paths, :formats, :formats=,
+ :locale, :locale=, :to => :lookup_context
+
+ # LookupContext is the object responsible to hold all information required to lookup
+ # templates, i.e. view paths and details. Check ActionView::LookupContext for more
+ # information.
+ def lookup_context
+ @lookup_context ||= ActionView::LookupContext.new(self.class._view_paths, details_for_lookup)
+ end
+
+ def details_for_lookup
+ { }
+ end
+
+ def append_view_path(path)
+ lookup_context.view_paths.push(*path)
+ end
+
+ def prepend_view_path(path)
+ lookup_context.view_paths.unshift(*path)
+ end
+
+ def template_exists?(*args)
+ lookup_context.exists?(*args)
+ end
+
+ module ClassMethods
+ # Append a path to the list of view paths for this controller.
+ #
+ # ==== Parameters
+ # path<String, ViewPath>:: If a String is provided, it gets converted into
+ # the default view path. You may also provide a custom view path
+ # (see ActionView::ViewPathSet for more information)
+ def append_view_path(path)
+ self.view_paths = view_paths.dup + Array(path)
+ end
+
+ # Prepend a path to the list of view paths for this controller.
+ #
+ # ==== Parameters
+ # path<String, ViewPath>:: If a String is provided, it gets converted into
+ # the default view path. You may also provide a custom view path
+ # (see ActionView::ViewPathSet for more information)
+ def prepend_view_path(path)
+ self.view_paths = Array(path) + view_paths.dup
+ end
+
+ # A list of all of the default view paths for this controller.
+ def view_paths
+ _view_paths
+ end
+
+ # Set the view paths.
+ #
+ # ==== Parameters
+ # paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
+ # otherwise, process the parameter into a ViewPathSet.
+ def view_paths=(paths)
+ self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
+ self._view_paths.freeze
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 759e52b135..536154fc6b 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -13,13 +13,13 @@ module ActionController
autoload_under "metal" do
autoload :Compatibility
autoload :ConditionalGet
- autoload :Configuration
autoload :Cookies
autoload :Flash
autoload :Head
autoload :Helpers
autoload :HideActions
autoload :HttpAuthentication
+ autoload :ImplicitRender
autoload :Instrumentation
autoload :MimeResponds
autoload :RackDelegation
@@ -46,7 +46,6 @@ module ActionController
eager_autoload do
autoload :RecordIdentifier
- autoload :UrlRewriter
# TODO: Don't autoload exceptions, setup explicit
# requires for files that need them
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 10244f8216..fcd3cb9bd3 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -15,7 +15,6 @@ module ActionController
include ActionController::Renderers::All
include ActionController::ConditionalGet
include ActionController::RackDelegation
- include ActionController::Configuration
# Legacy modules
include SessionManagement
@@ -30,35 +29,13 @@ module ActionController
include ActionController::Verification
include ActionController::RequestForgeryProtection
include ActionController::Streaming
+ include ActionController::RecordIdentifier
include ActionController::HttpAuthentication::Basic::ControllerMethods
include ActionController::HttpAuthentication::Digest::ControllerMethods
# Add instrumentations hooks at the bottom, to ensure they instrument
# all the methods properly.
include ActionController::Instrumentation
-
- # TODO: Extract into its own module
- # This should be moved together with other normalizing behavior
- module ImplicitRender
- def send_action(*)
- ret = super
- default_render unless response_body
- ret
- end
-
- def default_render
- render
- end
-
- def method_for_action(action_name)
- super || begin
- if template_exists?(action_name.to_s, {:formats => formats}, :_prefix => controller_path)
- "default_render"
- end
- end
- end
- end
-
include ImplicitRender
include ActionController::Rescue
@@ -82,12 +59,9 @@ module ActionController
filter
end
- protected
+ ActionController.run_base_hooks(self)
- # Overwrite url rewriter to use request.
- def _url_rewriter
- return ActionController::UrlRewriter unless request
- @_url_rewriter ||= ActionController::UrlRewriter.new(request, params)
- end
end
end
+
+require "action_controller/deprecated/base"
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index d784138ebe..b3fa129929 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -40,28 +40,34 @@ module ActionController #:nodoc:
autoload :Sweeping, 'action_controller/caching/sweeping'
end
- 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)
+ module ConfigMethods
+ def cache_store
+ config.cache_store
end
- include Pages, Actions, Fragments
- include Sweeping if defined?(ActiveRecord)
+ def cache_store=(store)
+ config.cache_store = ActiveSupport::Cache.lookup_store(store)
+ end
- @@perform_caching = true
- cattr_accessor :perform_caching
- end
+ private
- module ClassMethods
def cache_configured?
perform_caching && cache_store
end
end
+ include ConfigMethods
+ include Pages, Actions, Fragments
+ include Sweeping if defined?(ActiveRecord)
+
+ included do
+ extend ConfigMethods
+
+ @@perform_caching = true
+ cattr_accessor :perform_caching
+ end
+
+
def caching_allowed?
request.get? && response.status == 200
end
@@ -75,10 +81,5 @@ module ActionController #:nodoc:
yield
end
end
-
- private
- def cache_configured?
- self.class.cache_configured?
- end
end
end
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index 00a7f034d3..bb5ff95a67 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -41,7 +41,9 @@ module ActionController #:nodoc:
else
pos = buffer.length
block.call
- write_fragment(name, buffer[pos..-1], options)
+ content = buffer[pos..-1]
+ content = content.as_str if content.respond_to?(:as_str)
+ write_fragment(name, content, options)
end
else
block.call
diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb
index 5797eeebd6..fe95f0e0d7 100644
--- a/actionpack/lib/action_controller/caching/pages.rb
+++ b/actionpack/lib/action_controller/caching/pages.rb
@@ -1,5 +1,6 @@
require 'fileutils'
require 'uri'
+require 'active_support/core_ext/class/attribute_accessors'
module ActionController #:nodoc:
module Caching
@@ -34,27 +35,26 @@ module ActionController #:nodoc:
# Additionally, you can expire caches using Sweepers that act on changes in the model to determine when a cache is supposed to be
# expired.
module Pages
- def self.included(base) #:nodoc:
- base.extend(ClassMethods)
- base.class_eval do
- @@page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
- ##
- # :singleton-method:
- # The cache directory should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>.
- # For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>RAILS_ROOT + "/public"</tt>). Changing
- # this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
- # web server to look in the new location for cached files.
- cattr_accessor :page_cache_directory
-
- @@page_cache_extension = '.html'
- ##
- # :singleton-method:
- # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in
- # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
- # If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
- # extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
- cattr_accessor :page_cache_extension
- end
+ extend ActiveSupport::Concern
+
+ included do
+ @@page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
+ ##
+ # :singleton-method:
+ # The cache directory should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>.
+ # For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>RAILS_ROOT + "/public"</tt>). Changing
+ # this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
+ # web server to look in the new location for cached files.
+ cattr_accessor :page_cache_directory
+
+ @@page_cache_extension = '.html'
+ ##
+ # :singleton-method:
+ # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in
+ # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
+ # If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
+ # extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
+ cattr_accessor :page_cache_extension
end
module ClassMethods
@@ -121,10 +121,10 @@ module ActionController #:nodoc:
if options.is_a?(Hash)
if options[:action].is_a?(Array)
options[:action].dup.each do |action|
- self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :action => action)))
+ self.class.expire_page(url_for(options.merge(:only_path => true, :action => action)))
end
else
- self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true)))
+ self.class.expire_page(url_for(options.merge(:only_path => true)))
end
else
self.class.expire_page(options)
@@ -139,7 +139,7 @@ module ActionController #:nodoc:
path = case options
when Hash
- url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format]))
+ url_for(options.merge(:only_path => true, :format => params[:format]))
when String
options
else
diff --git a/actionpack/lib/action_controller/caching/sweeping.rb b/actionpack/lib/action_controller/caching/sweeping.rb
index 871f41bfdd..cf16417e84 100644
--- a/actionpack/lib/action_controller/caching/sweeping.rb
+++ b/actionpack/lib/action_controller/caching/sweeping.rb
@@ -30,9 +30,7 @@ module ActionController #:nodoc:
# cache_sweeper OpenBar::Sweeper, :only => [ :edit, :destroy, :share ]
# end
module Sweeping
- def self.included(base) #:nodoc:
- base.extend(ClassMethods)
- end
+ extend ActiveSupport::Concern
module ClassMethods #:nodoc:
def cache_sweeper(*sweepers)
diff --git a/actionpack/lib/action_controller/deprecated.rb b/actionpack/lib/action_controller/deprecated.rb
index a4eef07841..9f2de57033 100644
--- a/actionpack/lib/action_controller/deprecated.rb
+++ b/actionpack/lib/action_controller/deprecated.rb
@@ -1,5 +1,3 @@
ActionController::AbstractRequest = ActionController::Request = ActionDispatch::Request
ActionController::AbstractResponse = ActionController::Response = ActionDispatch::Response
ActionController::Routing = ActionDispatch::Routing
-ActionController::Routing::Routes = ActionDispatch::Routing::RouteSet.new
-ActionController::UrlWriter = ActionController::UrlFor
diff --git a/actionpack/lib/action_controller/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb
new file mode 100644
index 0000000000..1d05b3fbd6
--- /dev/null
+++ b/actionpack/lib/action_controller/deprecated/base.rb
@@ -0,0 +1,131 @@
+module ActionController
+ class Base
+ class << self
+ def deprecated_config_accessor(option, message = nil)
+ deprecated_config_reader(option, message)
+ deprecated_config_writer(option, message)
+ end
+
+ def deprecated_config_reader(option, message = nil)
+ message ||= "Reading #{option} directly from ActionController::Base is deprecated. " \
+ "Please read it from config.#{option}"
+
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{option}
+ ActiveSupport::Deprecation.warn #{message.inspect}, caller
+ config.#{option}
+ end
+ RUBY
+ end
+
+ def deprecated_config_writer(option, message = nil)
+ message ||= "Setting #{option} directly on ActionController::Base is deprecated. " \
+ "Please set it on config.action_controller.#{option}"
+
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{option}=(val)
+ ActiveSupport::Deprecation.warn #{message.inspect}, caller
+ config.#{option} = val
+ end
+ RUBY
+ end
+
+ def consider_all_requests_local
+ ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local is deprecated, " <<
+ "use Rails.application.config.consider_all_requests_local instead", caller
+ Rails.application.config.consider_all_requests_local
+ end
+
+ def consider_all_requests_local=(value)
+ ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local= is deprecated. " <<
+ "Please configure it on your application with config.consider_all_requests_local=", caller
+ Rails.application.config.consider_all_requests_local = value
+ end
+
+ def allow_concurrency
+ ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency is deprecated, " <<
+ "use Rails.application.config.allow_concurrency instead", caller
+ Rails.application.config.allow_concurrency
+ end
+
+ def allow_concurrency=(value)
+ ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency= is deprecated. " <<
+ "Please configure it on your application with config.allow_concurrency=", caller
+ Rails.application.config.allow_concurrency = value
+ end
+
+ def ip_spoofing_check=(value)
+ ActiveSupport::Deprecation.warn "ActionController::Base.ip_spoofing_check= is deprecated. " <<
+ "Please configure it on your application with config.action_dispatch.ip_spoofing_check=", caller
+ Rails.application.config.action_dispatch.ip_spoofing_check = value
+ end
+
+ def ip_spoofing_check
+ ActiveSupport::Deprecation.warn "ActionController::Base.ip_spoofing_check is deprecated. " <<
+ "Configuring ip_spoofing_check on the application configures a middleware.", caller
+ Rails.application.config.action_disaptch.ip_spoofing_check
+ end
+
+ def trusted_proxies=(value)
+ ActiveSupport::Deprecation.warn "ActionController::Base.trusted_proxies= is deprecated. " <<
+ "Please configure it on your application with config.action_dispatch.trusted_proxies=", caller
+ Rails.application.config.action_dispatch.ip_spoofing_check = value
+ end
+
+ def trusted_proxies
+ ActiveSupport::Deprecation.warn "ActionController::Base.trusted_proxies is deprecated. " <<
+ "Configuring trusted_proxies on the application configures a middleware.", caller
+ Rails.application.config.action_dispatch.ip_spoofing_check = value
+ end
+
+ def session(*args)
+ ActiveSupport::Deprecation.warn(
+ "Disabling sessions for a single controller has been deprecated. " +
+ "Sessions are now lazy loaded. So if you don't access them, " +
+ "consider them off. You can still modify the session cookie " +
+ "options with request.session_options.", caller)
+ end
+
+ def session=(value)
+ ActiveSupport::Deprecation.warn "ActionController::Base.session= is deprecated. " <<
+ "Please configure it on your application with config.session_store :cookie_store, :key => '....'", caller
+ if value.delete(:disabled)
+ Rails.application.config.session_store :disabled
+ else
+ store = Rails.application.config.session_store
+ Rails.application.config.session_store store, value
+ end
+ end
+
+ # Controls the resource action separator
+ def resource_action_separator
+ @resource_action_separator ||= "/"
+ end
+
+ def resource_action_separator=(val)
+ ActiveSupport::Deprecation.warn "ActionController::Base.resource_action_separator is deprecated and only " \
+ "works with the deprecated router DSL."
+ @resource_action_separator = val
+ end
+
+ def use_accept_header
+ ActiveSupport::Deprecation.warn "ActionController::Base.use_accept_header doesn't do anything anymore. " \
+ "The accept header is always taken into account."
+ end
+
+ def use_accept_header=(val)
+ use_accept_header
+ end
+ end
+
+ deprecated_config_writer :session_store
+ deprecated_config_writer :session_options
+ deprecated_config_accessor :relative_url_root, "relative_url_root is ineffective. Please stop using it"
+ deprecated_config_accessor :assets_dir
+ deprecated_config_accessor :javascripts_dir
+ deprecated_config_accessor :stylesheets_dir
+
+ delegate :consider_all_requests_local, :consider_all_requests_local=,
+ :allow_concurrency, :allow_concurrency=, :to => :"self.class"
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 2b35e111ec..eebd2c943a 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -34,7 +34,8 @@ module ActionController
# and response object available. You might wish to control the
# environment and response manually for performance reasons.
- attr_internal :status, :headers, :content_type, :response
+ attr_internal :status, :headers, :content_type, :response, :request
+ delegate :session, :to => "@_request"
def initialize(*)
@_headers = {}
@@ -49,6 +50,14 @@ module ActionController
headers["Content-Type"] = type.to_s
end
+ def content_type
+ headers["Content-Type"]
+ end
+
+ def location
+ headers["Location"]
+ end
+
def location=(url)
headers["Location"] = url
end
@@ -58,8 +67,9 @@ module ActionController
end
# :api: private
- def dispatch(name, env)
- @_env = env
+ def dispatch(name, request)
+ @_request = request
+ @_env = request.env
@_env['action_controller.instance'] = self
process(name)
to_a
@@ -70,31 +80,12 @@ module ActionController
response ? response.to_a : [status, headers, response_body]
end
- class ActionEndpoint
- @@endpoints = Hash.new {|h,k| h[k] = Hash.new {|sh,sk| sh[sk] = {} } }
-
- def self.for(controller, action, stack)
- @@endpoints[controller][action][stack] ||= begin
- endpoint = new(controller, action)
- stack.build(endpoint)
- end
- end
-
- def initialize(controller, action)
- @controller, @action = controller, action
- @_formats = [Mime::HTML]
- end
-
- def call(env)
- @controller.new.dispatch(@action, env)
- end
- end
-
class_attribute :middleware_stack
self.middleware_stack = ActionDispatch::MiddlewareStack.new
def self.inherited(base)
self.middleware_stack = base.middleware_stack.dup
+ super
end
def self.use(*args)
@@ -118,8 +109,10 @@ module ActionController
#
# ==== Returns
# Proc:: A rack application
- def self.action(name)
- ActionEndpoint.for(self, name, middleware_stack)
+ def self.action(name, klass = ActionDispatch::Request)
+ middleware_stack.build do |env|
+ new.dispatch(name, klass.new(env))
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb
index a1cfa32d4d..ab8d87b2c4 100644
--- a/actionpack/lib/action_controller/metal/compatibility.rb
+++ b/actionpack/lib/action_controller/metal/compatibility.rb
@@ -2,26 +2,23 @@ module ActionController
module Compatibility
extend ActiveSupport::Concern
- include AbstractController::Compatibility
-
class ::ActionController::ActionControllerError < StandardError #:nodoc:
end
+ module ClassMethods
+ end
+
# Temporary hax
included do
::ActionController::UnknownAction = ::AbstractController::ActionNotFound
::ActionController::DoubleRenderError = ::AbstractController::DoubleRenderError
- cattr_accessor :session_options
- self.session_options = {}
-
- cattr_accessor :relative_url_root
- self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT']
+ # ROUTES TODO: This should be handled by a middleware and route generation
+ # should be able to handle SCRIPT_NAME
+ self.config.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT']
class << self
delegate :default_charset=, :to => "ActionDispatch::Response"
- delegate :resources_path_names, :to => "ActionController::Routing::Routes"
- delegate :resources_path_names=, :to => "ActionController::Routing::Routes"
end
# cattr_reader :protected_instance_variables
@@ -32,31 +29,17 @@ module ActionController
@before_filter_chain_aborted @_headers @_params
@_response)
- # Controls the resource action separator
- cattr_accessor :resource_action_separator
- self.resource_action_separator = "/"
-
- cattr_accessor :use_accept_header
- self.use_accept_header = true
+ def rescue_action(env)
+ raise env["action_dispatch.rescue.exception"]
+ end
self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
-
- # 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
-
- cattr_accessor :ip_spoofing_check
- self.ip_spoofing_check = true
-
- cattr_accessor :trusted_proxies
end
# For old tests
def initialize_template_class(*) end
def assign_shortcuts(*) end
- # TODO: Remove this after we flip
def template
@template ||= view_context
end
@@ -66,52 +49,20 @@ module ActionController
super
end
- module ClassMethods
- def consider_all_requests_local
- ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local is deprecated, " <<
- "use Rails.application.config.consider_all_requests_local instead"
- Rails.application.config.consider_all_requests_local
- end
-
- def consider_all_requests_local=(value)
- ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local= is no longer effective. " <<
- "Please configure it on your application with config.consider_all_requests_local="
- Rails.application.config.consider_all_requests_local = value
- end
-
- def allow_concurrency
- ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency is deprecated, " <<
- "use Rails.application.config.allow_concurrency instead"
- Rails.application.config.allow_concurrency
- end
-
- def allow_concurrency=(value)
- ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency= is no longer effective. " <<
- "Please configure it on your application with config.allow_concurrency="
- Rails.application.config.allow_concurrency = value
- end
-
- def rescue_action(env)
- raise env["action_dispatch.rescue.exception"]
- end
-
- # Defines the storage option for cached fragments
- def cache_store=(store_option)
- @@cache_store = ActiveSupport::Cache.lookup_store(store_option)
- end
- end
-
- delegate :consider_all_requests_local, :consider_all_requests_local=,
- :allow_concurrency, :allow_concurrency=, :to => :"self.class"
-
- def render_to_body(options)
- if options.is_a?(Hash) && options.key?(:template)
- options[:template].sub!(/^\//, '')
+ def _normalize_options(options)
+ if options[:action] && options[:action].to_s.include?(?/)
+ ActiveSupport::Deprecation.warn "Giving a path to render :action is deprecated. " <<
+ "Please use render :template instead", caller
+ options[:template] = options.delete(:action)
end
options[:text] = nil if options.delete(:nothing) == true
options[:text] = " " if options.key?(:text) && options[:text].nil?
+ super
+ end
+ def render_to_body(options)
+ options[:template].sub!(/^\//, '') if options.key?(:template)
super || " "
end
@@ -126,18 +77,5 @@ module ActionController
def performed?
response_body
end
-
- # ==== Request only view path switching ====
- def append_view_path(path)
- view_paths.push(*path)
- end
-
- def prepend_view_path(path)
- view_paths.unshift(*path)
- end
-
- def view_paths
- view_context.view_paths
- end
end
end
diff --git a/actionpack/lib/action_controller/metal/configuration.rb b/actionpack/lib/action_controller/metal/configuration.rb
deleted file mode 100644
index 5c829853b7..0000000000
--- a/actionpack/lib/action_controller/metal/configuration.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-module ActionController
- module Configuration
- extend ActiveSupport::Concern
-
- def config
- @config ||= self.class.config
- end
-
- def config=(config)
- @config = config
- end
-
- module ClassMethods
- def default_config
- @default_config ||= {}
- end
-
- def config
- self.config ||= default_config
- end
-
- def config=(config)
- @config = ActiveSupport::OrderedHash.new
- @config.merge!(config)
- end
- end
- end
-end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb
index 37be8b3999..a5c9910d68 100644
--- a/actionpack/lib/action_controller/metal/head.rb
+++ b/actionpack/lib/action_controller/metal/head.rb
@@ -1,6 +1,7 @@
module ActionController
module Head
extend ActiveSupport::Concern
+
include ActionController::UrlFor
# Return a response that has no content (merely headers). The options
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index 1b5a4c3080..8efe01e37b 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -86,7 +86,7 @@ module ActionController
end
private
- # Overwrite _modules_for_helpers to accept :all as argument, which loads
+ # Overwrite modules_for_helpers to accept :all as argument, which loads
# all helpers in helpers_dir.
#
# ==== Parameters
@@ -95,7 +95,7 @@ module ActionController
# ==== Returns
# Array[Module]:: A normalized list of modules for the list of
# helpers provided.
- def _modules_for_helpers(args)
+ def modules_for_helpers(args)
args += all_application_helpers if args.delete(:all)
super(args)
end
diff --git a/actionpack/lib/action_controller/metal/hide_actions.rb b/actionpack/lib/action_controller/metal/hide_actions.rb
index e893acffdf..3358d80c35 100644
--- a/actionpack/lib/action_controller/metal/hide_actions.rb
+++ b/actionpack/lib/action_controller/metal/hide_actions.rb
@@ -15,10 +15,8 @@ module ActionController
# Overrides AbstractController::Base#action_method? to return false if the
# action name is in the list of hidden actions.
- def action_method?(action_name)
- self.class.visible_action?(action_name) do
- !self.class.hidden_actions.include?(action_name) && super
- end
+ def method_for_action(action_name)
+ self.class.visible_action?(action_name) && super
end
module ClassMethods
@@ -31,13 +29,13 @@ module ActionController
end
def inherited(klass)
- klass.instance_variable_set("@visible_actions", {})
+ klass.class_eval { @visible_actions = {} }
super
end
def visible_action?(action_name)
return @visible_actions[action_name] if @visible_actions.key?(action_name)
- @visible_actions[action_name] = yield
+ @visible_actions[action_name] = !hidden_actions.include?(action_name)
end
# Overrides AbstractController::Base#action_methods to remove any methods
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 0f35a7c040..6ec788f302 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -124,7 +124,7 @@ module ActionController
end
def authenticate(request, &login_procedure)
- unless authorization(request).blank?
+ unless request.authorization.blank?
login_procedure.call(*user_name_and_password(request))
end
end
@@ -133,15 +133,8 @@ module ActionController
decode_credentials(request).split(/:/, 2)
end
- def authorization(request)
- request.env['HTTP_AUTHORIZATION'] ||
- request.env['X-HTTP_AUTHORIZATION'] ||
- request.env['X_HTTP_AUTHORIZATION'] ||
- request.env['REDIRECT_X_HTTP_AUTHORIZATION']
- end
-
def decode_credentials(request)
- ActiveSupport::Base64.decode64(authorization(request).split(' ', 2).last || '')
+ ActiveSupport::Base64.decode64(request.authorization.split(' ', 2).last || '')
end
def encode_credentials(user_name, password)
@@ -165,7 +158,7 @@ module ActionController
# Authenticate with HTTP Digest, returns true or false
def authenticate_with_http_digest(realm = "Application", &password_procedure)
- HttpAuthentication::Digest.authenticate(request, realm, &password_procedure)
+ HttpAuthentication::Digest.authenticate(config.secret, request, realm, &password_procedure)
end
# Render output including the HTTP Digest authentication header
@@ -175,30 +168,23 @@ module ActionController
end
# Returns false on a valid response, true otherwise
- def authenticate(request, realm, &password_procedure)
- authorization(request) && validate_digest_response(request, realm, &password_procedure)
- end
-
- def authorization(request)
- request.env['HTTP_AUTHORIZATION'] ||
- request.env['X-HTTP_AUTHORIZATION'] ||
- request.env['X_HTTP_AUTHORIZATION'] ||
- request.env['REDIRECT_X_HTTP_AUTHORIZATION']
+ def authenticate(secret_key, request, realm, &password_procedure)
+ request.authorization && validate_digest_response(secret_key, request, realm, &password_procedure)
end
# Returns false 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)
+ def validate_digest_response(secret_key, request, realm, &password_procedure)
credentials = decode_credentials_header(request)
- valid_nonce = validate_nonce(request, credentials[:nonce])
+ valid_nonce = validate_nonce(secret_key, request, credentials[:nonce])
- if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque]
+ if valid_nonce && realm == credentials[:realm] && opaque(secret_key) == credentials[:opaque]
password = password_procedure.call(credentials[:username])
return false unless password
method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD']
- uri = credentials[:uri][0,1] == '/' ? request.request_uri : request.url
+ uri = credentials[:uri][0,1] == '/' ? request.fullpath : request.url
[true, false].any? do |password_is_ha1|
expected = expected_response(method, uri, credentials, password, password_is_ha1)
@@ -226,7 +212,7 @@ module ActionController
end
def decode_credentials_header(request)
- decode_credentials(authorization(request))
+ decode_credentials(request.authorization)
end
def decode_credentials(header)
@@ -238,6 +224,9 @@ module ActionController
end
def authentication_header(controller, realm)
+ secret_key = controller.config.secret
+ nonce = self.nonce(secret_key)
+ opaque = opaque(secret_key)
controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}")
end
@@ -280,7 +269,7 @@ module ActionController
# 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 modified by client.
- def nonce(time = Time.now)
+ def nonce(secret_key, time = Time.now)
t = time.to_i
hashed = [t, secret_key]
digest = ::Digest::MD5.hexdigest(hashed.join(":"))
@@ -292,21 +281,16 @@ module ActionController
# 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)
+ def validate_nonce(secret_key, request, value, seconds_to_timeout=5*60)
t = ActiveSupport::Base64.decode64(value).split(":").first.to_i
- nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
+ nonce(secret_key, t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end
# Opaque based on random generation - but changing each request?
- def opaque()
+ def opaque(secret_key)
::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
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
new file mode 100644
index 0000000000..282dcf66b3
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -0,0 +1,21 @@
+module ActionController
+ module ImplicitRender
+ def send_action(*)
+ ret = super
+ default_render unless response_body
+ ret
+ end
+
+ def default_render
+ render
+ end
+
+ def method_for_action(action_name)
+ super || begin
+ if template_exists?(action_name.to_s, _prefix)
+ "default_render"
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index 85035dc09c..d69de65f28 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -20,7 +20,7 @@ module ActionController
:params => request.filtered_parameters,
:formats => request.formats.map(&:to_sym),
:method => request.method,
- :path => (request.request_uri rescue "unknown")
+ :path => (request.fullpath rescue "unknown")
}
ActiveSupport::Notifications.instrument("action_controller.start_processing", raw_payload.dup)
diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index bb55383631..37106733cb 100644
--- a/actionpack/lib/action_controller/metal/rack_delegation.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -6,14 +6,11 @@ module ActionController
extend ActiveSupport::Concern
included do
- delegate :session, :to => "@_request"
delegate :headers, :status=, :location=, :content_type=,
:status, :location, :content_type, :to => "@_response"
- attr_internal :request
end
- def dispatch(action, env)
- @_request = ActionDispatch::Request.new(env)
+ def dispatch(action, request)
@_response = ActionDispatch::Response.new
@_response.request = request
super
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index faf0589fd2..25e4e18493 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -11,6 +11,7 @@ module ActionController
extend ActiveSupport::Concern
include AbstractController::Logger
+ include ActionController::RackDelegation
include ActionController::UrlFor
# Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index 639b508746..49d3d6b466 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -19,7 +19,7 @@ module ActionController
<<-RUBY_EVAL
if options.key?(:#{name})
_process_options(options)
- return _render_option_#{name}(options[:#{name}], options)
+ return _render_option_#{name}(options.delete(:#{name}), options)
end
RUBY_EVAL
end
diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb
index 0aae9f8579..f892bd9b91 100644
--- a/actionpack/lib/action_controller/metal/rendering.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -2,68 +2,54 @@ module ActionController
module Rendering
extend ActiveSupport::Concern
- included do
- include AbstractController::Rendering
- include AbstractController::LocalizedCache
- end
+ include ActionController::RackDelegation
+ include AbstractController::Rendering
- def process_action(*)
- self.formats = request.formats.map {|x| x.to_sym}
+ def process(*)
+ self.formats = request.formats.map { |x| x.to_sym }
super
end
def render(*args)
- if response_body
- raise ::AbstractController::DoubleRenderError
- end
-
- args << {} unless args.last.is_a?(Hash)
- super(*args)
- self.content_type ||= args.last[:_template].mime_type.to_s
- response_body
- end
-
- def render_to_body(options)
- _process_options(options)
+ raise ::AbstractController::DoubleRenderError if response_body
super
+ response_body
end
private
- def _render_partial(options)
- options[:partial] = action_name if options[:partial] == true
- options[:_details] = {:formats => formats}
- super
+ def _normalize_args(action=nil, options={}, &blk)
+ options = super
+ options[:update] = blk if block_given?
+ options
end
- def format_for_text
- formats.first
+ def _normalize_options(options)
+ if options.key?(:text) && options[:text].respond_to?(:to_text)
+ options[:text] = options[:text].to_text
+ end
+
+ if options[:status]
+ options[:status] = Rack::Utils.status_code(options[:status])
+ end
+
+ super
end
def _process_options(options)
status, content_type, location = options.values_at(:status, :content_type, :location)
+
self.status = status if status
self.content_type = content_type if content_type
self.headers["Location"] = url_for(location) if location
- end
- def _normalize_options(action=nil, options={}, &blk)
- case action
- when NilClass
- when Hash
- options = super(action.delete(:action), action)
- when String, Symbol
- options = super
- else
- options.merge! :partial => action
- end
-
- if options[:status]
- options[:status] = Rack::Utils.status_code(options[:status])
- end
+ super
+ end
- options[:update] = blk if block_given?
- options
+ def _with_template_hook(template)
+ super
+ self.content_type ||= template.mime_type.to_s
end
+
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 276c703307..39a809657b 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -12,11 +12,10 @@ module ActionController #:nodoc:
included do
# 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
+ config.request_forgery_protection_token ||= :authenticity_token
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
- class_attribute :allow_forgery_protection
- self.allow_forgery_protection = true
+ config.allow_forgery_protection ||= true
helper_method :form_authenticity_token
helper_method :protect_against_forgery?
@@ -80,9 +79,47 @@ module ActionController #:nodoc:
self.request_forgery_protection_token ||= :authenticity_token
before_filter :verify_authenticity_token, options
end
+
+ def request_forgery_protection_token
+ config.request_forgery_protection_token
+ end
+
+ def request_forgery_protection_token=(val)
+ config.request_forgery_protection_token = val
+ end
+
+ def allow_forgery_protection
+ config.allow_forgery_protection
+ end
+
+ def allow_forgery_protection=(val)
+ config.allow_forgery_protection = val
+ end
end
protected
+
+ def protect_from_forgery(options = {})
+ self.request_forgery_protection_token ||= :authenticity_token
+ before_filter :verify_authenticity_token, options
+ end
+
+ def request_forgery_protection_token
+ config.request_forgery_protection_token
+ end
+
+ def request_forgery_protection_token=(val)
+ config.request_forgery_protection_token = val
+ end
+
+ def allow_forgery_protection
+ config.allow_forgery_protection
+ end
+
+ def allow_forgery_protection=(val)
+ config.allow_forgery_protection = val
+ end
+
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
verified_request? || raise(ActionController::InvalidAuthenticityToken)
@@ -109,7 +146,7 @@ module ActionController #:nodoc:
end
def protect_against_forgery?
- self.class.allow_forgery_protection
+ config.allow_forgery_protection
end
end
end
diff --git a/actionpack/lib/action_controller/metal/session_management.rb b/actionpack/lib/action_controller/metal/session_management.rb
index d70f40ce7a..91d89ff9a4 100644
--- a/actionpack/lib/action_controller/metal/session_management.rb
+++ b/actionpack/lib/action_controller/metal/session_management.rb
@@ -2,44 +2,8 @@ module ActionController #:nodoc:
module SessionManagement #:nodoc:
extend ActiveSupport::Concern
- include ActionController::Configuration
-
module ClassMethods
- # Set the session store to be used for keeping the session data between requests.
- # By default, sessions are stored in browser cookies (<tt>:cookie_store</tt>),
- # but you can also specify one of the other included stores (<tt>:active_record_store</tt>,
- # <tt>:mem_cache_store</tt>, or your own custom class.
- def session_store=(store)
- if store == :active_record_store
- self.session_store = ActiveRecord::SessionStore
- else
- @@session_store = store.is_a?(Symbol) ?
- ActionDispatch::Session.const_get(store.to_s.camelize) :
- store
- end
- end
-
- # Returns the session store class currently used.
- def session_store
- if defined? @@session_store
- @@session_store
- else
- ActionDispatch::Session::CookieStore
- end
- end
-
- def session=(options = {})
- self.session_store = nil if options.delete(:disabled)
- session_options.merge!(options)
- end
- def session(*args)
- ActiveSupport::Deprecation.warn(
- "Disabling sessions for a single controller has been deprecated. " +
- "Sessions are now lazy loaded. So if you don't access them, " +
- "consider them off. You can still modify the session cookie " +
- "options with request.session_options.", caller)
- end
end
end
end
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 8f03b8bb17..753af3dc58 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -9,18 +9,13 @@ module ActionController #:nodoc:
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
:disposition => 'attachment'.freeze,
- :stream => true,
- :buffer_size => 4096,
- :x_sendfile => false
}.freeze
- X_SENDFILE_HEADER = 'X-Sendfile'.freeze
-
protected
- # Sends the file, by default streaming it 4096 bytes at a time. This way the
- # whole file doesn't need to be read into memory at once. This makes it
- # feasible to send even large files. You can optionally turn off streaming
- # and send the whole file at once.
+ # Sends the file. This uses a server-appropriate method (such as X-Sendfile)
+ # via the Rack::Sendfile middleware. The header to use is set via
+ # config.action_dispatch.x_sendfile_header, and defaults to "X-Sendfile".
+ # Your server can also configure this for you by setting the X-Sendfile-Type header.
#
# Be careful to sanitize the path parameter if it is coming from a web
# page. <tt>send_file(params[:path])</tt> allows a malicious user to
@@ -31,24 +26,12 @@ module ActionController #:nodoc:
# Defaults to <tt>File.basename(path)</tt>.
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
# either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
- # * <tt>:length</tt> - used to manually override the length (in bytes) of the content that
- # is going to be sent to the client. Defaults to <tt>File.size(path)</tt>.
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
# Valid values are 'inline' and 'attachment' (default).
- # * <tt>:stream</tt> - whether to send the file to the user agent as it is read (+true+)
- # or to read the entire file before sending (+false+). Defaults to +true+.
- # * <tt>:buffer_size</tt> - specifies size (in bytes) of the buffer used to stream the file.
- # Defaults to 4096.
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
# * <tt>:url_based_filename</tt> - set to +true+ if you want the browser guess the filename from
# the URL, which is necessary for i18n filenames on certain browsers
# (setting <tt>:filename</tt> overrides this option).
- # * <tt>:x_sendfile</tt> - uses X-Sendfile to send the file when set to +true+. This is currently
- # only available with Lighttpd/Apache2 and specific modules installed and activated. Since this
- # uses the web server to send the file, this may lower memory consumption on your server and
- # it will not block your application for further requests.
- # See http://blog.lighttpd.net/articles/2006/07/02/x-sendfile and
- # http://tn123.ath.cx/mod_xsendfile/ for details. Defaults to +false+.
#
# The default Content-Type and Content-Disposition headers are
# set to download arbitrary binary files in as many browsers as
@@ -81,29 +64,16 @@ module ActionController #:nodoc:
def send_file(path, options = {}) #:doc:
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
- options[:length] ||= File.size(path)
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
send_file_headers! options
- @performed_render = false
-
if options[:x_sendfile]
- 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|
- len = options[:buffer_size] || 4096
- File.open(path, 'rb') do |file|
- while buf = file.read(len)
- output.write(buf)
- end
- end
- }
- else
- File.open(path, 'rb') { |file| render :status => options[:status], :text => file.read }
- end
+ ActiveSupport::Deprecation.warn(":x_sendfile is no longer needed in send_file", caller)
end
+
+ self.status = options[:status] || 200
+ self.content_type = options[:content_type] if options.key?(:content_type)
+ self.response_body = File.open(path, "rb")
end
# Sends the given binary data to the browser. This method is similar to
@@ -138,32 +108,35 @@ module ActionController #:nodoc:
# 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:
- send_file_headers! options.merge(:length => data.bytesize)
- render :status => options[:status], :text => data
+ send_file_headers! options.dup
+ render options.slice(:status, :content_type).merge(:text => data)
end
private
def send_file_headers!(options)
options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options))
- [:length, :type, :disposition].each do |arg|
+ [:type, :disposition].each do |arg|
raise ArgumentError, ":#{arg} option required" if options[arg].nil?
end
- disposition = options[:disposition].dup || 'attachment'
+ if options.key?(:length)
+ ActiveSupport::Deprecation.warn("You do not need to provide the file's length", caller)
+ end
- disposition <<= %(; filename="#{options[:filename]}") if options[:filename]
+ disposition = options[:disposition]
+ disposition += %(; filename="#{options[:filename]}") if options[:filename]
content_type = options[:type]
if content_type.is_a?(Symbol)
- raise ArgumentError, "Unknown MIME type #{options[:type]}" unless Mime::EXTENSION_LOOKUP.key?(content_type.to_s)
- self.content_type = Mime::Type.lookup_by_extension(content_type.to_s)
+ extension = Mime[content_type]
+ raise ArgumentError, "Unknown MIME type #{options[:type]}" unless extension
+ self.content_type = extension
else
self.content_type = content_type
end
headers.merge!(
- 'Content-Length' => options[:length].to_s,
'Content-Disposition' => disposition,
'Content-Transfer-Encoding' => 'binary'
)
diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb
index 707ad968f4..4b8c452d50 100644
--- a/actionpack/lib/action_controller/metal/testing.rb
+++ b/actionpack/lib/action_controller/metal/testing.rb
@@ -13,7 +13,6 @@ module ActionController
if cookies = @_request.env['action_dispatch.cookies']
cookies.write(@_response)
end
- @_response.body ||= self.response_body
@_response.prepare!
set_test_assigns
ret
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 4f3ad07be5..10c7ca9021 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -1,165 +1,20 @@
-require 'active_support/core_ext/class/attribute'
-require 'active_support/core_ext/module/attribute_accessors'
-
module ActionController
- # In <b>routes.rb</b> one defines URL-to-controller mappings, but the reverse
- # is also possible: an URL can be generated from one of your routing definitions.
- # URL generation functionality is centralized in this module.
- #
- # See ActionController::Routing and ActionController::Resources for general
- # information about routing and routes.rb.
- #
- # <b>Tip:</b> If you need to generate URLs from your models or some other place,
- # then ActionController::UrlFor is what you're looking for. Read on for
- # an introduction.
- #
- # == URL generation from parameters
- #
- # As you may know, some functions - such as ActionController::Base#url_for
- # and ActionView::Helpers::UrlHelper#link_to, can generate URLs given a set
- # of parameters. For example, you've probably had the chance to write code
- # like this in one of your views:
- #
- # <%= link_to('Click here', :controller => 'users',
- # :action => 'new', :message => 'Welcome!') %>
- #
- # #=> Generates a link to: /users/new?message=Welcome%21
- #
- # link_to, and all other functions that require URL generation functionality,
- # actually use ActionController::UrlFor under the hood. And in particular,
- # they use the ActionController::UrlFor#url_for method. One can generate
- # the same path as the above example by using the following code:
- #
- # include UrlFor
- # url_for(:controller => 'users',
- # :action => 'new',
- # :message => 'Welcome!',
- # :only_path => true)
- # # => "/users/new?message=Welcome%21"
- #
- # Notice the <tt>:only_path => true</tt> part. This is because UrlFor has no
- # information about the website hostname that your Rails app is serving. So if you
- # want to include the hostname as well, then you must also pass the <tt>:host</tt>
- # argument:
- #
- # include UrlFor
- # url_for(:controller => 'users',
- # :action => 'new',
- # :message => 'Welcome!',
- # :host => 'www.example.com') # Changed this.
- # # => "http://www.example.com/users/new?message=Welcome%21"
- #
- # By default, all controllers and views have access to a special version of url_for,
- # that already knows what the current hostname is. So if you use url_for in your
- # controllers or your views, then you don't need to explicitly pass the <tt>:host</tt>
- # argument.
- #
- # For convenience reasons, mailers provide a shortcut for ActionController::UrlFor#url_for.
- # So within mailers, you only have to type 'url_for' instead of 'ActionController::UrlFor#url_for'
- # in full. However, mailers don't have hostname information, and what's why you'll still
- # have to specify the <tt>:host</tt> argument when generating URLs in mailers.
- #
- #
- # == URL generation for named routes
- #
- # UrlFor also allows one to access methods that have been auto-generated from
- # named routes. For example, suppose that you have a 'users' resource in your
- # <b>routes.rb</b>:
- #
- # map.resources :users
- #
- # 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 by including ActionController::UrlFor in your class:
- #
- # class User < ActiveRecord::Base
- # include ActionController::UrlFor
- #
- # def base_uri
- # user_path(self)
- # end
- # end
- #
- # User.find(1).base_uri # => "/users/1"
- #
module UrlFor
extend ActiveSupport::Concern
- included do
- ActionController::Routing::Routes.install_helpers(self)
-
- # Including in a class uses an inheritable hash. Modules get a plain hash.
- if respond_to?(:class_attribute)
- class_attribute :default_url_options
- else
- mattr_accessor :default_url_options
- end
+ include ActionDispatch::Routing::UrlFor
- self.default_url_options = {}
+ def url_options
+ super.reverse_merge(
+ :host => request.host_with_port,
+ :protocol => request.protocol,
+ :_path_segments => request.symbolized_path_parameters
+ ).merge(:script_name => request.script_name)
end
- # Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
- # the form of a hash, just like the one you would use for url_for directly. Example:
- #
- # def default_url_options(options)
- # { :project => @project.active? ? @project.url_name : "unknown" }
- # end
- #
- # As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the
- # urls as they stem from the business domain. Please note that any individual url_for call can always override the defaults set
- # by this method.
- def default_url_options(options = nil)
- self.class.default_url_options
- end
-
- def rewrite_options(options) #:nodoc:
- if options.delete(:use_defaults) != false && (defaults = default_url_options(options))
- defaults.merge(options)
- else
- options
- end
- end
-
- # Generate a url based on the options provided, default_url_options and the
- # routes defined in routes.rb. The following options are supported:
- #
- # * <tt>:only_path</tt> - If true, the relative url is returned. Defaults to +false+.
- # * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'.
- # * <tt>:host</tt> - Specifies the host the link should be targeted at.
- # If <tt>:only_path</tt> is false, this option must be
- # provided either explicitly, or via +default_url_options+.
- # * <tt>:port</tt> - Optionally specify the port to connect to.
- # * <tt>:anchor</tt> - An anchor name to be appended to the path.
- # * <tt>:skip_relative_url_root</tt> - If true, the url is not constructed using the
- # +relative_url_root+ set in ActionController::Base.relative_url_root.
- # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
- #
- # Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to
- # +url_for+ is forwarded to the Routes module.
- #
- # Examples:
- #
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :port=>'8080' # => 'http://somehost.org:8080/tasks/testing'
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok'
- # url_for :controller => 'tasks', :action => 'testing', :trailing_slash=>true # => 'http://somehost.org/tasks/testing/'
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33'
- def url_for(options = {})
- options ||= {}
- case options
- when String
- options
- when Hash
- _url_rewriter.rewrite(rewrite_options(options))
- else
- polymorphic_url(options)
- end
- end
-
- protected
-
- def _url_rewriter
- ActionController::UrlRewriter
+ def _router
+ raise "In order to use #url_for, you must include the helpers of a particular " \
+ "router. For instance, `include Rails.application.routes.url_helpers"
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/middleware.rb b/actionpack/lib/action_controller/middleware.rb
index 17275793b7..2115b07b3e 100644
--- a/actionpack/lib/action_controller/middleware.rb
+++ b/actionpack/lib/action_controller/middleware.rb
@@ -6,7 +6,8 @@ module ActionController
end
def call(env)
- @controller.build(@app).dispatch(:index, env)
+ request = ActionDispatch::Request.new(env)
+ @controller.build(@app).dispatch(:index, request)
end
end
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb
index eaed00cfb7..ae363e300c 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/polymorphic_routes.rb
@@ -92,8 +92,7 @@ module ActionController
inflection = if options[:action].to_s == "new"
args.pop
:singular
- elsif (record.respond_to?(:new_record?) && record.new_record?) ||
- (record.respond_to?(:destroyed?) && record.destroyed?)
+ elsif (record.respond_to?(:persisted?) && !record.persisted?)
args.pop
:plural
elsif record.is_a?(Class)
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index 55a5c22ac0..6a3afbb157 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -1,30 +1,80 @@
-require "action_controller"
require "rails"
+require "action_controller"
require "action_view/railtie"
+require "active_support/core_ext/class/subclasses"
+require "active_support/deprecation/proxy_wrappers"
+require "active_support/deprecation"
module ActionController
class Railtie < Rails::Railtie
railtie_name :action_controller
- require "action_controller/railties/subscriber"
- subscriber ActionController::Railties::Subscriber.new
+ require "action_controller/railties/log_subscriber"
+ require "action_controller/railties/url_helpers"
+
+ ad = config.action_dispatch
+ config.action_controller.singleton_class.send(:define_method, :session) do
+ ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
+ "renamed to config.action_dispatch.session.", caller
+ ad.session
+ end
+
+ config.action_controller.singleton_class.send(:define_method, :session=) do |val|
+ ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
+ "renamed to config.action_dispatch.session.", caller
+ ad.session = val
+ end
+
+ config.action_controller.singleton_class.send(:define_method, :session_store) do
+ ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
+ "renamed to config.action_dispatch.session_store.", caller
+ ad.session_store
+ end
+
+ config.action_controller.singleton_class.send(:define_method, :session_store=) do |val|
+ ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
+ "renamed to config.action_dispatch.session_store.", caller
+ ad.session_store = val
+ end
+
+ log_subscriber ActionController::Railties::LogSubscriber.new
initializer "action_controller.logger" do
- ActionController::Base.logger ||= Rails.logger
+ ActionController.base_hook { self.logger ||= Rails.logger }
end
initializer "action_controller.set_configs" do |app|
- app.config.action_controller.each do |k,v|
- ActionController::Base.send "#{k}=", v
- end
+ paths = app.config.paths
+ ac = app.config.action_controller
+
+ ac.assets_dir = paths.public.to_a.first
+ ac.javascripts_dir = paths.public.javascripts.to_a.first
+ ac.stylesheets_dir = paths.public.stylesheets.to_a.first
+ ac.secret = app.config.cookie_secret
+
+ ActionController.base_hook { self.config.replace(ac) }
end
initializer "action_controller.initialize_framework_caches" do
- ActionController::Base.cache_store ||= RAILS_CACHE
+ ActionController.base_hook { self.cache_store ||= RAILS_CACHE }
end
initializer "action_controller.set_helpers_path" do |app|
- ActionController::Base.helpers_path = app.config.paths.app.helpers.to_a
+ ActionController.base_hook do
+ self.helpers_path = app.config.paths.app.helpers.to_a
+ end
+ end
+
+ initializer "action_controller.url_helpers" do |app|
+ ActionController.base_hook do
+ extend ::ActionController::Railtie::UrlHelpers.with(app.routes)
+ end
+
+ message = "ActionController::Routing::Routes is deprecated. " \
+ "Instead, use Rails.application.routes"
+
+ proxy = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(app.routes, message)
+ ActionController::Routing::Routes = proxy
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/railties/subscriber.rb b/actionpack/lib/action_controller/railties/log_subscriber.rb
index 4499e82292..c2299d0b05 100644
--- a/actionpack/lib/action_controller/railties/subscriber.rb
+++ b/actionpack/lib/action_controller/railties/log_subscriber.rb
@@ -1,6 +1,6 @@
module ActionController
module Railties
- class Subscriber < Rails::Subscriber
+ class LogSubscriber < Rails::LogSubscriber
INTERNAL_PARAMS = %w(controller action format _method only_path)
def start_processing(event)
@@ -22,15 +22,7 @@ module ActionController
end
def send_file(event)
- message = if event.payload[:x_sendfile]
- header = ActionController::Streaming::X_SENDFILE_HEADER
- "Sent #{header} header %s"
- elsif event.payload[:stream]
- "Streamed file %s"
- else
- "Sent file %s"
- end
-
+ message = "Sent file %s"
message << " (%.1fms)"
info(message % [event.payload[:path], event.duration])
end
diff --git a/actionpack/lib/action_controller/railties/url_helpers.rb b/actionpack/lib/action_controller/railties/url_helpers.rb
new file mode 100644
index 0000000000..ad2a8d4ef3
--- /dev/null
+++ b/actionpack/lib/action_controller/railties/url_helpers.rb
@@ -0,0 +1,14 @@
+module ActionController
+ class Railtie
+ module UrlHelpers
+ def self.with(router)
+ Module.new do
+ define_method(:inherited) do |klass|
+ super(klass)
+ klass.send(:include, router.url_helpers)
+ end
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index 1165c3b7c5..3f966b1b64 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -60,13 +60,32 @@ module ActionController
#
# dom_id(Post.find(45), :edit) # => "edit_post_45"
def dom_id(record, prefix = nil)
- if record_id = record.id
+ if record_id = record_key_for_dom_id(record)
"#{dom_class(record, prefix)}#{JOIN}#{record_id}"
else
dom_class(record, prefix || NEW)
end
end
+ # Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id.
+ # This can be overwritten to customize the default generated string representation if desired.
+ # If you need to read back a key from a dom_id in order to query for the underlying database record,
+ # you should write a helper like 'person_record_from_dom_id' that will extract the key either based
+ # on the default implementation (which just joins all key attributes with '-') or on your own
+ # overwritten version of the method. By default, this implementation passes the key string through a
+ # method that replaces all characters that are invalid inside DOM ids, with valid ones. You need to
+ # make sure yourself that your dom ids are valid, in case you overwrite this method.
+ def record_key_for_dom_id(record)
+ return record.id unless record.respond_to?(:to_model)
+ key = record.to_model.to_key
+ key ? sanitize_dom_id(key.join('_')) : key
+ end
+
+ # Replaces characters that are invalid in HTML DOM ids with valid ones.
+ def sanitize_dom_id(candidate_id)
+ candidate_id # TODO implement conversion to valid DOM id values
+ end
+
# Returns the plural class name of a record or class. Examples:
#
# plural_class_name(post) # => "posts"
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 14557ca782..cdb5db32aa 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -17,9 +17,9 @@ module ActionController
end
end
- def assign_parameters(controller_path, action, parameters = {})
+ def assign_parameters(router, controller_path, action, parameters = {})
parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action)
- extra_keys = ActionController::Routing::Routes.extra_keys(parameters)
+ extra_keys = router.extra_keys(parameters)
non_path_parameters = get? ? query_parameters : request_parameters
parameters.each do |key, value|
if value.is_a? Fixnum
@@ -220,7 +220,7 @@ module ActionController
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
# Sanity check for required instance variables so we can give an
# understandable error message.
- %w(@controller @request @response).each do |iv_name|
+ %w(@router @controller @request @response).each do |iv_name|
if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
end
@@ -236,7 +236,7 @@ module ActionController
@request.env['REQUEST_METHOD'] = http_method
parameters ||= {}
- @request.assign_parameters(@controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
+ @request.assign_parameters(@router, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
@request.session = ActionController::TestSession.new(session) unless session.nil?
@request.session["flash"] = @request.flash.update(flash || {})
@@ -322,6 +322,8 @@ module ActionController
@controller ||= klass.new rescue nil
end
+ @request.env.delete('PATH_INFO')
+
if @controller
@controller.request = @request
@controller.params = {}
@@ -335,13 +337,20 @@ module ActionController
private
def build_request_uri(action, parameters)
- unless @request.env['REQUEST_URI']
- options = @controller.__send__(:rewrite_options, parameters)
- options.update(:only_path => true, :action => action)
-
- url = ActionController::UrlRewriter.new(@request, parameters)
- @request.request_uri = url.rewrite(options)
+ unless @request.env["PATH_INFO"]
+ options = @controller.__send__(:url_options).merge(parameters)
+ options.update(
+ :only_path => true,
+ :action => action,
+ :relative_url_root => nil,
+ :_path_segments => @request.symbolized_path_parameters)
+
+ url, query_string = @router.url_for(options).split("?", 2)
+
+ @request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
+ @request.env["PATH_INFO"] = url
+ @request.env["QUERY_STRING"] = query_string || ""
end
end
- end
+ end
end
diff --git a/actionpack/lib/action_controller/url_rewriter.rb b/actionpack/lib/action_controller/url_rewriter.rb
deleted file mode 100644
index 933a1fa8f9..0000000000
--- a/actionpack/lib/action_controller/url_rewriter.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-require 'active_support/core_ext/hash/except'
-
-module ActionController
- # Rewrites URLs for Base.redirect_to and Base.url_for in the controller.
- class UrlRewriter #:nodoc:
- RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash, :skip_relative_url_root]
-
- def initialize(request, parameters)
- @request, @parameters = request, parameters
- end
-
- def rewrite(options = {})
- options[:host] ||= @request.host_with_port
- options[:protocol] ||= @request.protocol
-
- self.class.rewrite(options, @request.symbolized_path_parameters) do |options|
- process_path_options(options)
- end
- end
-
- def to_str
- "#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@parameters[:controller]}, #{@parameters[:action]}, #{@request.parameters.inspect}"
- end
-
- alias_method :to_s, :to_str
-
- def self.rewrite(options, path_segments=nil)
- rewritten_url = ""
-
- unless options[:only_path]
- rewritten_url << (options[:protocol] || "http")
- rewritten_url << "://" unless rewritten_url.match("://")
- rewritten_url << rewrite_authentication(options)
-
- raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host]
-
- rewritten_url << options[:host]
- rewritten_url << ":#{options.delete(:port)}" if options.key?(:port)
- end
-
- path_options = options.except(*RESERVED_OPTIONS)
- path_options = yield(path_options) if block_given?
- path = Routing::Routes.generate(path_options, path_segments || {})
-
- rewritten_url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root]
- rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
- rewritten_url << "##{Rack::Utils.escape(options[:anchor].to_param.to_s)}" if options[:anchor]
-
- rewritten_url
- end
-
- protected
-
- def self.rewrite_authentication(options)
- if options[:user] && options[:password]
- "#{Rack::Utils.escape(options.delete(:user))}:#{Rack::Utils.escape(options.delete(:password))}@"
- else
- ""
- end
- end
-
- # Given a Hash of options, generates a route
- def process_path_options(options)
- options = options.symbolize_keys
- options.update(options[:params].symbolize_keys) if options[:params]
-
- if (overwrite = options.delete(:overwrite_params))
- options.update(@parameters.symbolize_keys)
- options.update(overwrite.symbolize_keys)
- end
-
- options
- end
-
- end
-end
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 479ea959e6..dfb8919561 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -48,6 +48,7 @@ module ActionDispatch
autoload :Flash
autoload :Head
autoload :ParamsParser
+ autoload :RemoteIp
autoload :Rescue
autoload :ShowExceptions
autoload :Static
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index 428e62dc6b..d2404e63c5 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -37,8 +37,21 @@ module ActionDispatch
end
module Response
- def cache_control
- @cache_control ||= {}
+ attr_reader :cache_control
+
+ def initialize(*)
+ status, header, body = super
+
+ @cache_control = {}
+ @etag = self["ETag"]
+
+ if cache_control = self["Cache-Control"]
+ cache_control.split(/,\s*/).each do |segment|
+ first, last = segment.split("=")
+ last ||= true
+ @cache_control[first.to_sym] = last
+ end
+ end
end
def last_modified
@@ -65,7 +78,7 @@ module ActionDispatch
def etag=(etag)
key = ActiveSupport::Cache.expand_cache_key(etag)
- @etag = %("#{Digest::MD5.hexdigest(key)}")
+ @etag = self["ETag"] = %("#{Digest::MD5.hexdigest(key)}")
end
private
@@ -100,6 +113,8 @@ module ActionDispatch
def set_conditional_cache_control!
control = @cache_control
+ return if self["Cache-Control"].present?
+
if control.empty?
headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
elsif @cache_control[:no_cache]
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 1958e1668d..451b79b190 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -25,9 +25,16 @@ module ActionDispatch
module FilterParameters
extend ActiveSupport::Concern
+ mattr_reader :compiled_parameter_filter_for
+ @@compiled_parameter_filter_for = {}
+
# Return a hash of parameters with all sensitive data replaced.
def filtered_parameters
- @filtered_parameters ||= process_parameter_filter(parameters)
+ @filtered_parameters ||= if filtering_parameters?
+ process_parameter_filter(parameters)
+ else
+ parameters.dup
+ end
end
alias :fitered_params :filtered_parameters
@@ -46,10 +53,18 @@ module ActionDispatch
protected
- def compile_parameter_filter #:nodoc:
+ def filtering_parameters? #:nodoc:
+ @env["action_dispatch.parameter_filter"].present?
+ end
+
+ def process_parameter_filter(params) #:nodoc:
+ compiled_parameter_filter_for(@env["action_dispatch.parameter_filter"]).call(params)
+ end
+
+ def compile_parameter_filter(filters) #:nodoc:
strings, regexps, blocks = [], [], []
- Array(@env["action_dispatch.parameter_filter"]).each do |item|
+ filters.each do |item|
case item
when NilClass
when Proc
@@ -65,34 +80,34 @@ module ActionDispatch
[regexps, blocks]
end
- def filtering_parameters? #:nodoc:
- @env["action_dispatch.parameter_filter"].present?
- end
+ def compiled_parameter_filter_for(filters) #:nodoc:
+ @@compiled_parameter_filter_for[filters] ||= begin
+ regexps, blocks = compile_parameter_filter(filters)
- def process_parameter_filter(original_params) #:nodoc:
- return original_params.dup unless filtering_parameters?
+ lambda do |original_params|
+ filtered_params = {}
- filtered_params = {}
- regexps, blocks = compile_parameter_filter
+ original_params.each do |key, value|
+ if regexps.find { |r| key =~ r }
+ value = '[FILTERED]'
+ elsif value.is_a?(Hash)
+ value = process_parameter_filter(value)
+ elsif value.is_a?(Array)
+ value = value.map { |v| v.is_a?(Hash) ? process_parameter_filter(v) : v }
+ elsif blocks.present?
+ key = key.dup
+ value = value.dup if value.duplicable?
+ blocks.each { |b| b.call(key, value) }
+ end
- original_params.each do |key, value|
- if regexps.find { |r| key =~ r }
- value = '[FILTERED]'
- elsif value.is_a?(Hash)
- value = process_parameter_filter(value)
- elsif value.is_a?(Array)
- value = value.map { |i| process_parameter_filter(i) }
- elsif blocks.present?
- key = key.dup
- value = value.dup if value.duplicable?
- blocks.each { |b| b.call(key, value) }
- end
+ filtered_params[key] = value
+ end
- filtered_params[key] = value
+ filtered_params
+ end
end
-
- filtered_params
end
+
end
end
end \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index 40617e239a..fec250e928 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -67,21 +67,6 @@ module ActionDispatch
@env["action_dispatch.request.formats"] = [Mime::Type.lookup_by_extension(parameters[:format])]
end
- # Returns a symbolized version of the <tt>:format</tt> parameter of the request.
- # If no \format is given it returns <tt>:js</tt>for Ajax requests and <tt>:html</tt>
- # otherwise.
- def template_format
- parameter_format = parameters[:format]
-
- if parameter_format
- parameter_format
- elsif xhr?
- :js
- else
- :html
- end
- end
-
# Receives an array of mimes and return the first user sent mime that
# matches the order array.
#
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 7a17023ed2..ea9f0f99c2 100755
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -30,6 +30,14 @@ module ActionDispatch
METHOD
end
+ def self.new(env)
+ if request = env["action_dispatch.request"] && request.instance_of?(self)
+ return request
+ end
+
+ super
+ end
+
def key?(key)
@env.key?(key)
end
@@ -119,36 +127,7 @@ module ActionDispatch
# delimited list in the case of multiple chained proxies; the last
# address which is not trusted is the originating IP.
def remote_ip
- remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].scan(/[^,\s]+/)
-
- unless remote_addr_list.blank?
- not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES || addr =~ ActionController::Base.trusted_proxies}
- return not_trusted_addrs.first unless not_trusted_addrs.empty?
- end
- remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
-
- if @env.include? 'HTTP_CLIENT_IP'
- if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
- # We don't know which came from the proxy, and which from the user
- raise ActionController::ActionControllerError.new <<EOM
-IP spoofing attack?!
-HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
-HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
-EOM
- end
-
- return @env['HTTP_CLIENT_IP']
- end
-
- if remote_ips
- while remote_ips.size > 1 && (TRUSTED_PROXIES =~ remote_ips.last.strip || ActionController::Base.trusted_proxies =~ remote_ips.last.strip)
- remote_ips.pop
- end
-
- return remote_ips.last.strip
- end
-
- @env['REMOTE_ADDR']
+ (@env["action_dispatch.remote_ip"] || ip).to_s
end
# Returns the lowercase name of the HTTP server software.
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index f299306ff4..9cfe5a5ea9 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -32,31 +32,38 @@ module ActionDispatch # :nodoc:
# end
# end
class Response < Rack::Response
- include ActionDispatch::Http::Cache::Response
-
attr_accessor :request, :blank
attr_writer :header, :sending_file
alias_method :headers=, :header=
- def initialize
- @status = 200
- @header = {}
- @cache_control = {}
+ module Setup
+ def initialize(status = 200, header = {}, body = [])
+ @writer = lambda { |x| @body << x }
+ @block = nil
+ @length = 0
- @writer = lambda { |x| @body << x }
- @block = nil
- @length = 0
+ @status, @header = status, header
+ self.body = body
- @body, @cookie = [], []
- @sending_file = false
+ @cookie = []
+ @sending_file = false
- @blank = false
- @etag = nil
+ @blank = false
+
+ if content_type = self["Content-Type"]
+ type, charset = content_type.split(/;\s*charset=/)
+ @content_type = Mime::Type.lookup(type)
+ @charset = charset || "UTF-8"
+ end
- yield self if block_given?
+ yield self if block_given?
+ end
end
+ include Setup
+ include ActionDispatch::Http::Cache::Response
+
def status=(status)
@status = Rack::Utils.status_code(status)
end
@@ -76,6 +83,18 @@ module ActionDispatch # :nodoc:
end
alias_method :status_message, :message
+ def respond_to?(method)
+ if method.to_sym == :to_path
+ @body.respond_to?(:to_path)
+ else
+ super
+ end
+ end
+
+ def to_path
+ @body.to_path
+ end
+
def body
str = ''
each { |part| str << part.to_s }
@@ -120,7 +139,7 @@ module ActionDispatch # :nodoc:
assign_default_content_type_and_charset!
handle_conditional_get!
self["Set-Cookie"] = @cookie.join("\n") unless @cookie.blank?
- self["ETag"] = @etag if @etag
+ self["ETag"] = @_etag if @_etag
super
end
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 40ceb5a9b6..b64a83c62e 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -3,7 +3,7 @@ module ActionDispatch
module URL
# Returns the complete URL used for this request.
def url
- protocol + host_with_port + request_uri
+ protocol + host_with_port + fullpath
end
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
@@ -81,42 +81,15 @@ module ActionDispatch
parts[0..-(tld_length+2)]
end
- # Returns the query string, accounting for server idiosyncrasies.
- def query_string
- @env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].to_s.split('?', 2)[1] || '')
+ def subdomain(tld_length = 1)
+ subdomains(tld_length).join('.')
end
# Returns the request URI, accounting for server idiosyncrasies.
# WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
def request_uri
- if uri = @env['REQUEST_URI']
- # Remove domain, which webrick puts into the request_uri.
- (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
- else
- # Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
- uri = @env['PATH_INFO'].to_s
-
- if script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
- uri = uri.sub(/#{script_filename}\//, '')
- end
-
- env_qs = @env['QUERY_STRING'].to_s
- uri += "?#{env_qs}" unless env_qs.empty?
-
- if uri.blank?
- @env.delete('REQUEST_URI')
- else
- @env['REQUEST_URI'] = uri
- end
- end
- end
-
- # Returns the interpreted \path to requested resource after all the installation
- # directory of this application was taken into account.
- def path
- path = request_uri.to_s[/\A[^\?]*/]
- path.sub!(/\A#{ActionController::Base.relative_url_root}/, '')
- path
+ ActiveSupport::Deprecation.warn "Using #request_uri is deprecated. Use fullpath instead.", caller
+ fullpath
end
private
diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb
index 7cf75ffe63..d07841218a 100644
--- a/actionpack/lib/action_dispatch/middleware/callbacks.rb
+++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb
@@ -37,7 +37,7 @@ module ActionDispatch
def initialize(app, prepare_each_request = false)
@app, @prepare_each_request = app, prepare_each_request
- run_callbacks(:prepare) unless @prepare_each_request
+ run_callbacks(:prepare)
end
def call(env)
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index 522982e202..f4c4324fb0 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -1,4 +1,3 @@
-require 'active_support/json'
require 'action_dispatch/http/request'
module ActionDispatch
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
new file mode 100644
index 0000000000..c7d710b98e
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -0,0 +1,51 @@
+module ActionDispatch
+ class RemoteIp
+ class IpSpoofAttackError < StandardError ; end
+
+ class RemoteIpGetter
+ def initialize(env, check_ip_spoofing, trusted_proxies)
+ @env = env
+ @check_ip_spoofing = check_ip_spoofing
+ @trusted_proxies = trusted_proxies
+ end
+
+ def remote_addrs
+ @remote_addrs ||= begin
+ list = @env['REMOTE_ADDR'] ? @env['REMOTE_ADDR'].split(/[,\s]+/) : []
+ list.reject { |addr| addr =~ @trusted_proxies }
+ end
+ end
+
+ def to_s
+ return remote_addrs.first if remote_addrs.any?
+
+ forwarded_ips = @env['HTTP_X_FORWARDED_FOR'] ? @env['HTTP_X_FORWARDED_FOR'].strip.split(/[,\s]+/) : []
+
+ if client_ip = @env['HTTP_CLIENT_IP']
+ if @check_ip_spoofing && !forwarded_ips.include?(client_ip)
+ # We don't know which came from the proxy, and which from the user
+ raise IpSpoofAttackError, "IP spoofing attack?!" \
+ "HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}" \
+ "HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}"
+ end
+ return client_ip
+ end
+
+ return forwarded_ips.reject { |ip| ip =~ @trusted_proxies }.last || @env["REMOTE_ADDR"]
+ end
+ end
+
+ def initialize(app, check_ip_spoofing = true, trusted_proxies = nil)
+ @app = app
+ @check_ip_spoofing = check_ip_spoofing
+ regex = '(^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.)'
+ regex << "|(#{trusted_proxies})" if trusted_proxies
+ @trusted_proxies = Regexp.new(regex, "i")
+ end
+
+ def call(env)
+ env["action_dispatch.remote_ip"] = RemoteIpGetter.new(env, @check_ip_spoofing, @trusted_proxies)
+ @app.call(env)
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index 04a101dbb2..22da82479e 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -1,5 +1,4 @@
require 'active_support/core_ext/hash/keys'
-require 'rack/request'
module ActionDispatch
module Session
@@ -177,9 +176,8 @@ module ActionDispatch
if key.blank?
raise ArgumentError, 'A key is required to write a ' +
'cookie containing the session data. Use ' +
- 'config.action_controller.session = { :key => ' +
- '"_myapp_session", :secret => "some secret phrase" } in ' +
- 'config/application.rb'
+ 'config.action_controller.session_store :cookie_store, { :key => ' +
+ '"_myapp_session" } in config/application.rb'
end
end
@@ -193,10 +191,9 @@ module ActionDispatch
if secret.blank?
raise ArgumentError, "A secret is required to generate an " +
"integrity hash for cookie session data. Use " +
- "config.action_controller.session = { :key => " +
- "\"_myapp_session\", :secret => \"some secret phrase of at " +
- "least #{SECRET_MIN_LENGTH} characters\" } " +
- "in config/environment.rb"
+ "config.cookie_secret = \"some secret phrase of at " +
+ "least #{SECRET_MIN_LENGTH} characters\"" +
+ "in config/application.rb"
end
if secret.length < SECRET_MIN_LENGTH
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index 18a2922fa7..5c5362ce4a 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -58,7 +58,7 @@ module ActionDispatch
if lazy_compare?(@klass) && lazy_compare?(middleware)
normalize(@klass) == normalize(middleware)
else
- klass == ActiveSupport::Inflector.constantize(middleware.to_s)
+ klass.name == middleware.to_s
end
end
end
@@ -122,7 +122,11 @@ module ActionDispatch
find_all { |middleware| middleware.active? }
end
- def build(app)
+ def build(app = nil, &blk)
+ app ||= blk
+
+ raise "MiddlewareStack#build requires an app" unless app
+
active.reverse.inject(app) { |a, e| e.build(a) }
end
end
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index 335daafc01..e486bd4079 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -5,6 +5,9 @@ module ActionDispatch
class Railtie < Rails::Railtie
railtie_name :action_dispatch
+ config.action_dispatch.x_sendfile_header = "X-Sendfile"
+ config.action_dispatch.ip_spoofing_check = true
+
# Prepare dispatcher callbacks and run 'prepare' callbacks
initializer "action_dispatch.prepare_dispatcher" do |app|
# TODO: This used to say unless defined?(Dispatcher). Find out why and fix.
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 335c9edb98..5bc3205c51 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -205,6 +205,7 @@ module ActionDispatch
autoload :Mapper, 'action_dispatch/routing/mapper'
autoload :Route, 'action_dispatch/routing/route'
autoload :RouteSet, 'action_dispatch/routing/route_set'
+ autoload :UrlFor, 'action_dispatch/routing/url_for'
SEPARATORS = %w( / . ? )
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options]
diff --git a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
index 8ce6b2f6d5..dd650e83d9 100644
--- a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
@@ -1,5 +1,30 @@
module ActionDispatch
module Routing
+ class RouteSet
+ attr_accessor :controller_namespaces
+
+ CONTROLLER_REGEXP = /[_a-zA-Z0-9]+/
+
+ def controller_constraints
+ @controller_constraints ||= begin
+ namespaces = controller_namespaces + in_memory_controller_namespaces
+ source = namespaces.map { |ns| "#{Regexp.escape(ns)}/#{CONTROLLER_REGEXP.source}" }
+ source << CONTROLLER_REGEXP.source
+ Regexp.compile(source.sort.reverse.join('|'))
+ end
+ end
+
+ def in_memory_controller_namespaces
+ namespaces = Set.new
+ ActionController::Base.subclasses.each do |klass|
+ controller_name = klass.underscore
+ namespaces << controller_name.split('/')[0...-1].join('/')
+ end
+ namespaces.delete('')
+ namespaces
+ end
+ end
+
# Mapper instances are used to build routes. The object passed to the draw
# block in config/routes.rb is a Mapper instance.
#
@@ -244,14 +269,15 @@ module ActionDispatch
attr_reader :collection_methods, :member_methods, :new_methods
attr_reader :path_prefix, :name_prefix, :path_segment
attr_reader :plural, :singular
- attr_reader :options
+ attr_reader :options, :defaults
- def initialize(entities, options)
+ def initialize(entities, options, defaults)
@plural ||= entities
@singular ||= options[:singular] || plural.to_s.singularize
@path_segment = options.delete(:as) || @plural
@options = options
+ @defaults = defaults
arrange_actions
add_default_actions
@@ -280,7 +306,7 @@ module ActionDispatch
def new_path
new_action = self.options[:path_names][:new] if self.options[:path_names]
- new_action ||= ActionController::Base.resources_path_names[:new]
+ new_action ||= self.defaults[:path_names][:new]
@new_path ||= "#{path}/#{new_action}"
end
@@ -370,7 +396,7 @@ module ActionDispatch
end
class SingletonResource < Resource #:nodoc:
- def initialize(entity, options)
+ def initialize(entity, options, defaults)
@singular = @plural = entity
options[:controller] ||= @singular.to_s.pluralize
super
@@ -717,7 +743,7 @@ module ActionDispatch
private
def map_resource(entities, options = {}, &block)
- resource = Resource.new(entities, options)
+ resource = Resource.new(entities, options, :path_names => @set.resources_path_names)
with_options :controller => resource.controller do |map|
map_associations(resource, options)
@@ -734,7 +760,7 @@ module ActionDispatch
end
def map_singleton_resource(entities, options = {}, &block)
- resource = SingletonResource.new(entities, options)
+ resource = SingletonResource.new(entities, options, :path_names => @set.resources_path_names)
with_options :controller => resource.controller do |map|
map_associations(resource, options)
@@ -826,7 +852,7 @@ module ActionDispatch
actions.each do |action|
[method].flatten.each do |m|
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
- action_path ||= ActionController::Base.resources_path_names[action] || action
+ action_path ||= @set.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, { :force_id => true })
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 8de68b3174..0b7b09ee7a 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/hash/except'
+
module ActionDispatch
module Routing
class Mapper
@@ -36,7 +38,7 @@ module ActionDispatch
end
def to_route
- [ app, conditions, requirements, defaults, @options[:as] ]
+ [ app, conditions, requirements, defaults, @options[:as], @options[:anchor] ]
end
private
@@ -64,7 +66,7 @@ module ActionDispatch
# match "account/overview"
def using_match_shorthand?(args, options)
- args.present? && options.except(:via).empty? && !args.first.include?(':')
+ args.present? && options.except(:via, :anchor).empty? && !args.first.include?(':')
end
def normalize_path(path)
@@ -85,10 +87,9 @@ module ActionDispatch
end
def requirements
- @requirements ||= returning(@options[:constraints] || {}) do |requirements|
+ @requirements ||= (@options[:constraints] || {}).tap do |requirements|
requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints]
@options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) }
- requirements[:controller] ||= @set.controller_constraints
end
end
@@ -175,9 +176,15 @@ module ActionDispatch
end
def match(*args)
- @set.add_route(*Mapping.new(@set, @scope, args).to_route)
+ mapping = Mapping.new(@set, @scope, args).to_route
+ @set.add_route(*mapping)
self
end
+
+ def default_url_options=(options)
+ @set.default_url_options = options
+ end
+ alias_method :default_url_options, :default_url_options=
end
module HttpHelpers
@@ -283,7 +290,7 @@ module ActionDispatch
end
def namespace(path)
- scope(path.to_s, :name_prefix => path.to_s, :namespace => path.to_s) { yield }
+ scope(path.to_s, :name_prefix => path.to_s, :controller_namespace => path.to_s) { yield }
end
def constraints(constraints = {})
@@ -294,6 +301,7 @@ module ActionDispatch
options = args.extract_options!
options = (@scope[:options] || {}).merge(options)
+ options[:anchor] = true unless options.key?(:anchor)
if @scope[:name_prefix] && !options[:as].blank?
options[:as] = "#{@scope[:name_prefix]}_#{options[:as]}"
@@ -318,12 +326,12 @@ module ActionDispatch
parent ? "#{parent}_#{child}" : child
end
- def merge_namespace_scope(parent, child)
+ def merge_controller_namespace_scope(parent, child)
parent ? "#{parent}/#{child}" : child
end
def merge_controller_scope(parent, child)
- @scope[:namespace] ? "#{@scope[:namespace]}/#{child}" : child
+ @scope[:controller_namespace] ? "#{@scope[:controller_namespace]}/#{child}" : child
end
def merge_resources_path_names_scope(parent, child)
@@ -367,9 +375,9 @@ module ActionDispatch
def actions
if only = options[:only]
- only.map(&:to_sym)
+ Array(only).map(&:to_sym)
elsif except = options[:except]
- default_actions - except.map(&:to_sym)
+ default_actions - Array(except).map(&:to_sym)
else
default_actions
end
@@ -443,7 +451,7 @@ module ActionDispatch
def resource(*resources, &block)
options = resources.extract_options!
- if verify_common_behavior_for(:resource, resources, options, &block)
+ if apply_common_behavior_for(:resource, resources, options, &block)
return self
end
@@ -451,7 +459,10 @@ module ActionDispatch
scope(:path => resource.name.to_s, :controller => resource.controller) do
with_scope_level(:resource, resource) do
- yield if block_given?
+
+ scope(:name_prefix => resource.name.to_s) do
+ yield if block_given?
+ end
get :show if resource.actions.include?(:show)
post :create if resource.actions.include?(:create)
@@ -468,7 +479,7 @@ module ActionDispatch
def resources(*resources, &block)
options = resources.extract_options!
- if verify_common_behavior_for(:resources, resources, options, &block)
+ if apply_common_behavior_for(:resources, resources, options, &block)
return self
end
@@ -534,6 +545,21 @@ module ActionDispatch
end
end
+ def mount(app, options = nil)
+ if options
+ path = options.delete(:at)
+ else
+ options = app
+ app, path = options.find { |k, v| k.respond_to?(:call) }
+ options.delete(app) if app
+ end
+
+ raise "A rack application must be specified" unless path
+
+ match(path, options.merge(:to => app, :anchor => false))
+ self
+ end
+
def match(*args)
options = args.extract_options!
@@ -591,7 +617,7 @@ module ActionDispatch
path_names[name.to_sym] || name.to_s
end
- def verify_common_behavior_for(method, resources, options, &block)
+ def apply_common_behavior_for(method, resources, options, &block)
if resources.length > 1
resources.each { |r| send(method, r, options, &block) }
return true
diff --git a/actionpack/lib/action_dispatch/routing/route.rb b/actionpack/lib/action_dispatch/routing/route.rb
index e6e44d3546..6f37eadd6b 100644
--- a/actionpack/lib/action_dispatch/routing/route.rb
+++ b/actionpack/lib/action_dispatch/routing/route.rb
@@ -4,7 +4,7 @@ module ActionDispatch
attr_reader :app, :conditions, :defaults, :name
attr_reader :path, :requirements
- def initialize(app, conditions = {}, requirements = {}, defaults = {}, name = nil)
+ def initialize(app, conditions, requirements, defaults, name, anchor)
@app = app
@defaults = defaults
@name = name
@@ -17,7 +17,7 @@ module ActionDispatch
if path = conditions[:path_info]
@path = path
- conditions[:path_info] = ::Rack::Mount::Strexp.compile(path, requirements, SEPARATORS)
+ conditions[:path_info] = ::Rack::Mount::Strexp.compile(path, requirements, SEPARATORS, anchor)
end
@conditions = conditions.inject({}) { |h, (k, v)|
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index dcf98b729b..722be432c7 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -1,5 +1,6 @@
require 'rack/mount'
require 'forwardable'
+require 'action_dispatch/routing/deprecated_mapper'
module ActionDispatch
module Routing
@@ -11,8 +12,8 @@ module ActionDispatch
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
class Dispatcher
- def initialize(options = {})
- defaults = options[:defaults]
+ def initialize(options={})
+ @defaults = options[:defaults]
@glob_param = options.delete(:glob)
end
@@ -20,7 +21,8 @@ module ActionDispatch
params = env[PARAMETERS_KEY]
prepare_params!(params)
- unless controller = controller(params)
+ # Just raise undefined constant errors if a controller was specified as default.
+ unless controller = controller(params, @defaults.key?(:controller))
return [404, {'X-Cascade' => 'pass'}, []]
end
@@ -39,14 +41,13 @@ module ActionDispatch
end
end
- def controller(params)
+ def controller(params, raise_error=true)
if params && params.has_key?(:controller)
controller = "#{params[:controller].camelize}Controller"
ActiveSupport::Inflector.constantize(controller)
end
rescue NameError => e
- raise unless e.message.include?(controller)
- nil
+ raise ActionController::RoutingError, e.message, e.backtrace if raise_error
end
private
@@ -59,7 +60,6 @@ module ActionDispatch
end
end
-
# A NamedRouteCollection instance is a collection of named routes, and also
# maintains an anonymous module that can be used to install helpers for the
# named routes.
@@ -168,63 +168,25 @@ module ActionDispatch
selector = url_helper_name(name, kind)
hash_access_method = hash_access_name(name, kind)
- # We use module_eval to avoid leaks.
- #
- # def users_url(*args)
- # if args.empty? || Hash === args.first
- # options = hash_for_users_url(args.first || {})
- # else
- # options = hash_for_users_url(args.extract_options!)
- # default = default_url_options(options) if self.respond_to?(:default_url_options, true)
- # options = (default ||= {}).merge(options)
- #
- # keys = []
- # keys -= options.keys if args.size < keys.size - 1
- #
- # args = args.zip(keys).inject({}) do |h, (v, k)|
- # h[k] = v
- # h
- # end
- #
- # # Tell url_for to skip default_url_options
- # options[:use_defaults] = false
- # options.merge!(args)
- # end
- #
- # url_for(options)
- # end
@module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
def #{selector}(*args)
- if args.empty? || Hash === args.first
- options = #{hash_access_method}(args.first || {})
- else
- options = #{hash_access_method}(args.extract_options!)
- default = default_url_options(options) if self.respond_to?(:default_url_options, true)
- options = (default ||= {}).merge(options)
-
- keys = #{route.segment_keys.inspect}
- keys -= options.keys if args.size < keys.size - 1 # take format into account
-
- args = args.zip(keys).inject({}) do |h, (v, k)|
- h[k] = v
- h
- end
-
- # Tell url_for to skip default_url_options
- options[:use_defaults] = false
- options.merge!(args)
+ options = #{hash_access_method}(args.extract_options!)
+
+ if args.any?
+ options[:_positional_args] = args
+ options[:_positional_keys] = #{route.segment_keys.inspect}
end
url_for(options)
end
- protected :#{selector}
END_EVAL
helpers << selector
end
end
- attr_accessor :routes, :named_routes, :controller_namespaces
+ attr_accessor :routes, :named_routes
attr_accessor :disable_clear_and_finalize, :resources_path_names
+ attr_accessor :default_url_options
def self.default_resources_path_names
{ :new => 'new', :edit => 'edit' }
@@ -235,8 +197,10 @@ module ActionDispatch
self.named_routes = NamedRouteCollection.new
self.resources_path_names = self.class.default_resources_path_names.dup
self.controller_namespaces = Set.new
+ self.default_url_options = {}
@disable_clear_and_finalize = false
+ clear!
end
def draw(&block)
@@ -273,61 +237,155 @@ module ActionDispatch
named_routes.install(destinations, regenerate_code)
end
- def empty?
- routes.empty?
- end
+ def url_helpers
+ @url_helpers ||= begin
+ router = self
- CONTROLLER_REGEXP = /[_a-zA-Z0-9]+/
+ Module.new do
+ extend ActiveSupport::Concern
+ include UrlFor
- def controller_constraints
- @controller_constraints ||= begin
- namespaces = controller_namespaces + in_memory_controller_namespaces
- source = namespaces.map { |ns| "#{Regexp.escape(ns)}/#{CONTROLLER_REGEXP.source}" }
- source << CONTROLLER_REGEXP.source
- Regexp.compile(source.sort.reverse.join('|'))
+ # ROUTES TODO: install_helpers isn't great... can we make a module with the stuff that
+ # we can include?
+ # Yes plz - JP
+ included do
+ router.install_helpers(self)
+ end
+
+ define_method(:_router) { router }
+ end
end
end
- def in_memory_controller_namespaces
- namespaces = Set.new
- ActionController::Base.subclasses.each do |klass|
- controller_name = klass.underscore
- namespaces << controller_name.split('/')[0...-1].join('/')
- end
- namespaces.delete('')
- namespaces
+ def empty?
+ routes.empty?
end
- def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil)
- route = Route.new(app, conditions, requirements, defaults, name)
+ def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil, anchor = true)
+ route = Route.new(app, conditions, requirements, defaults, name, anchor)
@set.add_route(*route)
named_routes[name] = route if name
routes << route
route
end
- def options_as_params(options)
- # If an explicit :controller was given, always make :action explicit
- # too, so that action expiry works as expected for things like
- #
- # generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
- #
- # (the above is from the unit tests). In the above case, because the
- # controller was explicitly given, but no action, the action is implied to
- # be "index", not the recalled action of "show".
- #
- # great fun, eh?
-
- options_as_params = options.clone
- options_as_params[:action] ||= 'index' if options[:controller]
- options_as_params[:action] = options_as_params[:action].to_s if options_as_params[:action]
- options_as_params
- end
+ class Generator
+ attr_reader :options, :recall, :set, :script_name, :named_route
+
+ def initialize(options, recall, set, extras = false)
+ @script_name = options.delete(:script_name)
+ @named_route = options.delete(:use_route)
+ @options = options.dup
+ @recall = recall.dup
+ @set = set
+ @extras = extras
+
+ normalize_options!
+ normalize_controller_action_id!
+ use_relative_controller!
+ controller.sub!(%r{^/}, '') if controller
+ handle_nil_action!
+ end
+
+ def controller
+ @controller ||= @options[:controller]
+ end
+
+ def current_controller
+ @recall[:controller]
+ end
+
+ def use_recall_for(key)
+ if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key])
+ @options[key] = @recall.delete(key)
+ end
+ end
+
+ def normalize_options!
+ # If an explicit :controller was given, always make :action explicit
+ # too, so that action expiry works as expected for things like
+ #
+ # generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
+ #
+ # (the above is from the unit tests). In the above case, because the
+ # controller was explicitly given, but no action, the action is implied to
+ # be "index", not the recalled action of "show".
+
+ if options[:controller]
+ options[:action] ||= 'index'
+ options[:controller] = options[:controller].to_s
+ end
+
+ if options[:action]
+ options[:action] = options[:action].to_s
+ end
+ end
+
+ # This pulls :controller, :action, and :id out of the recall.
+ # The recall key is only used if there is no key in the options
+ # or if the key in the options is identical. If any of
+ # :controller, :action or :id is not found, don't pull any
+ # more keys from the recall.
+ def normalize_controller_action_id!
+ @recall[:action] ||= 'index' if current_controller
+
+ use_recall_for(:controller) or return
+ use_recall_for(:action) or return
+ use_recall_for(:id)
+ end
+
+ # if the current controller is "foo/bar/baz" and :controller => "baz/bat"
+ # is specified, the controller becomes "foo/baz/bat"
+ def use_relative_controller!
+ if !named_route && different_controller?
+ old_parts = current_controller.split('/')
+ size = controller.count("/") + 1
+ parts = old_parts[0...-size] << controller
+ @controller = @options[:controller] = parts.join("/")
+ end
+ end
+
+ # This handles the case of :action => nil being explicitly passed.
+ # It is identical to :action => "index"
+ def handle_nil_action!
+ if options.has_key?(:action) && options[:action].nil?
+ options[:action] = 'index'
+ end
+ recall[:action] = options.delete(:action) if options[:action] == 'index'
+ end
- def build_expiry(options, recall)
- recall.inject({}) do |expiry, (key, recalled_value)|
- expiry[key] = (options.key?(key) && options[key].to_param != recalled_value.to_param)
- expiry
+ def generate
+ error = ActionController::RoutingError.new("No route matches #{options.inspect}")
+ path, params = @set.generate(:path_info, named_route, options, recall, opts)
+
+ raise error unless path
+
+ params.reject! {|k,v| !v }
+
+ return [path, params.keys] if @extras
+
+ path << "?#{params.to_query}" if params.any?
+ "#{script_name}#{path}"
+ rescue Rack::Mount::RoutingError
+ raise error
+ end
+
+ def opts
+ parameterize = lambda do |name, value|
+ if name == :controller
+ value
+ elsif value.is_a?(Array)
+ value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
+ else
+ Rack::Mount::Utils.escape_uri(value.to_param)
+ end
+ end
+ {:parameterize => parameterize}
+ end
+
+ def different_controller?
+ return false unless current_controller
+ controller.to_param != current_controller.to_param
end
end
@@ -338,82 +396,44 @@ module ActionDispatch
end
def generate_extras(options, recall={})
- generate(options, recall, :generate_extras)
+ generate(options, recall, true)
end
- def generate(options, recall = {}, method = :generate)
- options, recall = options.dup, recall.dup
- named_route = options.delete(:use_route)
+ def generate(options, recall = {}, extras = false)
+ Generator.new(options, recall, @set, extras).generate
+ end
- options = options_as_params(options)
- expire_on = build_expiry(options, recall)
+ RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash]
- recall[:action] ||= 'index' if options[:controller] || recall[:controller]
+ def url_for(options)
+ options = default_url_options.merge(options || {})
- if recall[:controller] && (!options.has_key?(:controller) || options[:controller] == recall[:controller])
- options[:controller] = recall.delete(:controller)
+ handle_positional_args(options)
- if recall[:action] && (!options.has_key?(:action) || options[:action] == recall[:action])
- options[:action] = recall.delete(:action)
+ rewritten_url = ""
- if recall[:id] && (!options.has_key?(:id) || options[:id] == recall[:id])
- options[:id] = recall.delete(:id)
- end
- end
- end
-
- options[:controller] = options[:controller].to_s if options[:controller]
+ path_segments = options.delete(:_path_segments)
- if !named_route && expire_on[:controller] && options[:controller] && options[:controller][0] != ?/
- old_parts = recall[:controller].split('/')
- new_parts = options[:controller].split('/')
- parts = old_parts[0..-(new_parts.length + 1)] + new_parts
- options[:controller] = parts.join('/')
- end
+ unless options[:only_path]
+ rewritten_url << (options[:protocol] || "http")
+ rewritten_url << "://" unless rewritten_url.match("://")
+ rewritten_url << rewrite_authentication(options)
- options[:controller] = options[:controller][1..-1] if options[:controller] && options[:controller][0] == ?/
+ raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host]
- merged = options.merge(recall)
- if options.has_key?(:action) && options[:action].nil?
- options.delete(:action)
- recall[:action] = 'index'
+ rewritten_url << options[:host]
+ rewritten_url << ":#{options.delete(:port)}" if options.key?(:port)
end
- recall[:action] = options.delete(:action) if options[:action] == 'index'
-
- opts = {}
- opts[:parameterize] = lambda { |name, value|
- if name == :controller
- value
- elsif value.is_a?(Array)
- value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
- else
- Rack::Mount::Utils.escape_uri(value.to_param)
- end
- }
- unless result = @set.generate(:path_info, named_route, options, recall, opts)
- raise ActionController::RoutingError, "No route matches #{options.inspect}"
- end
+ path_options = options.except(*RESERVED_OPTIONS)
+ path_options = yield(path_options) if block_given?
+ path = generate(path_options, path_segments || {})
- path, params = result
- params.each do |k, v|
- if v
- params[k] = v
- else
- params.delete(k)
- end
- end
+ # ROUTES TODO: This can be called directly, so script_name should probably be set in the router
+ rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
+ rewritten_url << "##{Rack::Utils.escape(options[:anchor].to_param.to_s)}" if options[:anchor]
- if path && method == :generate_extras
- [path, params.keys]
- elsif path
- path << "?#{params.to_query}" if params.any?
- path
- else
- raise ActionController::RoutingError, "No route matches #{options.inspect}"
- end
- rescue Rack::Mount::RoutingError
- raise ActionController::RoutingError, "No route matches #{options.inspect}"
+ rewritten_url
end
def call(env)
@@ -431,9 +451,9 @@ module ActionDispatch
end
req = Rack::Request.new(env)
- @set.recognize(req) do |route, params|
+ @set.recognize(req) do |route, matches, params|
dispatcher = route.app
- if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params)
+ if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false)
dispatcher.prepare_params!(params)
return params
end
@@ -441,6 +461,30 @@ module ActionDispatch
raise ActionController::RoutingError, "No route matches #{path.inspect}"
end
+
+ private
+ def handle_positional_args(options)
+ return unless args = options.delete(:_positional_args)
+
+ keys = options.delete(:_positional_keys)
+ keys -= options.keys if args.size < keys.size - 1 # take format into account
+
+ args = args.zip(keys).inject({}) do |h, (v, k)|
+ h[k] = v
+ h
+ end
+
+ # Tell url_for to skip default_url_options
+ options.merge!(args)
+ end
+
+ def rewrite_authentication(options)
+ if options[:user] && options[:password]
+ "#{Rack::Utils.escape(options.delete(:user))}:#{Rack::Utils.escape(options.delete(:password))}@"
+ else
+ ""
+ end
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
new file mode 100644
index 0000000000..ec78f53fa6
--- /dev/null
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -0,0 +1,139 @@
+module ActionDispatch
+ module Routing
+ # In <b>routes.rb</b> one defines URL-to-controller mappings, but the reverse
+ # is also possible: an URL can be generated from one of your routing definitions.
+ # URL generation functionality is centralized in this module.
+ #
+ # See ActionDispatch::Routing and ActionController::Resources for general
+ # information about routing and routes.rb.
+ #
+ # <b>Tip:</b> If you need to generate URLs from your models or some other place,
+ # then ActionController::UrlFor is what you're looking for. Read on for
+ # an introduction.
+ #
+ # == URL generation from parameters
+ #
+ # As you may know, some functions - such as ActionController::Base#url_for
+ # and ActionView::Helpers::UrlHelper#link_to, can generate URLs given a set
+ # of parameters. For example, you've probably had the chance to write code
+ # like this in one of your views:
+ #
+ # <%= link_to('Click here', :controller => 'users',
+ # :action => 'new', :message => 'Welcome!') %>
+ #
+ # #=> Generates a link to: /users/new?message=Welcome%21
+ #
+ # link_to, and all other functions that require URL generation functionality,
+ # actually use ActionController::UrlFor under the hood. And in particular,
+ # they use the ActionController::UrlFor#url_for method. One can generate
+ # the same path as the above example by using the following code:
+ #
+ # include UrlFor
+ # url_for(:controller => 'users',
+ # :action => 'new',
+ # :message => 'Welcome!',
+ # :only_path => true)
+ # # => "/users/new?message=Welcome%21"
+ #
+ # Notice the <tt>:only_path => true</tt> part. This is because UrlFor has no
+ # information about the website hostname that your Rails app is serving. So if you
+ # want to include the hostname as well, then you must also pass the <tt>:host</tt>
+ # argument:
+ #
+ # include UrlFor
+ # url_for(:controller => 'users',
+ # :action => 'new',
+ # :message => 'Welcome!',
+ # :host => 'www.example.com') # Changed this.
+ # # => "http://www.example.com/users/new?message=Welcome%21"
+ #
+ # By default, all controllers and views have access to a special version of url_for,
+ # that already knows what the current hostname is. So if you use url_for in your
+ # controllers or your views, then you don't need to explicitly pass the <tt>:host</tt>
+ # argument.
+ #
+ # For convenience reasons, mailers provide a shortcut for ActionController::UrlFor#url_for.
+ # So within mailers, you only have to type 'url_for' instead of 'ActionController::UrlFor#url_for'
+ # in full. However, mailers don't have hostname information, and what's why you'll still
+ # have to specify the <tt>:host</tt> argument when generating URLs in mailers.
+ #
+ #
+ # == URL generation for named routes
+ #
+ # UrlFor also allows one to access methods that have been auto-generated from
+ # named routes. For example, suppose that you have a 'users' resource in your
+ # <b>routes.rb</b>:
+ #
+ # map.resources :users
+ #
+ # 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 by including ActionController::UrlFor in your class:
+ #
+ # class User < ActiveRecord::Base
+ # include ActionController::UrlFor
+ #
+ # def base_uri
+ # user_path(self)
+ # end
+ # end
+ #
+ # User.find(1).base_uri # => "/users/1"
+ #
+ module UrlFor
+ extend ActiveSupport::Concern
+
+ included do
+ # TODO: with_routing extends @controller with url_helpers, trickling down to including this module which overrides its default_url_options
+ unless method_defined?(:default_url_options)
+ # Including in a class uses an inheritable hash. Modules get a plain hash.
+ if respond_to?(:class_attribute)
+ class_attribute :default_url_options
+ else
+ mattr_accessor :default_url_options
+ remove_method :default_url_options
+ end
+
+ self.default_url_options = {}
+ end
+ end
+
+ def url_options
+ default_url_options
+ end
+
+ # Generate a url based on the options provided, default_url_options and the
+ # routes defined in routes.rb. The following options are supported:
+ #
+ # * <tt>:only_path</tt> - If true, the relative url is returned. Defaults to +false+.
+ # * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'.
+ # * <tt>:host</tt> - Specifies the host the link should be targeted at.
+ # If <tt>:only_path</tt> is false, this option must be
+ # provided either explicitly, or via +default_url_options+.
+ # * <tt>:port</tt> - Optionally specify the port to connect to.
+ # * <tt>:anchor</tt> - An anchor name to be appended to the path.
+ # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
+ #
+ # Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to
+ # +url_for+ is forwarded to the Routes module.
+ #
+ # Examples:
+ #
+ # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :port=>'8080' # => 'http://somehost.org:8080/tasks/testing'
+ # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok'
+ # url_for :controller => 'tasks', :action => 'testing', :trailing_slash=>true # => 'http://somehost.org/tasks/testing/'
+ # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33'
+ def url_for(options = nil)
+ case options
+ when String
+ options
+ when nil, Hash
+ _router.url_for(url_options.merge(options || {}))
+ else
+ polymorphic_url(options)
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index c2486d3730..937c9f48d2 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -132,16 +132,21 @@ module ActionDispatch
end
def normalize_argument_to_redirection(fragment)
- after_routing = @controller.url_for(fragment)
- if after_routing =~ %r{^\w+://.*}
- after_routing
- else
- # FIXME - this should probably get removed.
- if after_routing.first != '/'
- after_routing = '/' + after_routing
+ case fragment
+ when %r{^\w[\w\d+.-]*:.*}
+ fragment
+ when String
+ if fragment =~ %r{^\w[\w\d+.-]*:.*}
+ fragment
+ else
+ @request.protocol + @request.host_with_port + fragment
end
- @request.protocol + @request.host_with_port + after_routing
- end
+ when :back
+ raise RedirectBackError unless refer = @request.headers["Referer"]
+ refer
+ else
+ @controller.url_for(fragment)
+ end.gsub(/[\r\n]/, '')
end
def validate_request!
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 0c33539b4a..1d7e8090e4 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -80,7 +80,7 @@ module ActionDispatch
expected_path = "/#{expected_path}" unless expected_path[0] == ?/
# Load routes.rb if it hasn't been loaded.
- generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults)
+ generated_path, extra_keys = @router.generate_extras(options, defaults)
found_extras = options.reject {|k, v| ! extra_keys.include? k}
msg = build_message(message, "found extras <?>, not <?>", found_extras, extras)
@@ -125,7 +125,7 @@ module ActionDispatch
end
# A helper to make it easier to test different route configurations.
- # This method temporarily replaces ActionController::Routing::Routes
+ # This method temporarily replaces @router
# with a new RouteSet instance.
#
# The new instance is yielded to the passed block. Typically the block
@@ -142,22 +142,19 @@ module ActionDispatch
# end
#
def with_routing
- real_routes = ActionController::Routing::Routes
- ActionController::Routing.module_eval { remove_const :Routes }
-
- temporary_routes = ActionController::Routing::RouteSet.new
- ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
-
- yield temporary_routes
+ old_routes, @router = @router, ActionDispatch::Routing::RouteSet.new
+ old_controller, @controller = @controller, @controller.clone if @controller
+ _router = @router
+ @controller.singleton_class.send(:send, :include, @router.url_helpers) if @controller
+ yield @router
ensure
- if ActionController::Routing.const_defined? :Routes
- ActionController::Routing.module_eval { remove_const :Routes }
- end
- ActionController::Routing.const_set(:Routes, real_routes) if real_routes
+ @router = old_routes
+ @controller = old_controller if @controller
end
+ # ROUTES TODO: These assertions should really work in an integration context
def method_missing(selector, *args, &block)
- if @controller && ActionController::Routing::Routes.named_routes.helpers.include?(selector)
+ if @controller && @router.named_routes.helpers.include?(selector)
@controller.send(selector, *args, &block)
else
super
@@ -174,7 +171,7 @@ module ActionDispatch
request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method
request.path = path
- params = ActionController::Routing::Routes.recognize_path(path, { :method => request.method })
+ params = @router.recognize_path(path, { :method => request.method })
request.path_parameters = params.with_indifferent_access
request
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 2093bb3a0e..0aff4250c1 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -1,6 +1,6 @@
require 'stringio'
require 'uri'
-require 'active_support/core_ext/object/metaclass'
+require 'active_support/core_ext/object/singleton_class'
require 'rack/test'
module ActionDispatch
@@ -162,12 +162,31 @@ module ActionDispatch
# A running counter of the number of requests processed.
attr_accessor :request_count
+ include ActionDispatch::Routing::UrlFor
+
# Create and initialize a new Session instance.
def initialize(app)
@app = app
+
+ # If the app is a Rails app, make url_helpers available on the session
+ # This makes app.url_for and app.foo_path available in the console
+ if app.respond_to?(:routes) && app.routes.respond_to?(:url_helpers)
+ singleton_class.class_eval { include app.routes.url_helpers }
+ end
+
reset!
end
+ def url_options
+ opts = super.reverse_merge(
+ :host => host,
+ :protocol => https? ? "https" : "http"
+ )
+
+ opts.merge!(:port => 443) if !opts.key?(:port) && https?
+ opts
+ end
+
# Resets the instance. This can be used to reset the state information
# in an existing session instance, so it can be used from a clean-slate
# condition.
@@ -187,12 +206,10 @@ module ActionDispatch
unless defined? @named_routes_configured
# install the named routes in this session instance.
- klass = metaclass
- ActionController::Routing::Routes.install_helpers(klass)
+ klass = singleton_class
# the helpers are made protected by default--we make them public for
# easier access during testing and troubleshooting.
- klass.module_eval { public *ActionController::Routing::Routes.named_routes.helpers }
@named_routes_configured = true
end
end
@@ -221,14 +238,6 @@ module ActionDispatch
@host = name
end
- # Returns the URL for the given options, according to the rules specified
- # in the application's routes.
- def url_for(options)
- controller ?
- controller.url_for(options) :
- generic_url_rewriter.rewrite(options)
- end
-
private
# Performs the actual request.
@@ -273,26 +282,14 @@ module ActionDispatch
@request_count += 1
@request = ActionDispatch::Request.new(session.last_request.env)
- @response = ActionDispatch::TestResponse.from_response(@mock_session.last_response)
+ response = @mock_session.last_response
+ @response = ActionDispatch::TestResponse.new(response.status, response.headers, response.body)
@html_document = nil
@controller = session.last_request.env['action_controller.instance']
return response.status
end
-
- # Get a temporary URL writer object
- def generic_url_rewriter
- env = {
- 'REQUEST_METHOD' => "GET",
- 'QUERY_STRING' => "",
- "REQUEST_URI" => "/",
- "HTTP_HOST" => host,
- "SERVER_PORT" => https? ? "443" : "80",
- "HTTPS" => https? ? "on" : "off"
- }
- ActionController::UrlRewriter.new(ActionDispatch::Request.new(env), {})
- end
end
module Runner
@@ -364,6 +361,14 @@ module ActionDispatch
end
end
+ extend ActiveSupport::Concern
+ include ActionDispatch::Routing::UrlFor
+
+ def url_options
+ reset! unless @integration_session
+ @integration_session.url_options
+ end
+
# Delegate unhandled messages to the current session instance.
def method_missing(sym, *args, &block)
reset! unless @integration_session
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
index eae703e1b6..d4eecac2de 100644
--- a/actionpack/lib/action_dispatch/testing/test_process.rb
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -1,3 +1,5 @@
+require 'action_dispatch/middleware/flash'
+
module ActionDispatch
module TestProcess
def assigns(key = nil)
diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb
index 67f89e1627..72a1cd30ad 100644
--- a/actionpack/lib/action_pack/version.rb
+++ b/actionpack/lib/action_pack/version.rb
@@ -1,9 +1,10 @@
-module ActionPack #:nodoc:
+module ActionPack
module VERSION #:nodoc:
MAJOR = 3
MINOR = 0
- TINY = "0.beta1"
+ TINY = 0
+ BUILD = "beta1"
- STRING = [MAJOR, MINOR, TINY].join('.')
+ STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
end
end
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index f5035fe45a..afe6386105 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -37,15 +37,18 @@ module ActionView
autoload :Helpers
autoload_under "render" do
+ autoload :Layouts
autoload :Partials
autoload :Rendering
end
- autoload :MissingTemplate, 'action_view/base'
- autoload :Resolver, 'action_view/template/resolver'
- autoload :PathResolver, 'action_view/template/resolver'
- autoload :PathSet, 'action_view/paths'
- autoload :FileSystemResolverWithFallback, 'action_view/template/resolver'
+ autoload :Base
+ autoload :LookupContext
+ autoload :MissingTemplate, 'action_view/base'
+ autoload :Resolver, 'action_view/template/resolver'
+ autoload :PathResolver, 'action_view/template/resolver'
+ autoload :FileSystemResolver, 'action_view/template/resolver'
+ autoload :PathSet, 'action_view/paths'
autoload :TemplateError, 'action_view/template/error'
autoload :TemplateHandler, 'action_view/template'
@@ -55,7 +58,7 @@ module ActionView
autoload :TestCase, 'action_view/test_case'
end
+require 'active_support/i18n'
require 'active_support/core_ext/string/output_safety'
-require 'action_view/base'
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 4096c296c3..ffe3060404 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -11,7 +11,7 @@ module ActionView #:nodoc:
def initialize(paths, path, details, partial)
@path = path
- display_paths = paths.compact.join(":")
+ display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ")
template_type = if partial
"partial"
elsif path =~ /layouts/i
@@ -20,7 +20,7 @@ module ActionView #:nodoc:
'template'
end
- super("Missing #{template_type} #{path} with #{details.inspect} in view path #{display_paths}")
+ super("Missing #{template_type} #{path} with #{details.inspect} in view paths #{display_paths}")
end
end
@@ -173,81 +173,43 @@ module ActionView #:nodoc:
module Subclasses
end
- include Helpers, Rendering, Partials, ::ERB::Util
+ include Helpers, Rendering, Partials, Layouts, ::ERB::Util, Context
+ extend ActiveSupport::Memoizable
- def config
- self.config = DEFAULT_CONFIG unless @config
- @config
- end
-
- def config=(config)
- @config = ActiveSupport::OrderedOptions.new.merge(config)
- end
-
- extend ActiveSupport::Memoizable
-
- attr_accessor :base_path, :assigns, :template_extension, :formats
- attr_internal :captures
+ ActionView.run_base_hooks(self)
- def reset_formats(formats)
- @formats = formats
-
- if defined?(AbstractController::HashKey)
- # This is expensive, but we need to reset this when the format is updated,
- # which currently only happens
- Thread.current[:format_locale_key] =
- AbstractController::HashKey.get(self.class, formats, I18n.locale)
- end
- end
-
- class << self
- delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
- delegate :logger, :to => 'ActionController::Base', :allow_nil => true
- end
-
- @@debug_rjs = false
- ##
- # :singleton-method:
# Specify whether RJS responses should be wrapped in a try/catch block
# that alert()s the caught exception (and then re-raises it).
cattr_accessor :debug_rjs
+ @@debug_rjs = false
- # Specify whether templates should be cached. Otherwise the file we be read everytime it is accessed.
- # Automatically reloading templates are not thread safe and should only be used in development mode.
- @@cache_template_loading = nil
- cattr_accessor :cache_template_loading
-
- # :nodoc:
- def self.xss_safe?
- true
- end
+ class_attribute :helpers
+ attr_reader :helpers
- def self.cache_template_loading?
- ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading)
+ class << self
+ delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
+ delegate :logger, :to => 'ActionController::Base', :allow_nil => true
end
- attr_internal :request, :layout
+ attr_accessor :base_path, :assigns, :template_extension, :lookup_context
+ attr_internal :captures, :request, :layout, :controller, :template, :config
- def controller_path
- @controller_path ||= controller && controller.controller_path
- end
+ delegate :find, :exists?, :formats, :formats=, :locale, :locale=,
+ :view_paths, :view_paths=, :with_fallbacks, :update_details, :to => :lookup_context
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
:flash, :action_name, :controller_name, :to => :controller
delegate :logger, :to => :controller, :allow_nil => true
- delegate :find, :to => :view_paths
-
- include Context
+ def self.xss_safe? #:nodoc:
+ true
+ end
def self.process_view_paths(value)
ActionView::PathSet.new(Array(value))
end
- class_attribute :helpers
- attr_reader :helpers
-
def self.for_controller(controller)
@views ||= {}
@@ -275,26 +237,26 @@ module ActionView #:nodoc:
klass = self
end
- klass.new(controller.class.view_paths, {}, controller)
+ klass.new(controller.lookup_context, {}, controller)
end
- def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc:
+ def initialize(lookup_context = nil, assigns_for_first_render = {}, controller = nil, formats = nil) #:nodoc:
@config = nil
- @formats = formats
@assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) }
@helpers = self.class.helpers || Module.new
@_controller = controller
- @_content_for = Hash.new {|h,k| h[k] = ActiveSupport::SafeBuffer.new }
+ @_config = ActiveSupport::InheritableOptions.new(controller.config) if controller
+ @_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
@_virtual_path = nil
- self.view_paths = view_paths
- end
- attr_internal :controller, :template
- attr_reader :view_paths
+ @lookup_context = lookup_context.is_a?(ActionView::LookupContext) ?
+ lookup_context : ActionView::LookupContext.new(lookup_context)
+ @lookup_context.formats = formats if formats
+ end
- def view_paths=(paths)
- @view_paths = self.class.process_view_paths(paths)
+ def controller_path
+ @controller_path ||= controller && controller.controller_path
end
def punctuate_body!(part)
diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb
index b4f649385a..e359b0bdac 100644
--- a/actionpack/lib/action_view/helpers.rb
+++ b/actionpack/lib/action_view/helpers.rb
@@ -10,6 +10,7 @@ module ActionView #:nodoc:
autoload :CsrfHelper, 'action_view/helpers/csrf_helper'
autoload :DateHelper, 'action_view/helpers/date_helper'
autoload :DebugHelper, 'action_view/helpers/debug_helper'
+ autoload :DeprecatedBlockHelpers, 'action_view/helpers/deprecated_block_helpers'
autoload :FormHelper, 'action_view/helpers/form_helper'
autoload :FormOptionsHelper, 'action_view/helpers/form_options_helper'
autoload :FormTagHelper, 'action_view/helpers/form_tag_helper'
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index e106bb0897..4e12cdab54 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -5,9 +5,11 @@ require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/kernel/reporting'
module ActionView
- class Base
- @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
- cattr_accessor :field_error_proc
+ ActionView.base_hook do
+ class ActionView::Base
+ @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
+ cattr_accessor :field_error_proc
+ end
end
module Helpers
@@ -80,13 +82,13 @@ module ActionView
record = convert_to_model(record)
options = options.symbolize_keys
- options[:action] ||= record.new_record? ? "create" : "update"
+ options[:action] ||= record.persisted? ? "update" : "create"
action = url_for(:action => options[:action], :id => record)
submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize
contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil)
- contents.safe_concat hidden_field(record_name, :id) unless record.new_record?
+ contents.safe_concat hidden_field(record_name, :id) if record.persisted?
contents.safe_concat all_input_tags(record, record_name, options)
yield contents if block_given?
contents.safe_concat submit_tag(submit_value)
@@ -127,7 +129,7 @@ module ActionView
if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
(errors = obj.errors[method])
content_tag("div",
- "#{options[:prepend_text]}#{ERB::Util.html_escape(errors.first)}#{options[:append_text]}",
+ (options[:prepend_text].html_safe << errors.first).safe_concat(options[:append_text]),
:class => options[:css_class]
)
else
@@ -226,16 +228,16 @@ module ActionView
error_messages = objects.sum do |object|
object.errors.full_messages.map do |msg|
- content_tag(:li, ERB::Util.html_escape(msg))
+ content_tag(:li, msg)
end
- end.join
+ end.join.html_safe
contents = ''
contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
contents << content_tag(:p, message) unless message.blank?
contents << content_tag(:ul, error_messages)
- content_tag(:div, contents, html)
+ content_tag(:div, contents.html_safe, html)
end
else
''
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 96976ce45f..0c488b6793 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -11,7 +11,7 @@ module ActionView
# the assets exist before linking to them:
#
# image_tag("rails.png")
- # # => <img alt="Rails src="/images/rails.png?1230601161" />
+ # # => <img alt="Rails" src="/images/rails.png?1230601161" />
# stylesheet_link_tag("application")
# # => <link href="/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
#
@@ -133,13 +133,6 @@ module ActionView
# change. You can use something like Live HTTP Headers for Firefox to verify
# that the cache is indeed working.
module AssetTagHelper
- assets_dir = defined?(Rails.public_path) ? Rails.public_path : "public"
- ActionView::DEFAULT_CONFIG = {
- :assets_dir => assets_dir,
- :javascripts_dir => "#{assets_dir}/javascripts",
- :stylesheets_dir => "#{assets_dir}/stylesheets",
- }
-
JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls', 'rails'].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
# Returns a link tag that browsers and news readers can use to auto-detect
@@ -530,7 +523,7 @@ module ActionView
options.symbolize_keys!
src = options[:src] = path_to_image(source)
- options[:alt] ||= File.basename(src, '.*').split('.').first.to_s.capitalize
+ options[:alt] ||= File.basename(src, '.*').capitalize
if size = options.delete(:size)
options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
@@ -648,8 +641,8 @@ module ActionView
source = rewrite_asset_path(source)
if has_request && include_host
- unless source =~ %r{^#{ActionController::Base.relative_url_root}/}
- source = "#{ActionController::Base.relative_url_root}#{source}"
+ unless source =~ %r{^#{controller.config.relative_url_root}/}
+ source = "#{controller.config.relative_url_root}#{source}"
end
end
end
@@ -677,7 +670,7 @@ module ActionView
# or the value returned from invoking the proc if it's a proc or the value from
# invoking call if it's an object responding to call.
def compute_asset_host(source)
- if host = ActionController::Base.asset_host
+ if host = config.asset_host
if host.is_a?(Proc) || host.respond_to?(:call)
case host.is_a?(Proc) ? host.arity : host.method(:call).arity
when 2
diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
index 9951e11a37..58c3a8752e 100644
--- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
@@ -8,7 +8,7 @@ module ActionView
# Full usage example:
#
# config/routes.rb:
- # ActionController::Routing::Routes.draw do |map|
+ # Basecamp::Application.routes.draw do |map|
# map.resources :posts
# map.root :controller => "posts"
# end
@@ -114,7 +114,7 @@ module ActionView
feed_opts.merge!(options).reject!{|k,v| !k.to_s.match(/^xml/)}
xml.feed(feed_opts) do
- xml.id(options[:id] || "tag:#{request.host},#{options[:schema_date]}:#{request.request_uri.split(".")[0]}")
+ xml.id(options[:id] || "tag:#{request.host},#{options[:schema_date]}:#{request.fullpath.split(".")[0]}")
xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:root_url] || (request.protocol + request.host_with_port))
xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:url] || request.url)
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 8c48300ed3..75fc2fddeb 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -30,14 +30,10 @@ module ActionView
# <b><%= @greeting %></b>
# </body></html>
#
- def capture(*args, &block)
- # Return captured buffer in erb.
- if block_called_from_erb?(block)
- with_output_buffer { block.call(*args) }
- else
- # Return block result otherwise, but protect buffer also.
- with_output_buffer { return block.call(*args) }
- end
+ def capture(*args)
+ value = nil
+ buffer = with_output_buffer { value = yield *args }
+ buffer.presence || value
end
# Calling content_for stores a block of markup in an identifier for later use.
@@ -143,7 +139,7 @@ module ActionView
# Defaults to a new empty string.
def with_output_buffer(buf = nil) #:nodoc:
unless buf
- buf = ActiveSupport::SafeBuffer.new
+ buf = ActionView::OutputBuffer.new
buf.force_encoding(output_buffer.encoding) if buf.respond_to?(:force_encoding)
end
self.output_buffer, old_buffer = buf, output_buffer
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 8be2f76bd6..42018ee261 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -1,5 +1,6 @@
require "date"
require 'action_view/helpers/tag_helper'
+require 'active_support/core_ext/hash/slice'
module ActionView
module Helpers
@@ -815,7 +816,7 @@ module ActionView
tag_options[:selected] = "selected" if selected == i
select_options << content_tag(:option, value, tag_options)
end
- select_options.join("\n") + "\n"
+ (select_options.join("\n") + "\n").html_safe
end
# Builds select tag from date type and html select options
@@ -833,9 +834,9 @@ module ActionView
select_html = "\n"
select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
- select_html << select_options_as_html.to_s
+ select_html << select_options_as_html
- (content_tag(:select, select_html, select_options) + "\n").html_safe
+ (content_tag(:select, select_html.html_safe, select_options) + "\n").html_safe
end
# Builds a prompt option tag with supplied options or from default options
@@ -865,7 +866,7 @@ module ActionView
:id => input_id_from_type(type),
:name => input_name_from_type(type),
:value => value
- }) + "\n").html_safe
+ }.merge(@html_options.slice(:disabled))) + "\n").html_safe
end
# Returns the name attribute for the input tag
@@ -907,7 +908,7 @@ module ActionView
when :hour
(@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
when :minute
- @options[:time_separator]
+ @options[:discard_minute] ? "" : @options[:time_separator]
when :second
@options[:include_seconds] ? @options[:time_separator] : ""
end
diff --git a/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb b/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb
new file mode 100644
index 0000000000..3d0657e873
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb
@@ -0,0 +1,52 @@
+module ActionView
+ module Helpers
+ module DeprecatedBlockHelpers
+ extend ActiveSupport::Concern
+
+ include ActionView::Helpers::TagHelper
+ include ActionView::Helpers::TextHelper
+ include ActionView::Helpers::JavaScriptHelper
+ include ActionView::Helpers::FormHelper
+
+ def content_tag(*, &block)
+ block_called_from_erb?(block) ? safe_concat(super) : super
+ end
+
+ def javascript_tag(*, &block)
+ block_called_from_erb?(block) ? safe_concat(super) : super
+ end
+
+ def form_for(*, &block)
+ block_called_from_erb?(block) ? safe_concat(super) : super
+ end
+
+ def form_tag(*, &block)
+ block_called_from_erb?(block) ? safe_concat(super) : super
+ end
+
+ def fields_for(*, &block)
+ block_called_from_erb?(block) ? safe_concat(super) : super
+ end
+
+ def field_set_tag(*, &block)
+ block_called_from_erb?(block) ? safe_concat(super) : super
+ end
+
+ BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
+
+ if RUBY_VERSION < '1.9.0'
+ # Check whether we're called from an erb template.
+ # We'd return a string in any other case, but erb <%= ... %>
+ # can't take an <% end %> later on, so we have to use <% ... %>
+ # and implicitly concat.
+ def block_called_from_erb?(block)
+ block && eval(BLOCK_CALLED_FROM_ERB, block)
+ end
+ else
+ def block_called_from_erb?(block)
+ block && eval(BLOCK_CALLED_FROM_ERB, block.binding)
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 305d6b3128..7293145964 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -92,6 +92,10 @@ module ActionView
# link:classes/ActionView/Helpers/DateHelper.html, and
# link:classes/ActionView/Helpers/ActiveRecordHelper.html
module FormHelper
+ extend ActiveSupport::Concern
+
+ include FormTagHelper
+
# Creates a form and a scope around a specific model object that is used
# as a base for questioning about values for the fields.
#
@@ -309,21 +313,20 @@ module ActionView
options[:html][:remote] = true if options.delete(:remote)
- safe_concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
- fields_for(object_name, *(args << options), &proc)
- safe_concat('</form>')
+ output = form_tag(options.delete(:url) || {}, options.delete(:html) || {})
+ output << fields_for(object_name, *(args << options), &proc)
+ output.safe_concat('</form>')
end
def apply_form_for_options!(object_or_array, options) #:nodoc:
object = object_or_array.is_a?(Array) ? object_or_array.last : object_or_array
-
object = convert_to_model(object)
html_options =
- if object.respond_to?(:new_record?) && object.new_record?
- { :class => dom_class(object, :new), :id => dom_id(object), :method => :post }
- else
+ if object.respond_to?(:persisted?) && object.persisted?
{ :class => dom_class(object, :edit), :id => dom_id(object, :edit), :method => :put }
+ else
+ { :class => dom_class(object, :new), :id => dom_id(object), :method => :post }
end
options[:html] ||= {}
@@ -529,7 +532,10 @@ module ActionView
end
builder = options[:builder] || ActionView::Base.default_form_builder
- yield builder.new(object_name, object, self, options, block)
+
+ with_output_buffer do
+ yield builder.new(object_name, object, self, options, block)
+ end
end
# Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
@@ -1150,7 +1156,7 @@ module ActionView
def submit_default_value
object = @object.respond_to?(:to_model) ? @object.to_model : @object
- key = object ? (object.new_record? ? :create : :update) : :submit
+ key = object ? (object.persisted? ? :update : :create) : :submit
model = if object.class.respond_to?(:model_name)
object.class.model_name.human
@@ -1176,7 +1182,7 @@ module ActionView
association = args.shift
association = association.to_model if association.respond_to?(:to_model)
- if association.respond_to?(:new_record?)
+ if association.respond_to?(:persisted?)
association = [association] if @object.send(association_name).is_a?(Array)
elsif !association.is_a?(Array)
association = @object.send(association_name)
@@ -1184,9 +1190,11 @@ module ActionView
if association.is_a?(Array)
explicit_child_index = options[:child_index]
- association.map do |child|
- fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, options, block)
- end.join
+ output = ActiveSupport::SafeBuffer.new
+ association.each do |child|
+ output << fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, options, block)
+ end
+ output
elsif association
fields_for_nested_model(name, association, options, block)
end
@@ -1195,13 +1203,13 @@ module ActionView
def fields_for_nested_model(name, object, options, block)
object = object.to_model if object.respond_to?(:to_model)
- if object.new_record?
- @template.fields_for(name, object, options, &block)
- else
+ if object.persisted?
@template.fields_for(name, object, options) do |builder|
block.call(builder)
@template.concat builder.hidden_field(:id) unless builder.emitted_hidden_id?
end
+ else
+ @template.fields_for(name, object, options, &block)
end
end
@@ -1212,8 +1220,10 @@ module ActionView
end
end
- class Base
- cattr_accessor :default_form_builder
- @@default_form_builder = ::ActionView::Helpers::FormBuilder
+ ActionView.base_hook do
+ class ActionView::Base
+ cattr_accessor :default_form_builder
+ @@default_form_builder = ::ActionView::Helpers::FormBuilder
+ end
end
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 21acfbbee8..4c523d4b20 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -97,7 +97,9 @@ module ActionView
# </select>
#
module FormOptionsHelper
+ # ERB::Util can mask some helpers like textilize. Make sure to include them.
include ERB::Util
+ include TextHelper
# Create a select tag and a series of contained option tags for the provided object and method.
# The option currently held by the object will be selected, provided that the object is available.
@@ -572,10 +574,9 @@ module ActionView
end
if value.blank? && options[:prompt]
prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
- "<option value=\"\">#{prompt}</option>\n" + option_tags
- else
- option_tags
+ option_tags = "<option value=\"\">#{prompt}</option>\n" + option_tags
end
+ option_tags.html_safe
end
end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 9d76870646..07694f5ebb 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -10,6 +10,11 @@ module ActionView
# NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
# <tt>:disabled => true</tt> will give <tt>disabled="disabled"</tt>.
module FormTagHelper
+ extend ActiveSupport::Concern
+
+ include UrlHelper
+ include TextHelper
+
# Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
# ActionController::Base#url_for. The method for the form defaults to POST.
#
@@ -90,9 +95,9 @@ module ActionView
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
if blank = options.delete(:include_blank)
if blank.kind_of?(String)
- option_tags = "<option value=\"\">#{blank}</option>" + option_tags
+ option_tags = "<option value=\"\">#{blank}</option>".html_safe + option_tags
else
- option_tags = "<option value=\"\"></option>" + option_tags
+ option_tags = "<option value=\"\"></option>".html_safe + option_tags
end
end
content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
@@ -279,7 +284,7 @@ module ActionView
escape = options.key?("escape") ? options.delete("escape") : true
content = html_escape(content) if escape
- content_tag :textarea, content, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
+ content_tag :textarea, content.html_safe, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
end
# Creates a check box form input tag.
@@ -441,10 +446,10 @@ module ActionView
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
def field_set_tag(legend = nil, options = nil, &block)
content = capture(&block)
- safe_concat(tag(:fieldset, options, true))
- safe_concat(content_tag(:legend, legend)) unless legend.blank?
- concat(content)
- safe_concat("</fieldset>")
+ output = tag(:fieldset, options, true)
+ output.safe_concat(content_tag(:legend, legend)) unless legend.blank?
+ output.concat(content)
+ output.safe_concat("</fieldset>")
end
private
@@ -477,9 +482,10 @@ module ActionView
def form_tag_in_block(html_options, &block)
content = capture(&block)
- safe_concat(form_tag_html(html_options))
- concat(content)
- safe_concat("</form>")
+ output = ActiveSupport::SafeBuffer.new
+ output.safe_concat(form_tag_html(html_options))
+ output << content
+ output.safe_concat("</form>")
end
def token_tag
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index 0a901b2d2b..07eee3b399 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -83,17 +83,11 @@ module ActionView
content_or_options_with_block
end
- tag = content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
-
- if block_called_from_erb?(block)
- safe_concat(tag)
- else
- tag
- end
+ content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
end
def javascript_cdata_section(content) #:nodoc:
- "\n//#{cdata_section("\n#{content}\n//")}\n"
+ "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe
end
end
end
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 3d3502a08b..46e41bc406 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -28,27 +28,25 @@ module ActionView
# number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
# => +1.123.555.1234 x 1343
def number_to_phone(number, options = {})
- number = number.to_s.strip unless number.nil?
+ return nil if number.nil?
+
+ number = number.to_s.strip
options = options.symbolize_keys
area_code = options[:area_code] || nil
delimiter = options[:delimiter] || "-"
extension = options[:extension].to_s.strip || nil
country_code = options[:country_code] || nil
- begin
- str = ""
- str << "+#{country_code}#{delimiter}" unless country_code.blank?
- str << if area_code
- number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
- else
- number.gsub!(/([0-9]{0,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
- number.starts_with?('-') ? number.slice!(1..-1) : number
- end
- str << " x #{extension}" unless extension.blank?
- str
- rescue
- number
+ str = ""
+ str << "+#{country_code}#{delimiter}" unless country_code.blank?
+ str << if area_code
+ number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
+ else
+ number.gsub!(/([0-9]{0,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
+ number.starts_with?('-') ? number.slice!(1..-1) : number
end
+ str << " x #{extension}" unless extension.blank?
+ str
end
# Formats a +number+ into a currency string (e.g., $13.65). You can customize the format
@@ -87,13 +85,14 @@ module ActionView
format = options[:format] || defaults[:format]
separator = '' if precision == 0
- begin
- format.gsub(/%n/, number_with_precision(number,
- :precision => precision,
- :delimiter => delimiter,
- :separator => separator)
- ).gsub(/%u/, unit).html_safe
- rescue
+ value = number_with_precision(number,
+ :precision => precision,
+ :delimiter => delimiter,
+ :separator => separator)
+
+ if value
+ format.gsub(/%n/, value).gsub(/%u/, unit).html_safe
+ else
number
end
end
@@ -122,14 +121,11 @@ module ActionView
separator = options[:separator] || defaults[:separator]
delimiter = options[:delimiter] || defaults[:delimiter]
- begin
- number_with_precision(number,
- :precision => precision,
- :separator => separator,
- :delimiter => delimiter) + "%"
- rescue
- number
- end
+ value = number_with_precision(number,
+ :precision => precision,
+ :separator => separator,
+ :delimiter => delimiter)
+ value ? value + "%" : number
end
# Formats a +number+ with grouped thousands using +delimiter+ (e.g., 12,324). You can
@@ -168,11 +164,11 @@ module ActionView
delimiter ||= (options[:delimiter] || defaults[:delimiter])
separator ||= (options[:separator] || defaults[:separator])
- begin
- parts = number.to_s.split('.')
+ parts = number.to_s.split('.')
+ if parts[0]
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
parts.join(separator)
- rescue
+ else
number
end
end
@@ -216,11 +212,17 @@ module ActionView
delimiter ||= (options[:delimiter] || defaults[:delimiter])
begin
+ value = Float(number)
+ rescue ArgumentError, TypeError
+ value = nil
+ end
+
+ if value
rounded_number = BigDecimal.new((Float(number) * (10 ** precision)).to_s).round.to_f / 10 ** precision
number_with_delimiter("%01.#{precision}f" % rounded_number,
:separator => separator,
:delimiter => delimiter)
- rescue
+ else
number
end
end
@@ -293,17 +295,13 @@ module ActionView
unit_key = STORAGE_UNITS[exponent]
unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
- begin
- escaped_separator = Regexp.escape(separator)
- formatted_number = number_with_precision(number,
- :precision => precision,
- :separator => separator,
- :delimiter => delimiter
- ).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
- storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
- rescue
- number
- end
+ escaped_separator = Regexp.escape(separator)
+ formatted_number = number_with_precision(number,
+ :precision => precision,
+ :separator => separator,
+ :delimiter => delimiter
+ ).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
+ storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
end
end
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 51510449bd..4d6ea7dfb2 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -182,9 +182,11 @@ module ActionView
def initialize(context, &block) #:nodoc:
context._evaluate_assigns_and_ivars
@context, @lines = context, []
- include_helpers_from_context
- @context.with_output_buffer(@lines) do
- @context.instance_exec(self, &block)
+ @context.update_details(:formats => [:js, :html]) do
+ include_helpers_from_context
+ @context.with_output_buffer(@lines) do
+ @context.instance_exec(self, &block)
+ end
end
end
@@ -569,15 +571,19 @@ module ActionView
end
end
- def render(*options_for_render)
- old_formats = @context && @context.formats
+ def render(*options)
+ with_formats(:html) do
+ case option = options.first
+ when Hash
+ @context.render(*options)
+ else
+ option.to_s
+ end
+ end
+ end
- @context.reset_formats([:html]) if @context
- Hash === options_for_render.first ?
- @context.render(*options_for_render) :
- options_for_render.first.to_s
- ensure
- @context.reset_formats(old_formats) if @context
+ def with_formats(*args)
+ @context ? @context.update_details(:formats => args) { yield } : yield
end
def javascript_object_for(object)
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index ee10f8f3bb..8ae2e5f28f 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -7,6 +7,9 @@ module ActionView
module TagHelper
include ERB::Util
+ extend ActiveSupport::Concern
+ include CaptureHelper
+
BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked autobuffer
autoplay controls loop selected hidden scoped async
defer reversed ismap seemless muted required
@@ -69,13 +72,7 @@ module ActionView
def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
if block_given?
options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
- content_tag = content_tag_string(name, capture(&block), options, escape)
-
- if block_called_from_erb?(block)
- safe_concat(content_tag)
- else
- content_tag
- end
+ content_tag_string(name, capture(&block), options, escape)
else
content_tag_string(name, content_or_options_with_block, options, escape)
end
@@ -109,25 +106,10 @@ module ActionView
end
private
- BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
-
- if RUBY_VERSION < '1.9.0'
- # Check whether we're called from an erb template.
- # We'd return a string in any other case, but erb <%= ... %>
- # can't take an <% end %> later on, so we have to use <% ... %>
- # and implicitly concat.
- def block_called_from_erb?(block)
- block && eval(BLOCK_CALLED_FROM_ERB, block)
- end
- else
- def block_called_from_erb?(block)
- block && eval(BLOCK_CALLED_FROM_ERB, block.binding)
- end
- end
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
- "<#{name}#{tag_options}>#{content}</#{name}>".html_safe
+ ("<#{name}#{tag_options}>".html_safe << content.to_s).safe_concat("</#{name}>")
end
def tag_options(options, escape = true)
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index c348ea7a0d..8a89ee58a0 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -12,9 +12,10 @@ module ActionView
# prepend the key with a period, nothing is converted.
def translate(key, options = {})
options[:raise] = true
- I18n.translate(scope_key_by_partial(key), options).html_safe
+ translation = I18n.translate(scope_key_by_partial(key), options)
+ translation.is_a?(Array) ? translation.map { |entry| entry.html_safe } : translation.html_safe
rescue I18n::MissingTranslationData => e
- keys = I18n.send(:normalize_translation_keys, e.locale, e.key, e.options[:scope])
+ keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
content_tag('span', keys.join(', '), :class => 'translation_missing')
end
alias :t :translate
@@ -28,7 +29,7 @@ module ActionView
private
def scope_key_by_partial(key)
- if key.to_s.first == "."
+ if (key.respond_to?(:join) ? key.join : key.to_s).first == "."
if @_virtual_path
@_virtual_path.gsub(%r{/_?}, ".") + key.to_s
else
@@ -40,4 +41,4 @@ module ActionView
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index fde4bfa4ce..ae1385f3b7 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -5,7 +5,7 @@ require 'active_support/core_ext/hash/keys'
module ActionView
module Helpers #:nodoc:
# Provides a set of methods for making links and getting URLs that
- # depend on the routing subsystem (see ActionController::Routing).
+ # depend on the routing subsystem (see ActionDispatch::Routing).
# This allows you to use the same format for links in views
# and controllers.
module UrlHelper
@@ -63,7 +63,7 @@ module ActionView
# # => /testing/jump/#tax&ship
#
# <%= url_for(Workshop.new) %>
- # # relies on Workshop answering a new_record? call (and in this case returning true)
+ # # relies on Workshop answering a persisted? call (and in this case returning false)
# # => /workshops
#
# <%= url_for(@workshop) %>
@@ -202,8 +202,6 @@ module ActionView
#
# link_to("Destroy", "http://www.example.com", :method => :delete, :confirm => "Are you sure?")
# # => <a href='http://www.example.com' rel="nofollow" data-method="delete" data-confirm="Are you sure?">Destroy</a>
-
- #
def link_to(*args, &block)
if block_given?
options = args.first || {}
@@ -226,7 +224,7 @@ module ActionView
end
href_attr = "href=\"#{url}\"" unless href
- "<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe
+ ("<a #{href_attr}#{tag_options}>".html_safe << (name || url)).safe_concat("</a>")
end
end
@@ -469,14 +467,12 @@ module ActionView
extras << "subject=#{Rack::Utils.escape(subject).gsub("+", "%20")}&" unless subject.nil?
extras = "?" << extras.gsub!(/&?$/,"") unless extras.empty?
- email_address = email_address.to_s
-
- email_address_obfuscated = email_address.dup
+ email_address_obfuscated = html_escape(email_address)
email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.has_key?("replace_at")
email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
if encode == "javascript"
- "document.write('#{content_tag("a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
+ "document.write('#{content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
string << sprintf("%%%x", c)
end
"<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>"
@@ -493,9 +489,9 @@ module ActionView
char = c.chr
string << (char =~ /\w/ ? sprintf("%%%x", c) : char)
end
- content_tag "a", name || email_address_encoded, html_options.merge({ "href" => "#{string}#{extras}" })
+ content_tag "a", name || email_address_encoded.html_safe, html_options.merge({ "href" => "#{string}#{extras}" })
else
- content_tag "a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" })
+ content_tag "a", name || email_address_obfuscated.html_safe, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" })
end
end
@@ -548,10 +544,11 @@ module ActionView
# submitted url doesn't have any either. This lets the function
# work with things like ?order=asc
if url_string.index("?")
- request_uri = request.request_uri
+ request_uri = request.fullpath
else
- request_uri = request.request_uri.split('?').first
+ request_uri = request.path
end
+
if url_string =~ /^\w+:\/\//
url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
else
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
new file mode 100644
index 0000000000..27ee8b23c9
--- /dev/null
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -0,0 +1,154 @@
+require 'active_support/core_ext/object/try'
+require 'active_support/core_ext/object/blank'
+
+module ActionView
+ # LookupContext is the object responsible to hold all information required to lookup
+ # templates, i.e. view paths and details. The LookupContext is also responsible to
+ # generate a key, given to view paths, used in the resolver cache lookup. Since
+ # this key is generated just once during the request, it speeds up all cache accesses.
+ class LookupContext #:nodoc:
+ mattr_accessor :fallbacks
+ @@fallbacks = [FileSystemResolver.new(""), FileSystemResolver.new("/")]
+
+ mattr_accessor :registered_details
+ self.registered_details = []
+
+ def self.register_detail(name, options = {}, &block)
+ self.registered_details << name
+
+ Setters.send :define_method, :"_#{name}_defaults", &block
+ Setters.module_eval <<-METHOD, __FILE__, __LINE__ + 1
+ def #{name}=(value)
+ value = Array(value.presence || _#{name}_defaults)
+ #{"value << nil unless value.include?(nil)" unless options[:allow_nil] == false}
+
+ unless value == @details[:#{name}]
+ @details_key, @details = nil, @details.merge(:#{name} => value)
+ @details.freeze
+ end
+ end
+ METHOD
+ end
+
+ # Holds raw setters for the registered details.
+ module Setters #:nodoc:
+ end
+
+ register_detail(:formats) { Mime::SET.symbols }
+ register_detail(:locale) { [I18n.locale] }
+
+ class DetailsKey #:nodoc:
+ attr_reader :details
+ alias :eql? :equal?
+
+ @details_keys = Hash.new
+
+ def self.get(details)
+ @details_keys[details] ||= new(details)
+ end
+
+ def initialize(details)
+ @details, @hash = details, details.hash
+ end
+ end
+
+ def initialize(view_paths, details = {})
+ @details, @details_key = {}, nil
+ self.view_paths = view_paths
+ self.details = details
+ end
+
+ module ViewPaths
+ attr_reader :view_paths
+
+ # Whenever setting view paths, makes a copy so we can manipulate then in
+ # instance objects as we wish.
+ def view_paths=(paths)
+ @view_paths = ActionView::Base.process_view_paths(paths)
+ end
+
+ def find(name, prefix = nil, partial = false)
+ @view_paths.find(name, prefix, partial, details, details_key)
+ end
+
+ def find_all(name, prefix = nil, partial = false)
+ @view_paths.find_all(name, prefix, partial, details, details_key)
+ end
+
+ def exists?(name, prefix = nil, partial = false)
+ @view_paths.exists?(name, prefix, partial, details, details_key)
+ end
+
+ # Add fallbacks to the view paths. Useful in cases you are rendering a :file.
+ def with_fallbacks
+ added_resolvers = 0
+ self.class.fallbacks.each do |resolver|
+ next if view_paths.include?(resolver)
+ view_paths.push(resolver)
+ added_resolvers += 1
+ end
+ yield
+ ensure
+ added_resolvers.times { view_paths.pop }
+ end
+ end
+
+ module Details
+ attr_reader :details
+
+ def details=(given_details)
+ registered_details.each { |key| send(:"#{key}=", given_details[key]) }
+ end
+
+ def details_key
+ @details_key ||= DetailsKey.get(@details)
+ end
+
+ # Shortcut to read formats from details.
+ def formats
+ @details[:formats].compact
+ end
+
+ # Overload formats= to reject [:"*/*"] values.
+ def formats=(value, freeze=true)
+ value = nil if value == [:"*/*"]
+ super(value)
+ end
+
+ # Shortcut to read locale.
+ def locale
+ I18n.locale
+ end
+
+ # Overload locale= to also set the I18n.locale. If the current I18n.config object responds
+ # to i18n_config, it means that it's has a copy of the original I18n configuration and it's
+ # acting as proxy, which we need to skip.
+ def locale=(value)
+ value = value.first if value.is_a?(Array)
+ config = I18n.config.respond_to?(:i18n_config) ? I18n.config.i18n_config : I18n.config
+ config.locale = value if value
+ super(I18n.locale)
+ end
+
+ # Update the details keys by merging the given hash into the current
+ # details hash. If a block is given, the details are modified just during
+ # the execution of the block and reverted to the previous value after.
+ def update_details(new_details)
+ old_details = @details
+ self.details = old_details.merge(new_details)
+
+ if block_given?
+ begin
+ yield
+ ensure
+ @details = old_details
+ end
+ end
+ end
+ end
+
+ include Setters
+ include Details
+ include ViewPaths
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index 6e55d69d00..35927d09d1 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -1,80 +1,39 @@
module ActionView #:nodoc:
class PathSet < Array #:nodoc:
- def self.type_cast(obj, cache = nil)
- # TODO: Clean this up
- if obj.is_a?(String)
- if cache.nil?
- cache = !defined?(Rails.application) || Rails.application.config.cache_classes
+ %w(initialize << concat insert push unshift).each do |method|
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
+ def #{method}(*args)
+ super
+ typecast!
end
- FileSystemResolverWithFallback.new(obj, :cache => cache)
- else
- obj
- end
- end
-
- def initialize(*args)
- super(*args).map! { |obj| self.class.type_cast(obj) }
- end
-
- def <<(obj)
- super(self.class.type_cast(obj))
- end
-
- def concat(array)
- super(array.map! { |obj| self.class.type_cast(obj) })
- end
-
- def insert(index, obj)
- super(index, self.class.type_cast(obj))
- end
-
- def push(*objs)
- super(*objs.map { |obj| self.class.type_cast(obj) })
+ METHOD
end
- def unshift(*objs)
- super(*objs.map { |obj| self.class.type_cast(obj) })
+ def find(path, prefix = nil, partial = false, details = {}, key = nil)
+ template = find_all(path, prefix, partial, details, key).first
+ raise MissingTemplate.new(self, "#{prefix}/#{path}", details, partial) unless template
+ template
end
- def find(path, details = {}, prefix = nil, partial = false)
- template_path = path
-
- each do |load_path|
- if template = load_path.find(template_path, details, prefix, partial)
- return template
- end
+ def find_all(*args)
+ each do |resolver|
+ templates = resolver.find_all(*args)
+ return templates unless templates.empty?
end
-
- raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}", details, partial)
+ []
end
-
- def exists?(path, extension = nil, prefix = nil, partial = false)
- template_path = path.sub(/^\//, '')
- each do |load_path|
- return true if template = load_path.find(template_path, extension, prefix, partial)
- end
- false
+ def exists?(*args)
+ find_all(*args).any?
end
- def find_template(original_template_path, format = nil, html_fallback = true)
- return original_template_path if original_template_path.respond_to?(:render)
- template_path = original_template_path.sub(/^\//, '')
+ protected
- each do |load_path|
- if template = load_path.find(template_path, format)
- return template
- # Try to find html version if the format is javascript
- elsif format == :js && html_fallback && template = load_path["#{template_path}.#{I18n.locale}.html"]
- return template
- elsif format == :js && html_fallback && template = load_path["#{template_path}.html"]
- return template
- end
+ def typecast!
+ each_with_index do |path, i|
+ next unless path.is_a?(String)
+ self[i] = FileSystemResolver.new(path)
end
-
- return Template.new(original_template_path, original_template_path.to_s =~ /\A\// ? "" : ".") if File.file?(original_template_path)
-
- raise MissingTemplate.new(self, original_template_path, format)
end
end
end
diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb
index d9e2557d89..2e5d115630 100644
--- a/actionpack/lib/action_view/railtie.rb
+++ b/actionpack/lib/action_view/railtie.rb
@@ -5,12 +5,14 @@ module ActionView
class Railtie < Rails::Railtie
railtie_name :action_view
- require "action_view/railties/subscriber"
- subscriber ActionView::Railties::Subscriber.new
+ require "action_view/railties/log_subscriber"
+ log_subscriber ActionView::Railties::LogSubscriber.new
initializer "action_view.cache_asset_timestamps" do |app|
unless app.config.cache_classes
- ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
+ ActionView.base_hook do
+ ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
+ end
end
end
end
diff --git a/actionpack/lib/action_view/railties/subscriber.rb b/actionpack/lib/action_view/railties/log_subscriber.rb
index 803f19379c..9487a10706 100644
--- a/actionpack/lib/action_view/railties/subscriber.rb
+++ b/actionpack/lib/action_view/railties/log_subscriber.rb
@@ -1,6 +1,6 @@
module ActionView
module Railties
- class Subscriber < Rails::Subscriber
+ class LogSubscriber < Rails::LogSubscriber
def render_template(event)
message = "Rendered #{from_rails_root(event.payload[:identifier])}"
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
diff --git a/actionpack/lib/action_view/render/layouts.rb b/actionpack/lib/action_view/render/layouts.rb
new file mode 100644
index 0000000000..8688de3d18
--- /dev/null
+++ b/actionpack/lib/action_view/render/layouts.rb
@@ -0,0 +1,65 @@
+require 'active_support/core_ext/object/try'
+
+module ActionView
+ module Layouts
+
+ # You can think of a layout as a method that is called with a block. _layout_for
+ # returns the contents that are yielded to the layout. If the user calls yield
+ # :some_name, the block, by default, returns content_for(:some_name). If the user
+ # calls yield, the default block returns content_for(:layout).
+ #
+ # The user can override this default by passing a block to the layout.
+ #
+ # ==== Example
+ #
+ # # The template
+ # <% render :layout => "my_layout" do %>Content<% end %>
+ #
+ # # The layout
+ # <html><% yield %></html>
+ #
+ # In this case, instead of the default block, which would return content_for(:layout),
+ # this method returns the block that was passed in to render layout, and the response
+ # would be <html>Content</html>.
+ #
+ # Finally, the block can take block arguments, which can be passed in by yield.
+ #
+ # ==== Example
+ #
+ # # The template
+ # <% render :layout => "my_layout" do |customer| %>Hello <%= customer.name %><% end %>
+ #
+ # # The layout
+ # <html><% yield Struct.new(:name).new("David") %></html>
+ #
+ # In this case, the layout would receive the block passed into <tt>render :layout</tt>,
+ # and the Struct specified in the layout would be passed into the block. The result
+ # would be <html>Hello David</html>.
+ def _layout_for(name = nil, &block) #:nodoc:
+ if !block || name
+ @_content_for[name || :layout]
+ else
+ capture(&block)
+ end
+ end
+
+ # This is the method which actually finds the layout using details in the lookup
+ # context object. If no layout is found, it checkes if at least a layout with
+ # the given name exists across all details before raising the error.
+ def _find_layout(layout) #:nodoc:
+ begin
+ layout =~ /^\// ?
+ with_fallbacks { find(layout) } : find(layout)
+ rescue ActionView::MissingTemplate => e
+ update_details(:formats => nil) do
+ raise unless exists?(layout)
+ end
+ end
+ end
+
+ # Contains the logic that actually renders the layout.
+ def _render_layout(layout, locals, &block) #:nodoc:
+ layout.render(self, locals){ |*name| _layout_for(*name, &block) }
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 62d31662db..d34ab0354c 100644
--- a/actionpack/lib/action_view/render/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -174,17 +174,11 @@ module ActionView
class PartialRenderer
PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} }
- TEMPLATES = Hash.new {|h,k| h[k] = {} }
-
- attr_reader :template
def initialize(view_context, options, block)
@view = view_context
@partial_names = PARTIAL_NAMES[@view.controller.class]
- key = Thread.current[:format_locale_key]
- @templates = TEMPLATES[key] if key
-
setup(options, block)
end
@@ -228,6 +222,7 @@ module ActionView
if !@block && (layout = @options[:layout])
content = @view._render_layout(find_template(layout), @locals){ content }
end
+
content
end
end
@@ -244,9 +239,9 @@ module ActionView
end
def collection_with_template(template = @template)
- segments, locals, as = [], @locals, @options[:as] || template.variable_name
+ segments, locals, as, template = [], @locals, @options[:as] || @template.variable_name, @template
- counter_name = template.counter_name
+ counter_name = template.counter_name
locals[counter_name] = -1
@collection.each do |object|
@@ -256,7 +251,6 @@ module ActionView
segments << template.render(@view, locals)
end
- @template = template
segments
end
@@ -277,7 +271,7 @@ module ActionView
end
def render_partial(object = @object)
- locals, view = @locals, @view
+ locals, view, template = @locals, @view, @template
object ||= locals[template.variable_name]
locals[@options[:as] || template.variable_name] = object
@@ -288,6 +282,7 @@ module ActionView
end
private
+
def collection
if @object.respond_to?(:to_ary)
@object
@@ -296,20 +291,10 @@ module ActionView
end
end
- def find_template(path = @path)
- unless @templates
- path && _find_template(path)
- else
- path && @templates[path] ||= _find_template(path)
- end
- end
-
- def _find_template(path)
- if controller = @view.controller
- prefix = controller.controller_path unless path.include?(?/)
- end
-
- @view.find(path, {:formats => @view.formats}, prefix, true)
+ def find_template(path=@path)
+ return path unless path.is_a?(String)
+ prefix = @view.controller_path unless path.include?(?/)
+ @view.find(path, prefix, true)
end
def partial_path(object = @object)
@@ -324,21 +309,8 @@ module ActionView
end
end
- def render_partial(options)
- _evaluate_assigns_and_ivars
-
- details = options[:_details]
-
- # Is this needed
- self.formats = details[:formats] if details
- renderer = PartialRenderer.new(self, options, nil)
- text = renderer.render
- options[:_template] = renderer.template
- text
- end
-
def _render_partial(options, &block) #:nodoc:
- if defined? @renderer
+ if defined?(@renderer)
@renderer.setup(options, block)
else
@renderer = PartialRenderer.new(self, options, block)
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index abc7c09991..47ea70f5ad 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -15,27 +15,11 @@ module ActionView
def render(options = {}, locals = {}, &block) #:nodoc:
case options
when Hash
- layout = options[:layout]
- options[:locals] ||= {}
-
if block_given?
- return safe_concat(_render_partial(options.merge(:partial => layout), &block))
- elsif options.key?(:partial)
- return _render_partial(options)
- end
-
- template = if options[:file]
- find(options[:file], {:formats => formats})
- elsif options[:inline]
- handler = Template.handler_class_for_extension(options[:type] || "erb")
- Template.new(options[:inline], "inline template", handler, {})
- elsif options[:text]
- Template::Text.new(options[:text])
- end
-
- if template
- layout = find(layout, {:formats => formats}) if layout
- _render_template(template, layout, :locals => options[:locals])
+ content = _render_partial(options.merge(:partial => options[:layout]), &block)
+ safe_concat(content)
+ else
+ _render(options)
end
when :update
update_page(&block)
@@ -44,61 +28,57 @@ module ActionView
end
end
- # You can think of a layout as a method that is called with a block. _layout_for
- # returns the contents that are yielded to the layout. If the user calls yield
- # :some_name, the block, by default, returns content_for(:some_name). If the user
- # calls yield, the default block returns content_for(:layout).
- #
- # The user can override this default by passing a block to the layout.
- #
- # ==== Example
- #
- # # The template
- # <% render :layout => "my_layout" do %>Content<% end %>
- #
- # # The layout
- # <html><% yield %></html>
- #
- # In this case, instead of the default block, which would return content_for(:layout),
- # this method returns the block that was passed in to render layout, and the response
- # would be <html>Content</html>.
- #
- # Finally, the block can take block arguments, which can be passed in by yield.
- #
- # ==== Example
- #
- # # The template
- # <% render :layout => "my_layout" do |customer| %>Hello <%= customer.name %><% end %>
- #
- # # The layout
- # <html><% yield Struct.new(:name).new("David") %></html>
- #
- # In this case, the layout would receive the block passed into <tt>render :layout</tt>,
- # and the Struct specified in the layout would be passed into the block. The result
- # would be <html>Hello David</html>.
- def _layout_for(name = nil, &block)
- return @_content_for[name || :layout] if !block_given? || name
- capture(&block)
- end
-
# This is the API to render a ViewContext's template from a controller.
- #
- # Internal Options:
- # _template:: The Template object to render
- # _layout:: The layout, if any, to wrap the Template in
- def render_template(options)
+ def render_template(options, &block)
_evaluate_assigns_and_ivars
- template, layout = options.values_at(:_template, :_layout)
- _render_template(template, layout, options)
+
+ # TODO Layout for partials should be handled here, because inside the
+ # partial renderer it looks for the layout as a partial.
+ if options.key?(:partial) && options[:layout]
+ options[:layout] = _find_layout(options[:layout])
+ end
+
+ _render(options, &block)
+ end
+
+ # This method holds the common render logic for both controllers and
+ # views rendering stacks.
+ def _render(options) #:nodoc:
+ if options.key?(:partial)
+ _render_partial(options)
+ else
+ template = _determine_template(options)
+ yield template if block_given?
+ _render_template(template, options[:layout], options)
+ end
end
- def _render_template(template, layout = nil, options = {})
+ # Determine the template to be rendered using the given options.
+ def _determine_template(options) #:nodoc:
+ if options.key?(:inline)
+ handler = Template.handler_class_for_extension(options[:type] || "erb")
+ Template.new(options[:inline], "inline template", handler, {})
+ elsif options.key?(:text)
+ Template::Text.new(options[:text], self.formats.try(:first))
+ elsif options.key?(:_template)
+ options[:_template]
+ elsif options.key?(:file)
+ with_fallbacks { find(options[:file], options[:prefix]) }
+ elsif options.key?(:template)
+ find(options[:template], options[:prefix])
+ end
+ end
+
+ # Renders the given template. An string representing the layout can be
+ # supplied as well.
+ def _render_template(template, layout = nil, options = {}) #:nodoc:
locals = options[:locals] || {}
+ layout = _find_layout(layout) if layout
ActiveSupport::Notifications.instrument("action_view.render_template",
:identifier => template.identifier, :layout => layout.try(:identifier)) do
- content = template.render(self, locals)
+ content = template.render(self, locals) { |*name| _layout_for(*name) }
@_content_for[:layout] = content
if layout
@@ -110,8 +90,5 @@ module ActionView
end
end
- def _render_layout(layout, locals, &block)
- layout.render(self, locals){ |*name| _layout_for(*name, &block) }
- end
end
end
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index cd6b1930a1..b4fdb49d3b 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -16,23 +16,22 @@ module ActionView
end
extend Template::Handlers
- attr_reader :source, :identifier, :handler, :mime_type, :formats, :details
+
+ attr_reader :source, :identifier, :handler, :virtual_path, :formats
def initialize(source, identifier, handler, details)
@source = source
@identifier = identifier
@handler = handler
- @details = details
+
+ @partial = details[:partial]
+ @virtual_path = details[:virtual_path]
@method_names = {}
- format = details.delete(:format) || begin
- # TODO: Clean this up
- handler.respond_to?(:default_format) ? handler.default_format.to_sym.to_s : "html"
- end
- @mime_type = Mime::Type.lookup_by_extension(format.to_s)
- @formats = [format.to_sym]
- @formats << :html if format == :js
- @details[:formats] = Array.wrap(format.to_sym)
+ format = details[:format]
+ format ||= handler.default_format.to_sym if handler.respond_to?(:default_format)
+ format ||= :html
+ @formats = [format.to_sym]
end
def render(view, locals, &block)
@@ -47,19 +46,20 @@ module ActionView
end
end
- # TODO: Figure out how to abstract this
+ def mime_type
+ @mime_type ||= Mime::Type.lookup_by_extension(@formats.first.to_s) if @formats.first
+ end
+
def variable_name
- @variable_name ||= identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
+ @variable_name ||= @virtual_path[%r'_?(\w+)(\.\w+)*$', 1].to_sym
end
- # TODO: Figure out how to abstract this
def counter_name
@counter_name ||= "#{variable_name}_counter".to_sym
end
- # TODO: kill hax
def partial?
- @details[:partial]
+ @partial
end
def inspect
@@ -87,7 +87,7 @@ module ActionView
source = <<-end_src
def #{method_name}(local_assigns)
- _old_virtual_path, @_virtual_path = @_virtual_path, #{@details[:virtual_path].inspect};_old_output_buffer = output_buffer;#{locals_code};#{code}
+ _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = output_buffer;#{locals_code};#{code}
ensure
@_virtual_path, self.output_buffer = _old_virtual_path, _old_output_buffer
end
diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb
index 4573a440d1..ac5902cc0e 100644
--- a/actionpack/lib/action_view/template/handlers/erb.rb
+++ b/actionpack/lib/action_view/template/handlers/erb.rb
@@ -3,10 +3,17 @@ require 'active_support/core_ext/string/output_safety'
require 'erubis'
module ActionView
+ class OutputBuffer < ActiveSupport::SafeBuffer
+ def <<(value)
+ super(value.to_s)
+ end
+ alias :append= :<<
+ end
+
module Template::Handlers
class Erubis < ::Erubis::Eruby
def add_preamble(src)
- src << "@output_buffer = ActiveSupport::SafeBuffer.new;"
+ src << "@output_buffer = ActionView::OutputBuffer.new;"
end
def add_text(src, text)
@@ -15,15 +22,15 @@ module ActionView
end
def add_expr_literal(src, code)
- if code =~ /\s*raw\s+(.*)/
- src << "@output_buffer.safe_concat((" << $1 << ").to_s);"
+ if code =~ /(do|\{)(\s*\|[^|]*\|)?\s*\Z/
+ src << '@output_buffer.append= ' << code
else
- src << '@output_buffer << ((' << code << ').to_s);'
+ src << '@output_buffer.append= (' << code << ');'
end
end
def add_expr_escaped(src, code)
- src << '@output_buffer << ' << escaped_expr(code) << ';'
+ src << '@output_buffer.append= ' << escaped_expr(code) << ';'
end
def add_postamble(src)
@@ -42,14 +49,14 @@ module ActionView
self.erb_trim_mode = '-'
self.default_format = Mime::HTML
-
- cattr_accessor :erubis_implementation
- self.erubis_implementation = Erubis
+
+ cattr_accessor :erb_implementation
+ self.erb_implementation = Erubis
def compile(template)
source = template.source.gsub(/\A(<%(#.*coding[:=]\s*(\S+)\s*)-?%>)\s*\n?/, '')
erb = "<% __in_erb_template=true %>#{source}"
- result = self.class.erubis_implementation.new(erb, :trim=>(self.class.erb_trim_mode == "-")).src
+ result = self.class.erb_implementation.new(erb, :trim=>(self.class.erb_trim_mode == "-")).src
result = "#{$2}\n#{result}" if $2
result
end
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 8acfe6cad0..a43597e728 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -4,64 +4,47 @@ require "active_support/core_ext/array/wrap"
require "action_view/template"
module ActionView
- # Abstract superclass
class Resolver
-
- class_inheritable_accessor(:registered_details)
- self.registered_details = {}
-
- def self.register_detail(name, options = {})
- registered_details[name] = lambda do |val|
- val = Array.wrap(val || yield)
- val |= [nil] unless options[:allow_nil] == false
- val
- end
- end
-
- register_detail(:locale) { [I18n.locale] }
- register_detail(:formats) { Mime::SET.symbols }
- register_detail(:handlers, :allow_nil => false) do
- Template::Handlers.extensions
+ def initialize
+ @cached = Hash.new { |h1,k1| h1[k1] =
+ Hash.new { |h2,k2| h2[k2] = Hash.new { |h3, k3| h3[k3] = {} } } }
end
- def initialize(options = {})
- @cache = options[:cache]
- @cached = {}
+ def clear_cache
+ @cached.clear
end
- # Normalizes the arguments and passes it on to find_template
def find(*args)
find_all(*args).first
end
- def find_all(name, details = {}, prefix = nil, partial = nil)
- details = normalize_details(details)
+ # Normalizes the arguments and passes it on to find_template.
+ def find_all(name, prefix=nil, partial=false, details={}, key=nil)
name, prefix = normalize_name(name, prefix)
+ details = details.merge(:handlers => default_handlers)
- cached([name, details, prefix, partial]) do
- find_templates(name, details, prefix, partial)
+ cached(key, prefix, name, partial) do
+ find_templates(name, prefix, partial, details)
end
end
private
+ def caching?
+ @caching ||= !defined?(Rails.application) || Rails.application.config.cache_classes
+ end
+
+ def default_handlers
+ Template::Handlers.extensions + [nil]
+ end
+
# This is what child classes implement. No defaults are needed
# because Resolver guarantees that the arguments are present and
# normalized.
- def find_templates(name, details, prefix, partial)
+ def find_templates(name, prefix, partial, details)
raise NotImplementedError
end
- def normalize_details(details)
- details = details.dup
- # TODO: Refactor this concern out of the resolver
- details.delete(:formats) if details[:formats] == [:"*/*"]
- registered_details.each do |k, v|
- details[k] = v.call(details[k])
- end
- details
- end
-
# Support legacy foo.erb names even though we now ignore .erb
# as well as incorrectly putting part of the path in the template
# name instead of the prefix.
@@ -73,92 +56,73 @@ module ActionView
return parts.pop, [prefix, *parts].compact.join("/")
end
- def cached(key)
- return yield unless @cache
- return @cached[key] if @cached.key?(key)
- @cached[key] = yield
+ def cached(key, prefix, name, partial)
+ return yield unless key && caching?
+ scope = @cached[key][prefix][name]
+ if scope.key?(partial)
+ scope[partial]
+ else
+ scope[partial] = yield
+ end
end
end
class PathResolver < Resolver
-
EXTENSION_ORDER = [:locale, :formats, :handlers]
def to_s
@path.to_s
end
- alias to_path to_s
-
- def find_templates(name, details, prefix, partial)
- path = build_path(name, details, prefix, partial)
- query(path, EXTENSION_ORDER.map { |ext| details[ext] })
- end
+ alias :to_path :to_s
private
- def build_path(name, details, prefix, partial)
+ def find_templates(name, prefix, partial, details)
+ path = build_path(name, prefix, partial, details)
+ query(partial, path, EXTENSION_ORDER.map { |ext| details[ext] })
+ end
+
+ def build_path(name, prefix, partial, details)
path = ""
path << "#{prefix}/" unless prefix.empty?
path << (partial ? "_#{name}" : name)
path
end
- def query(path, exts)
+ def query(partial, path, exts)
query = File.join(@path, path)
+
exts.each do |ext|
query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << '}'
end
Dir[query].reject { |p| File.directory?(p) }.map do |p|
- Template.new(File.read(p), File.expand_path(p), *path_to_details(p))
+ handler, format = extract_handler_and_format(p)
+ Template.new(File.read(p), File.expand_path(p), handler,
+ :partial => partial, :virtual_path => path, :format => format)
end
end
- # # TODO: fix me
- # # :api: plugin
- def path_to_details(path)
- # [:erb, :format => :html, :locale => :en, :partial => true/false]
- if m = path.match(%r'((^|.*/)(_)?[\w-]+)((?:\.[\w-]+)*)\.(\w+)$')
- partial = m[3] == '_'
- details = (m[4]||"").split('.').reject { |e| e.empty? }
- handler = Template.handler_class_for_extension(m[5])
+ def extract_handler_and_format(path)
+ pieces = File.basename(path).split(".")
+ pieces.shift
- format = Mime[details.last] && details.pop.to_sym
- locale = details.last && details.pop.to_sym
-
- virtual_path = (m[1].gsub("#{@path}/", "") << details.join("."))
-
- return handler, :format => format, :locale => locale, :partial => partial,
- :virtual_path => virtual_path
- end
+ handler = Template.handler_class_for_extension(pieces.pop)
+ format = pieces.last && Mime[pieces.last] && pieces.pop.to_sym
+ [handler, format]
end
end
class FileSystemResolver < PathResolver
- def initialize(path, options = {})
+ def initialize(path)
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
- super(options)
+ super()
@path = Pathname.new(path).expand_path
end
- end
-
- # TODO: remove hack
- class FileSystemResolverWithFallback < Resolver
- def initialize(path, options = {})
- super(options)
- @paths = [FileSystemResolver.new(path, options), FileSystemResolver.new("", options), FileSystemResolver.new("/", options)]
- end
- def find_templates(*args)
- @paths.each do |p|
- template = p.find_templates(*args)
- return template unless template.empty?
- end
- []
- end
-
- def to_s
- @paths.first.to_s
+ def eql?(resolver)
+ self.class.equal?(resolver.class) && to_path == resolver.to_path
end
+ alias :== :eql?
end
end
diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb
index 2abb352d4e..df394b0fb0 100644
--- a/actionpack/lib/action_view/template/text.rb
+++ b/actionpack/lib/action_view/template/text.rb
@@ -1,15 +1,10 @@
module ActionView #:nodoc:
class Template
class Text < String #:nodoc:
- HTML = Mime[:html]
-
- def initialize(string, content_type = HTML)
+ def initialize(string, content_type = nil)
super(string.to_s)
- @content_type = Mime[content_type] || content_type
- end
-
- def details
- {:formats => [@content_type.to_sym]}
+ @content_type = Mime[content_type] || content_type if content_type
+ @content_type ||= Mime::TEXT
end
def identifier
@@ -29,7 +24,7 @@ module ActionView #:nodoc:
end
def formats
- [mime_type]
+ [@content_type.to_sym]
end
def partial?
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index fc29acea6d..1578ac9479 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -1,4 +1,5 @@
require 'action_controller/test_case'
+require 'action_view'
module ActionView
class Base
@@ -34,6 +35,8 @@ module ActionView
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
+ @request.env.delete('PATH_INFO')
+
@params = {}
end
end
@@ -60,6 +63,10 @@ module ActionView
make_test_case_available_to_view!
end
+ def config
+ @controller.config
+ end
+
def render(options = {}, local_assigns = {}, &block)
@rendered << output = _view.render(options, local_assigns, &block)
output
@@ -152,7 +159,7 @@ module ActionView
end
def method_missing(selector, *args)
- if ActionController::Routing::Routes.named_routes.helpers.include?(selector)
+ if @controller._router.named_routes.helpers.include?(selector)
@controller.__send__(selector, *args)
else
super
diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb
index 4ad87d9762..f70d497481 100644
--- a/actionpack/test/abstract/abstract_controller_test.rb
+++ b/actionpack/test/abstract/abstract_controller_test.rb
@@ -59,11 +59,11 @@ module AbstractController
end
def rendering_to_body
- self.response_body = render_to_body :_template_name => "naked_render.erb"
+ self.response_body = render_to_body :template => "naked_render.erb"
end
def rendering_to_string
- self.response_body = render_to_string :_template_name => "naked_render.erb"
+ self.response_body = render_to_string :template => "naked_render.erb"
end
end
diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb
index b6d89ea489..65a50807fd 100644
--- a/actionpack/test/abstract/layouts_test.rb
+++ b/actionpack/test/abstract/layouts_test.rb
@@ -8,41 +8,52 @@ module AbstractControllerTests
include AbstractController::Rendering
include AbstractController::Layouts
+ def _prefix
+ "template"
+ end
+
self.view_paths = [ActionView::FixtureResolver.new(
- "layouts/hello.erb" => "With String <%= yield %>",
- "layouts/hello_override.erb" => "With Override <%= yield %>",
- "layouts/abstract_controller_tests/layouts/with_string_implied_child.erb" =>
- "With Implied <%= yield %>",
- "layouts/overwrite.erb" => "Overwrite <%= yield %>",
- "layouts/with_false_layout.erb" => "False Layout <%= yield %>"
+ "abstract_controller_tests/layouts/with_string_implied_child.erb" =>
+ "With Implied <%= yield %>",
+ "layouts/hello.erb" => "With String <%= yield %>",
+ "layouts/hello_override.erb" => "With Override <%= yield %>",
+ "layouts/overwrite.erb" => "Overwrite <%= yield %>",
+ "layouts/with_false_layout.erb" => "False Layout <%= yield %>"
)]
end
class Blank < Base
- self.view_paths = []
-
+ self.view_paths = ActionView::FixtureResolver.new("template/index.erb" => "Hello blank!")
+
def index
- render :_template => ActionView::Template::Text.new("Hello blank!")
+ render
end
end
class WithString < Base
layout "hello"
-
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello string!",
+ "template/overwrite_default.erb" => "Hello string!",
+ "template/overwrite_false.erb" => "Hello string!",
+ "template/overwrite_string.erb" => "Hello string!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello string!")
+ render
end
def overwrite_default
- render :_template => ActionView::Template::Text.new("Hello string!"), :layout => :default
+ render :layout => :default
end
def overwrite_false
- render :_template => ActionView::Template::Text.new("Hello string!"), :layout => false
+ render :layout => false
end
def overwrite_string
- render :_template => ActionView::Template::Text.new("Hello string!"), :layout => "overwrite"
+ render :layout => "overwrite"
end
def overwrite_skip
@@ -70,18 +81,28 @@ module AbstractControllerTests
class WithProc < Base
layout proc { |c| "overwrite" }
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello proc!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello proc!")
+ render
end
end
class WithSymbol < Base
layout :hello
-
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello symbol!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello symbol!")
+ render
end
- private
+
+ private
+
def hello
"overwrite"
end
@@ -89,11 +110,17 @@ module AbstractControllerTests
class WithSymbolReturningString < Base
layout :no_hello
-
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello missing symbol!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello missing symbol!")
+ render
end
- private
+
+ private
+
def no_hello
nil
end
@@ -101,19 +128,28 @@ module AbstractControllerTests
class WithSymbolReturningNil < Base
layout :nilz
-
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello nilz!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello nilz!")
+ render
end
- def nilz() end
+ def nilz
+ end
end
class WithSymbolReturningObj < Base
layout :objekt
-
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello object!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello nilz!")
+ render
end
def objekt
@@ -123,33 +159,49 @@ module AbstractControllerTests
class WithSymbolAndNoMethod < Base
layout :no_method
-
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello boom!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello boom!")
+ render
end
end
class WithMissingLayout < Base
layout "missing"
-
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello missing!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello missing!")
+ render
end
end
class WithFalseLayout < Base
layout false
-
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello false!"
+ )
+
def index
- render :_template => ActionView::Template::Text.new("Hello false!")
+ render
end
end
class WithNilLayout < Base
layout nil
+
+ append_view_path ActionView::FixtureResolver.new(
+ "template/index.erb" => "Hello nil!"
+ )
def index
- render :_template => ActionView::Template::Text.new("Hello nil!")
+ render
end
end
diff --git a/actionpack/test/abstract/localized_cache_test.rb b/actionpack/test/abstract/localized_cache_test.rb
deleted file mode 100644
index 8b0b0fff03..0000000000
--- a/actionpack/test/abstract/localized_cache_test.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-require 'abstract_unit'
-
-module AbstractController
- module Testing
-
- class CachedController < AbstractController::Base
- include AbstractController::Rendering
- include AbstractController::LocalizedCache
-
- self.view_paths = [ActionView::FixtureResolver.new(
- "default.erb" => "With Default",
- "template.erb" => "With Template",
- "some/file.erb" => "With File",
- "template_name.erb" => "With Template Name"
- )]
- end
-
- class TestLocalizedCache < ActiveSupport::TestCase
-
- def setup
- @controller = CachedController.new
- CachedController.clear_template_caches!
- end
-
- def test_templates_are_cached
- @controller.render :template => "default.erb"
- assert_equal "With Default", @controller.response_body
-
- cached = @controller.class.template_cache
- assert_equal 1, cached.size
- assert_kind_of ActionView::Template, cached.values.first["default.erb"]
- end
-
- def test_cache_is_used
- CachedController.new.render :template => "default.erb"
-
- @controller.expects(:find_template).never
- @controller.render :template => "default.erb"
-
- assert_equal 1, @controller.class.template_cache.size
- end
-
- def test_cache_changes_with_locale
- CachedController.new.render :template => "default.erb"
-
- I18n.locale = :es
- @controller.render :template => "default.erb"
-
- assert_equal 2, @controller.class.template_cache.size
- ensure
- I18n.locale = :en
- end
-
- end
-
- end
-end
diff --git a/actionpack/test/abstract/render_test.rb b/actionpack/test/abstract/render_test.rb
index db924633ca..25dc8bd804 100644
--- a/actionpack/test/abstract/render_test.rb
+++ b/actionpack/test/abstract/render_test.rb
@@ -15,13 +15,8 @@ module AbstractController
"renderer/default.erb" => "With Default",
"renderer/string.erb" => "With String",
"renderer/symbol.erb" => "With Symbol",
- "renderer/template_name.erb" => "With Template Name",
"string/with_path.erb" => "With String With Path",
- "some/file.erb" => "With File",
- "with_format.html.erb" => "With html format",
- "with_format.xml.erb" => "With xml format",
- "with_locale.en.erb" => "With en locale",
- "with_locale.pl.erb" => "With pl locale"
+ "some/file.erb" => "With File"
)]
def template
@@ -55,30 +50,6 @@ module AbstractController
def symbol
render :symbol
end
-
- def template_name
- render :_template_name => :template_name
- end
-
- def object
- render :_template => ActionView::Template::Text.new("With Object")
- end
-
- def with_html_format
- render :template => "with_format", :format => :html
- end
-
- def with_xml_format
- render :template => "with_format", :format => :xml
- end
-
- def with_en_locale
- render :template => "with_locale"
- end
-
- def with_pl_locale
- render :template => "with_locale", :locale => :pl
- end
end
class TestRenderer < ActiveSupport::TestCase
@@ -126,36 +97,6 @@ module AbstractController
@controller.process(:string_with_path)
assert_equal "With String With Path", @controller.response_body
end
-
- def test_render_template_name
- @controller.process(:template_name)
- assert_equal "With Template Name", @controller.response_body
- end
-
- def test_render_object
- @controller.process(:object)
- assert_equal "With Object", @controller.response_body
- end
-
- def test_render_with_html_format
- @controller.process(:with_html_format)
- assert_equal "With html format", @controller.response_body
- end
-
- def test_render_with_xml_format
- @controller.process(:with_xml_format)
- assert_equal "With xml format", @controller.response_body
- end
-
- def test_render_with_en_locale
- @controller.process(:with_en_locale)
- assert_equal "With en locale", @controller.response_body
- end
-
- def test_render_with_pl_locale
- @controller.process(:with_pl_locale)
- assert_equal "With pl locale", @controller.response_body
- end
end
end
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 867e50d5b9..67aa412d3d 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -1,5 +1,11 @@
require File.expand_path('../../../load_paths', __FILE__)
+lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
+$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
+
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
+
$:.unshift(File.dirname(__FILE__) + '/lib')
$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers')
$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers')
@@ -10,7 +16,6 @@ require 'test/unit'
require 'abstract_controller'
require 'action_controller'
require 'action_view'
-require 'action_view/base'
require 'action_dispatch'
require 'fixture_template'
require 'active_support/dependencies'
@@ -64,29 +69,66 @@ module SetupOnce
end
end
-class ActiveSupport::TestCase
- include SetupOnce
+SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
+
+module ActiveSupport
+ class TestCase
+ include SetupOnce
+ # Hold off drawing routes until all the possible controller classes
+ # have been loaded.
+ setup_once do
+ SharedTestRoutes.draw do |map|
+ # FIXME: match ':controller(/:action(/:id))'
+ map.connect ':controller/:action/:id'
+ end
+
+ ActionController::IntegrationTest.app.router.draw do |map|
+ # FIXME: match ':controller(/:action(/:id))'
+ map.connect ':controller/:action/:id'
+ end
+ end
+ end
+end
+
+class RoutedRackApp
+ attr_reader :router
+ alias routes router
+
+ def initialize(router, &blk)
+ @router = router
+ @stack = ActionDispatch::MiddlewareStack.new(&blk).build(@router)
+ end
+
+ def call(env)
+ @stack.call(env)
+ end
+end
- # Hold off drawing routes until all the possible controller classes
- # have been loaded.
- setup_once do
- ActionController::Routing::Routes.draw do |map|
- match ':controller(/:action(/:id))'
+class BasicController
+ attr_accessor :request
+
+ def config
+ @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config|
+ # VIEW TODO: View tests should not require a controller
+ public_dir = File.expand_path("../fixtures/public", __FILE__)
+ config.assets_dir = public_dir
+ config.javascripts_dir = "#{public_dir}/javascripts"
+ config.stylesheets_dir = "#{public_dir}/stylesheets"
+ config
end
end
end
class ActionController::IntegrationTest < ActiveSupport::TestCase
def self.build_app(routes = nil)
- ActionDispatch::Flash
- ActionDispatch::MiddlewareStack.new { |middleware|
+ RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
middleware.use "ActionDispatch::ShowExceptions"
middleware.use "ActionDispatch::Callbacks"
middleware.use "ActionDispatch::ParamsParser"
middleware.use "ActionDispatch::Cookies"
middleware.use "ActionDispatch::Flash"
middleware.use "ActionDispatch::Head"
- }.build(routes || ActionController::Routing::Routes)
+ end
end
self.app = build_app
@@ -112,28 +154,22 @@ class ActionController::IntegrationTest < ActiveSupport::TestCase
end
def with_routing(&block)
- real_routes = ActionController::Routing::Routes
- ActionController::Routing.module_eval { remove_const :Routes }
-
- temporary_routes = ActionController::Routing::RouteSet.new
- self.class.app = self.class.build_app(temporary_routes)
- ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
+ temporary_routes = ActionDispatch::Routing::RouteSet.new
+ old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
+ old_routes = SharedTestRoutes
+ silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }
yield temporary_routes
ensure
- if ActionController::Routing.const_defined? :Routes
- ActionController::Routing.module_eval { remove_const :Routes }
- end
- ActionController::Routing.const_set(:Routes, real_routes) if real_routes
- self.class.app = self.class.build_app
+ self.class.app = old_app
+ silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
end
end
# Temporary base class
class Rack::TestCase < ActionController::IntegrationTest
setup do
- ActionController::Base.session_options[:key] = "abc"
- ActionController::Base.session_options[:secret] = ("*" * 30)
+ ActionController::Base.config.secret = "abc" * 30
end
def self.testing(klass = nil)
@@ -180,6 +216,16 @@ end
class ::ApplicationController < ActionController::Base
end
+module ActionView
+ class TestCase
+ # Must repeat the setup because AV::TestCase is a duplication
+ # of AC::TestCase
+ setup do
+ @router = SharedTestRoutes
+ end
+ end
+end
+
module ActionController
class Base
include ActionController::Testing
@@ -190,6 +236,10 @@ module ActionController
class TestCase
include ActionDispatch::TestProcess
+ setup do
+ @router = SharedTestRoutes
+ end
+
def assert_template(options = {}, message = nil)
validate_request!
@@ -232,3 +282,10 @@ module ActionController
end
end
end
+
+# This stub emulates the Railtie including the URL helpers from a Rails application
+module ActionController
+ class Base
+ include SharedTestRoutes.url_helpers
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionpack/test/activerecord/controller_runtime_test.rb
index ed8e324938..331f861d8f 100644
--- a/actionpack/test/activerecord/controller_runtime_test.rb
+++ b/actionpack/test/activerecord/controller_runtime_test.rb
@@ -1,37 +1,37 @@
require 'active_record_unit'
require 'active_record/railties/controller_runtime'
require 'fixtures/project'
-require 'rails/subscriber/test_helper'
-require 'action_controller/railties/subscriber'
+require 'rails/log_subscriber/test_helper'
+require 'action_controller/railties/log_subscriber'
ActionController::Base.send :include, ActiveRecord::Railties::ControllerRuntime
-class ControllerRuntimeSubscriberTest < ActionController::TestCase
- class SubscriberController < ActionController::Base
+class ControllerRuntimeLogSubscriberTest < ActionController::TestCase
+ class LogSubscriberController < ActionController::Base
def show
render :inline => "<%= Project.all %>"
end
end
-
- include Rails::Subscriber::TestHelper
- tests SubscriberController
+
+ include Rails::LogSubscriber::TestHelper
+ tests LogSubscriberController
def setup
- @old_logger = ActionController::Base.logger
- Rails::Subscriber.add(:action_controller, ActionController::Railties::Subscriber.new)
super
+ @old_logger = ActionController::Base.logger
+ Rails::LogSubscriber.add(:action_controller, ActionController::Railties::LogSubscriber.new)
end
def teardown
super
- Rails::Subscriber.subscribers.clear
+ Rails::LogSubscriber.log_subscribers.clear
ActionController::Base.logger = @old_logger
end
def set_logger(logger)
ActionController::Base.logger = logger
end
-
+
def test_log_with_active_record
get :show
wait
diff --git a/actionpack/test/activerecord/polymorphic_routes_test.rb b/actionpack/test/activerecord/polymorphic_routes_test.rb
index ea82758cf5..5643ad5ad6 100644
--- a/actionpack/test/activerecord/polymorphic_routes_test.rb
+++ b/actionpack/test/activerecord/polymorphic_routes_test.rb
@@ -26,7 +26,7 @@ class Series < ActiveRecord::Base
end
class PolymorphicRoutesTest < ActionController::TestCase
- include ActionController::UrlFor
+ include SharedTestRoutes.url_helpers
self.default_url_options[:host] = 'example.com'
def setup
@@ -400,7 +400,7 @@ class PolymorphicRoutesTest < ActionController::TestCase
map.resources :series
end
- ActionController::Routing::Routes.install_helpers(self.class)
+ self.class.send(:include, @router.url_helpers)
yield
end
end
@@ -422,7 +422,7 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
- ActionController::Routing::Routes.install_helpers(self.class)
+ self.class.send(:include, @router.url_helpers)
yield
end
end
@@ -441,7 +441,7 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
- ActionController::Routing::Routes.install_helpers(self.class)
+ self.class.send(:include, @router.url_helpers)
yield
end
end
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index d54be9bdc0..26e0d6d844 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -253,12 +253,14 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
end
def test_assert_redirect_to_nested_named_route
+ @controller = Admin::InnerModuleController.new
+
with_routing do |set|
set.draw do |map|
match 'admin/inner_module', :to => 'admin/inner_module#index', :as => :admin_inner_module
- match ':controller/:action'
+ # match ':controller/:action'
+ map.connect ':controller/:action/:id'
end
- @controller = Admin::InnerModuleController.new
process :redirect_to_index
# redirection is <{"action"=>"index", "controller"=>"admin/admin/inner_module"}>
assert_redirected_to admin_inner_module_path
@@ -266,12 +268,14 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
end
def test_assert_redirected_to_top_level_named_route_from_nested_controller
+ @controller = Admin::InnerModuleController.new
+
with_routing do |set|
set.draw do |map|
match '/action_pack_assertions/:id', :to => 'action_pack_assertions#index', :as => :top_level
- match ':controller/:action'
+ # match ':controller/:action'
+ map.connect ':controller/:action/:id'
end
- @controller = Admin::InnerModuleController.new
process :redirect_to_top_level_named_route
# assert_redirected_to "http://test.host/action_pack_assertions/foo" would pass because of exact match early return
assert_redirected_to "/action_pack_assertions/foo"
@@ -279,13 +283,15 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
end
def test_assert_redirected_to_top_level_named_route_with_same_controller_name_in_both_namespaces
+ @controller = Admin::InnerModuleController.new
+
with_routing do |set|
set.draw do |map|
# this controller exists in the admin namespace as well which is the only difference from previous test
match '/user/:id', :to => 'user#index', :as => :top_level
- match ':controller/:action'
+ # match ':controller/:action'
+ map.connect ':controller/:action/:id'
end
- @controller = Admin::InnerModuleController.new
process :redirect_to_top_level_named_route
# assert_redirected_to top_level_url('foo') would pass because of exact match early return
assert_redirected_to top_level_path('foo')
@@ -463,9 +469,11 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
assert_redirected_to '/some/path'
end
- def test_redirected_to_url_no_leadling_slash
+ def test_redirected_to_url_no_leading_slash_fails
process :redirect_to_path
- assert_redirected_to 'some/path'
+ assert_raise ActiveSupport::TestCase::Assertion do
+ assert_redirected_to 'some/path'
+ end
end
def test_redirected_to_url_full_url
diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb
index 612827dd41..cb3e848dfa 100644
--- a/actionpack/test/controller/assert_select_test.rb
+++ b/actionpack/test/controller/assert_select_test.rb
@@ -6,18 +6,7 @@
require 'abstract_unit'
require 'controller/fake_controllers'
-
-unless defined?(ActionMailer)
- begin
- $:.unshift("#{File.dirname(__FILE__)}/../../../actionmailer/lib")
- require 'action_mailer'
- rescue LoadError => e
- raise unless e.message =~ /action_mailer/
- require 'rubygems'
- gem 'actionmailer'
- end
-end
-
+require 'action_mailer'
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
class AssertSelectTest < ActionController::TestCase
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index 4fcfbacf4e..f047e7da30 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -66,6 +66,19 @@ class DefaultUrlOptionsController < ActionController::Base
end
end
+class UrlOptionsController < ActionController::Base
+ def from_view
+ render :inline => "<%= #{params[:route]} %>"
+ end
+
+ def url_options
+ super.merge(:host => 'www.override.com', :action => 'new', :locale => 'en')
+ end
+end
+
+class RecordIdentifierController < ActionController::Base
+end
+
class ControllerClassTests < ActiveSupport::TestCase
def test_controller_path
assert_equal 'empty', EmptyController.controller_path
@@ -92,6 +105,11 @@ class ControllerClassTests < ActiveSupport::TestCase
assert_equal [:password], parameters
end
+
+ def test_record_identifier
+ assert_respond_to RecordIdentifierController.new, :dom_id
+ assert_respond_to RecordIdentifierController.new, :dom_class
+ end
end
class ControllerInstanceTests < Test::Unit::TestCase
@@ -113,6 +131,15 @@ class ControllerInstanceTests < Test::Unit::TestCase
assert_equal Set.new(%w(public_action)), c.class.__send__(:action_methods), "#{c.controller_path} should not be empty!"
end
end
+
+ def test_temporary_anonymous_controllers
+ name = 'ExamplesController'
+ klass = Class.new(ActionController::Base)
+ Object.const_set(name, klass)
+
+ controller = klass.new
+ assert_equal "examples", controller.controller_path
+ end
end
class PerformActionTest < ActionController::TestCase
@@ -153,6 +180,31 @@ class PerformActionTest < ActionController::TestCase
end
end
+class UrlOptionsTest < ActionController::TestCase
+ tests UrlOptionsController
+
+ def setup
+ super
+ @request.host = 'www.example.com'
+ rescue_action_in_public!
+ end
+
+ def test_url_options_override
+ with_routing do |set|
+ set.draw do |map|
+ match 'from_view', :to => 'url_options#from_view', :as => :from_view
+ match ':controller/:action'
+ end
+
+ get :from_view, :route => "from_view_url"
+
+ assert_equal 'http://www.override.com/from_view?locale=en', @response.body
+ assert_equal 'http://www.override.com/from_view?locale=en', @controller.send(:from_view_url)
+ assert_equal 'http://www.override.com/default_url_options/new?locale=en', @controller.url_for(:controller => 'default_url_options')
+ end
+ end
+end
+
class DefaultUrlOptionsTest < ActionController::TestCase
tests DefaultUrlOptionsController
@@ -162,7 +214,7 @@ class DefaultUrlOptionsTest < ActionController::TestCase
rescue_action_in_public!
end
- def test_default_url_options_are_used_if_set
+ def test_default_url_options_override
with_routing do |set|
set.draw do |map|
match 'from_view', :to => 'default_url_options#from_view', :as => :from_view
@@ -219,12 +271,15 @@ class EmptyUrlOptionsTest < ActionController::TestCase
end
def test_named_routes_with_path_without_doing_a_request_first
+ @controller = EmptyController.new
+ @controller.request = @request
+
with_routing do |set|
set.draw do |map|
resources :things
end
- assert_equal '/things', EmptyController.new.send(:things_path)
+ assert_equal '/things', @controller.send(:things_path)
end
end
end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index de92fc56fd..a3c8fdbb6e 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -6,12 +6,18 @@ CACHE_DIR = 'test_cache'
# Don't change '/../temp/' cavalierly or you might hose something you don't want hosed
FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
ActionController::Base.page_cache_directory = FILE_STORE_PATH
-ActionController::Base.cache_store = :file_store, FILE_STORE_PATH
-class PageCachingTestController < ActionController::Base
+class CachingController < ActionController::Base
+ abstract!
+
+ self.cache_store = :file_store, FILE_STORE_PATH
+end
+
+class PageCachingTestController < CachingController
caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? }
caches_page :found, :not_found
+
def ok
head :ok
end
@@ -51,12 +57,13 @@ class PageCachingTest < ActionController::TestCase
@request = ActionController::TestRequest.new
@request.host = 'hostname.com'
+ @request.env.delete('PATH_INFO')
@response = ActionController::TestResponse.new
@controller = PageCachingTestController.new
+ @controller.cache_store = :file_store, FILE_STORE_PATH
- @params = {:controller => 'posts', :action => 'index', :only_path => true, :skip_relative_url_root => true}
- @rewriter = ActionController::UrlRewriter.new(@request, @params)
+ @params = {:controller => 'posts', :action => 'index', :only_path => true}
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
FileUtils.mkdir_p(FILE_STORE_PATH)
@@ -74,9 +81,9 @@ class PageCachingTest < ActionController::TestCase
match '/', :to => 'posts#index', :as => :main
end
@params[:format] = 'rss'
- assert_equal '/posts.rss', @rewriter.rewrite(@params)
+ assert_equal '/posts.rss', @router.url_for(@params)
@params[:format] = nil
- assert_equal '/', @rewriter.rewrite(@params)
+ assert_equal '/', @router.url_for(@params)
end
end
@@ -110,7 +117,7 @@ class PageCachingTest < ActionController::TestCase
end
def test_should_cache_ok_at_custom_path
- @request.request_uri = "/index.html"
+ @request.env['PATH_INFO'] = '/index.html'
get :ok
assert_response :ok
assert File.exist?("#{FILE_STORE_PATH}/index.html")
@@ -147,7 +154,7 @@ class PageCachingTest < ActionController::TestCase
end
end
-class ActionCachingTestController < ActionController::Base
+class ActionCachingTestController < CachingController
rescue_from(Exception) { head 500 }
if defined? ActiveRecord
rescue_from(ActiveRecord::RecordNotFound) { head :not_found }
@@ -305,12 +312,9 @@ class ActionCacheTest < ActionController::TestCase
end
def test_action_cache_conditional_options
- old_use_accept_header = ActionController::Base.use_accept_header
- ActionController::Base.use_accept_header = true
@request.env['HTTP_ACCEPT'] = 'application/json'
get :index
assert !fragment_exist?('hostname.com/action_caching_test')
- ActionController::Base.use_accept_header = old_use_accept_header
end
def test_action_cache_with_store_options
@@ -511,6 +515,7 @@ class ActionCacheTest < ActionController::TestCase
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@controller = ActionCachingTestController.new
+ @controller.singleton_class.send(:include, @router.url_helpers)
@request.host = 'hostname.com'
end
@@ -523,7 +528,7 @@ class ActionCacheTest < ActionController::TestCase
end
end
-class FragmentCachingTestController < ActionController::Base
+class FragmentCachingTestController < CachingController
def some_action; end;
end
@@ -532,8 +537,8 @@ class FragmentCachingTest < ActionController::TestCase
super
ActionController::Base.perform_caching = true
@store = ActiveSupport::Cache::MemoryStore.new
- ActionController::Base.cache_store = @store
@controller = FragmentCachingTestController.new
+ @controller.cache_store = @store
@params = {:controller => 'posts', :action => 'index'}
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@@ -631,7 +636,7 @@ class FragmentCachingTest < ActionController::TestCase
end
-class FunctionalCachingController < ActionController::Base
+class FunctionalCachingController < CachingController
def fragment_cached
end
@@ -665,8 +670,8 @@ class FunctionalFragmentCachingTest < ActionController::TestCase
super
ActionController::Base.perform_caching = true
@store = ActiveSupport::Cache::MemoryStore.new
- ActionController::Base.cache_store = @store
@controller = FunctionalCachingController.new
+ @controller.cache_store = @store
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb
index e5ffe20ecc..967107853b 100644
--- a/actionpack/test/controller/content_type_test.rb
+++ b/actionpack/test/controller/content_type_test.rb
@@ -145,18 +145,6 @@ end
class AcceptBasedContentTypeTest < ActionController::TestCase
tests OldContentTypeController
- def setup
- super
- @_old_accept_header = ActionController::Base.use_accept_header
- ActionController::Base.use_accept_header = true
- end
-
- def teardown
- super
- ActionController::Base.use_accept_header = @_old_accept_header
- end
-
-
def test_render_default_content_types_for_respond_to
@request.accept = Mime::HTML.to_s
get :render_default_content_types_for_respond_to
diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb
index f5ccef8aaf..908967a110 100644
--- a/actionpack/test/controller/cookie_test.rb
+++ b/actionpack/test/controller/cookie_test.rb
@@ -157,7 +157,7 @@ class CookieTest < ActionController::TestCase
def assert_cookie_header(expected)
header = @response.headers["Set-Cookie"]
if header.respond_to?(:to_str)
- assert_equal expected, header
+ assert_equal expected.split("\n").sort, header.split("\n").sort
else
assert_equal expected.split("\n"), header
end
diff --git a/actionpack/test/controller/http_digest_authentication_test.rb b/actionpack/test/controller/http_digest_authentication_test.rb
index 7e9a2625f1..eb2af523a2 100644
--- a/actionpack/test/controller/http_digest_authentication_test.rb
+++ b/actionpack/test/controller/http_digest_authentication_test.rb
@@ -40,11 +40,13 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
setup do
# Used as secret in generating nonce to prevent tampering of timestamp
- @old_secret, ActionController::Base.session_options[:secret] = ActionController::Base.session_options[:secret], "session_options_secret"
+ @secret = "session_options_secret"
+ @controller.config.secret = @secret
+ # @old_secret, ActionController::Base.config.secret[:secret] = ActionController::Base.session_options[:secret], @secret
end
teardown do
- ActionController::Base.session_options[:secret] = @old_secret
+ # ActionController::Base.session_options[:secret] = @old_secret
end
AUTH_HEADERS.each do |header|
@@ -138,7 +140,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
test "authentication request with request-uri that doesn't match credentials digest-uri" do
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
- @request.env['REQUEST_URI'] = "/http_digest_authentication_test/dummy_digest/altered/uri"
+ @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest/altered/uri"
get :display
assert_response :unauthorized
@@ -147,7 +149,8 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
test "authentication request with absolute request uri (as in webrick)" do
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
- @request.env['REQUEST_URI'] = "http://test.host/http_digest_authentication_test/dummy_digest"
+ @request.env["SERVER_NAME"] = "test.host"
+ @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest"
get :display
@@ -170,7 +173,8 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
test "authentication request with absolute uri in both request and credentials (as in Webrick with IE)" do
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:url => "http://test.host/http_digest_authentication_test/dummy_digest",
:username => 'pretty', :password => 'please')
- @request.env['REQUEST_URI'] = "http://test.host/http_digest_authentication_test/dummy_digest"
+ @request.env['SERVER_NAME'] = "test.host"
+ @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest"
get :display
@@ -202,7 +206,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
test "validate_digest_response should fail with nil returning password_procedure" do
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => nil, :password => nil)
- assert !ActionController::HttpAuthentication::Digest.validate_digest_response(@request, "SuperSecret"){nil}
+ assert !ActionController::HttpAuthentication::Digest.validate_digest_response(@secret, @request, "SuperSecret"){nil}
end
private
@@ -225,7 +229,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
credentials = decode_credentials(@response.headers['WWW-Authenticate'])
credentials.merge!(options)
- credentials.merge!(:uri => @request.env['REQUEST_URI'].to_s)
+ credentials.merge!(:uri => @request.env['PATH_INFO'].to_s)
ActionController::HttpAuthentication::Digest.encode_credentials(method, credentials, password, options[:password_is_ha1])
end
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 683ab5236c..2180466ca7 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -75,23 +75,6 @@ class SessionTest < Test::Unit::TestCase
@session.delete_via_redirect(path, args, headers)
end
- def test_url_for_with_controller
- options = {:action => 'show'}
- mock_controller = mock()
- mock_controller.expects(:url_for).with(options).returns('/show')
- @session.stubs(:controller).returns(mock_controller)
- assert_equal '/show', @session.url_for(options)
- end
-
- def test_url_for_without_controller
- options = {:action => 'show'}
- mock_rewriter = mock()
- mock_rewriter.expects(:rewrite).with(options).returns('/show')
- @session.stubs(:generic_url_rewriter).returns(mock_rewriter)
- @session.stubs(:controller).returns(nil)
- assert_equal '/show', @session.url_for(options)
- end
-
def test_get
path = "/index"; params = "blah"; headers = {:location => 'blah'}
@session.expects(:process).with(:get,path,params,headers)
@@ -195,8 +178,8 @@ class IntegrationTestTest < Test::Unit::TestCase
session1 = @test.open_session { |sess| }
session2 = @test.open_session # implicit session
- assert_equal ::ActionController::Integration::Session, session1.class
- assert_equal ::ActionController::Integration::Session, session2.class
+ assert_kind_of ::ActionController::Integration::Session, session1
+ assert_kind_of ::ActionController::Integration::Session, session2
assert_not_equal session1, session2
end
@@ -301,18 +284,13 @@ class IntegrationProcessTest < ActionController::IntegrationTest
end
end
- def test_cookie_monster
+ test 'response cookies are added to the cookie jar for the next request' do
with_test_route_set do
self.cookies['cookie_1'] = "sugar"
self.cookies['cookie_2'] = "oatmeal"
get '/cookie_monster'
- assert_equal 410, status
- assert_equal "Gone", status_message
- assert_response 410
- assert_response :gone
assert_equal "cookie_1=; path=/\ncookie_3=chocolate; path=/", headers["Set-Cookie"]
assert_equal({"cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies.to_hash)
- assert_equal "Gone", response.body
end
end
@@ -350,7 +328,7 @@ class IntegrationProcessTest < ActionController::IntegrationTest
with_test_route_set do
get '/get_with_params?foo=bar'
assert_equal '/get_with_params?foo=bar', request.env["REQUEST_URI"]
- assert_equal '/get_with_params?foo=bar', request.request_uri
+ assert_equal '/get_with_params?foo=bar', request.fullpath
assert_equal "foo=bar", request.env["QUERY_STRING"]
assert_equal 'foo=bar', request.query_string
assert_equal 'bar', request.parameters['foo']
@@ -363,8 +341,8 @@ class IntegrationProcessTest < ActionController::IntegrationTest
def test_get_with_parameters
with_test_route_set do
get '/get_with_params', :foo => "bar"
- assert_equal '/get_with_params', request.env["REQUEST_URI"]
- assert_equal '/get_with_params', request.request_uri
+ assert_equal '/get_with_params', request.env["PATH_INFO"]
+ assert_equal '/get_with_params', request.path_info
assert_equal 'foo=bar', request.env["QUERY_STRING"]
assert_equal 'foo=bar', request.query_string
assert_equal 'bar', request.parameters['foo']
@@ -401,16 +379,26 @@ class IntegrationProcessTest < ActionController::IntegrationTest
private
def with_test_route_set
with_routing do |set|
+ controller = ::IntegrationProcessTest::IntegrationController.clone
+ controller.class_eval do
+ include set.url_helpers
+ end
+
set.draw do |map|
- match ':action', :to => ::IntegrationProcessTest::IntegrationController
- get 'get/:action', :to => ::IntegrationProcessTest::IntegrationController
+ match ':action', :to => controller
+ get 'get/:action', :to => controller
end
+
+ self.singleton_class.send(:include, set.url_helpers)
+
yield
end
end
end
class MetalIntegrationTest < ActionController::IntegrationTest
+ include SharedTestRoutes.url_helpers
+
class Poller
def self.call(env)
if env["PATH_INFO"] =~ /^\/success/
diff --git a/actionpack/test/controller/subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb
index d7c1166f14..20d3e77b6e 100644
--- a/actionpack/test/controller/subscriber_test.rb
+++ b/actionpack/test/controller/log_subscriber_test.rb
@@ -1,9 +1,9 @@
require "abstract_unit"
-require "rails/subscriber/test_helper"
-require "action_controller/railties/subscriber"
+require "rails/log_subscriber/test_helper"
+require "action_controller/railties/log_subscriber"
module Another
- class SubscribersController < ActionController::Base
+ class LogSubscribersController < ActionController::Base
def show
render :nothing => true
end
@@ -35,24 +35,24 @@ module Another
end
end
-class ACSubscriberTest < ActionController::TestCase
- tests Another::SubscribersController
- include Rails::Subscriber::TestHelper
+class ACLogSubscriberTest < ActionController::TestCase
+ tests Another::LogSubscribersController
+ include Rails::LogSubscriber::TestHelper
def setup
+ super
+
@old_logger = ActionController::Base.logger
@cache_path = File.expand_path('../temp/test_cache', File.dirname(__FILE__))
ActionController::Base.page_cache_directory = @cache_path
- ActionController::Base.cache_store = :file_store, @cache_path
-
- Rails::Subscriber.add(:action_controller, ActionController::Railties::Subscriber.new)
- super
+ @controller.cache_store = :file_store, @cache_path
+ Rails::LogSubscriber.add(:action_controller, ActionController::Railties::LogSubscriber.new)
end
def teardown
super
- Rails::Subscriber.subscribers.clear
+ Rails::LogSubscriber.log_subscribers.clear
FileUtils.rm_rf(@cache_path)
ActionController::Base.logger = @old_logger
end
@@ -65,7 +65,7 @@ class ACSubscriberTest < ActionController::TestCase
get :show
wait
assert_equal 2, logs.size
- assert_equal "Processing by Another::SubscribersController#show as HTML", logs.first
+ assert_equal "Processing by Another::LogSubscribersController#show as HTML", logs.first
end
def test_process_action
@@ -134,11 +134,11 @@ class ACSubscriberTest < ActionController::TestCase
end
def test_send_xfile
- get :xfile_sender
+ assert_deprecated { get :xfile_sender }
wait
assert_equal 3, logs.size
- assert_match /Sent X\-Sendfile header/, logs[1]
+ assert_match /Sent file/, logs[1]
assert_match /test\/fixtures\/company\.rb/, logs[1]
end
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index 3bd3369242..5c1eaf453c 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -155,13 +155,11 @@ class RespondToControllerTest < ActionController::TestCase
def setup
super
- ActionController::Base.use_accept_header = true
@request.host = "www.example.com"
end
def teardown
super
- ActionController::Base.use_accept_header = false
end
def test_html
@@ -513,7 +511,7 @@ class RespondWithController < ActionController::Base
protected
def resource
- Customer.new("david", 13)
+ Customer.new("david", request.delete? ? nil : 13)
end
def _render_js(js, options)
@@ -544,13 +542,11 @@ class RespondWithControllerTest < ActionController::TestCase
def setup
super
- ActionController::Base.use_accept_header = true
@request.host = "www.example.com"
end
def teardown
super
- ActionController::Base.use_accept_header = false
end
def test_using_resource
@@ -717,7 +713,7 @@ class RespondWithControllerTest < ActionController::TestCase
delete :using_resource
assert_equal "text/html", @response.content_type
assert_equal 302, @response.status
- assert_equal "http://www.example.com/customers/13", @response.location
+ assert_equal "http://www.example.com/customers", @response.location
end
end
diff --git a/actionpack/test/controller/new_base/render_rjs_test.rb b/actionpack/test/controller/new_base/render_rjs_test.rb
index 8c47b38ab6..f4516ade63 100644
--- a/actionpack/test/controller/new_base/render_rjs_test.rb
+++ b/actionpack/test/controller/new_base/render_rjs_test.rb
@@ -17,7 +17,7 @@ module RenderRjs
end
def index_locale
- old_locale, I18n.locale = I18n.locale, :da
+ self.locale = :da
end
end
diff --git a/actionpack/test/controller/record_identifier_test.rb b/actionpack/test/controller/record_identifier_test.rb
index 6b6d154faa..813dedc80d 100644
--- a/actionpack/test/controller/record_identifier_test.rb
+++ b/actionpack/test/controller/record_identifier_test.rb
@@ -5,6 +5,7 @@ class Comment
include ActiveModel::Conversion
attr_reader :id
+ def to_key; id ? [id] : nil end
def save; @id = 1 end
def new_record?; @id.nil? end
def name
diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb
index 570ff4a41b..441bc47908 100644
--- a/actionpack/test/controller/redirect_test.rb
+++ b/actionpack/test/controller/redirect_test.rb
@@ -6,14 +6,14 @@ end
class Workshop
extend ActiveModel::Naming
include ActiveModel::Conversion
- attr_accessor :id, :new_record
+ attr_accessor :id
- def initialize(id, new_record)
- @id, @new_record = id, new_record
+ def initialize(id)
+ @id = id
end
- def new_record?
- @new_record
+ def persisted?
+ id.present?
end
def to_s
@@ -88,11 +88,11 @@ class RedirectController < ActionController::Base
end
def redirect_to_existing_record
- redirect_to Workshop.new(5, false)
+ redirect_to Workshop.new(5)
end
def redirect_to_new_record
- redirect_to Workshop.new(5, true)
+ redirect_to Workshop.new(nil)
end
def redirect_to_nil
@@ -239,11 +239,11 @@ class RedirectTest < ActionController::TestCase
get :redirect_to_existing_record
assert_equal "http://test.host/workshops/5", redirect_to_url
- assert_redirected_to Workshop.new(5, false)
+ assert_redirected_to Workshop.new(5)
get :redirect_to_new_record
assert_equal "http://test.host/workshops", redirect_to_url
- assert_redirected_to Workshop.new(5, true)
+ assert_redirected_to Workshop.new(nil)
end
end
diff --git a/actionpack/test/controller/render_json_test.rb b/actionpack/test/controller/render_json_test.rb
index 3938fc7061..2580ada88b 100644
--- a/actionpack/test/controller/render_json_test.rb
+++ b/actionpack/test/controller/render_json_test.rb
@@ -18,6 +18,10 @@ class RenderJsonTest < ActionController::TestCase
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
+ def render_json_hello_world_with_status
+ render :json => ActiveSupport::JSON.encode(:hello => 'world'), :status => 401
+ end
+
def render_json_hello_world_with_callback
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert'
end
@@ -58,6 +62,12 @@ class RenderJsonTest < ActionController::TestCase
assert_equal 'application/json', @response.content_type
end
+ def test_render_json_with_status
+ get :render_json_hello_world_with_status
+ assert_equal '{"hello":"world"}', @response.body
+ assert_equal 401, @response.status
+ end
+
def test_render_json_with_callback
get :render_json_hello_world_with_callback
assert_equal 'alert({"hello":"world"})', @response.body
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 2c3dc2a72d..e3c4869391 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -21,6 +21,10 @@ class TestController < ActionController::Base
def hello_world
end
+ def hello_world_file
+ render :file => File.expand_path("../../fixtures/hello.html", __FILE__)
+ end
+
def conditional_hello
if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123])
render :action => 'hello_world'
@@ -214,6 +218,10 @@ class TestController < ActionController::Base
render :text => false
end
+ def render_text_with_resource
+ render :text => Customer.new("David")
+ end
+
# :ported:
def render_nothing_with_appendix
render :text => "appended"
@@ -347,7 +355,7 @@ class TestController < ActionController::Base
@before = "i'm before the render"
render_to_string :text => "foo"
@after = "i'm after the render"
- render :action => "test/hello_world"
+ render :template => "test/hello_world"
end
def render_to_string_with_exception
@@ -361,7 +369,7 @@ class TestController < ActionController::Base
rescue
end
@after = "i'm after the render"
- render :action => "test/hello_world"
+ render :template => "test/hello_world"
end
def accessing_params_in_template_with_layout
@@ -506,7 +514,7 @@ class TestController < ActionController::Base
def render_to_string_with_partial
@partial_only = render_to_string :partial => "partial_only"
@partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") }
- render :action => "test/hello_world"
+ render :template => "test/hello_world"
end
def partial_with_counter
@@ -747,6 +755,11 @@ class RenderTest < ActionController::TestCase
assert_equal "The secret is in the sauce\n", @response.body
end
+ def test_render_file
+ get :hello_world_file
+ assert_equal "Hello world!", @response.body
+ end
+
# :ported:
def test_render_file_as_string_with_instance_variables
get :render_file_as_string_with_instance_variables
@@ -817,6 +830,11 @@ class RenderTest < ActionController::TestCase
assert_equal 'appended', @response.body
end
+ def test_render_text_with_resource
+ get :render_text_with_resource
+ assert_equal 'name: "David"', @response.body
+ end
+
# :ported:
def test_attempt_to_access_object_method
assert_raise(ActionController::UnknownAction, "No action responded to [clone]") { get :clone }
diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb
index b5b0d0b9d5..4da6c954cf 100644
--- a/actionpack/test/controller/render_xml_test.rb
+++ b/actionpack/test/controller/render_xml_test.rb
@@ -62,7 +62,8 @@ class RenderXmlTest < ActionController::TestCase
with_routing do |set|
set.draw do |map|
resources :customers
- match ':controller/:action'
+ # match ':controller/:action'
+ map.connect ':controller/:action/:id'
end
get :render_with_object_location
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index 37367eaafc..dd991898a8 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -326,7 +326,7 @@ class RescueTest < ActionController::IntegrationTest
end
test 'rescue routing exceptions' do
- @app = ActionDispatch::Rescue.new(ActionController::Routing::Routes) do
+ @app = ActionDispatch::Rescue.new(SharedTestRoutes) do
rescue_from ActionController::RoutingError, lambda { |env| [200, {"Content-Type" => "text/html"}, ["Gotcha!"]] }
end
@@ -335,7 +335,7 @@ class RescueTest < ActionController::IntegrationTest
end
test 'unrescued exception' do
- @app = ActionDispatch::Rescue.new(ActionController::Routing::Routes)
+ @app = ActionDispatch::Rescue.new(SharedTestRoutes)
assert_raise(ActionController::RoutingError) { get '/b00m' }
end
diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb
index 01ed491732..f60045bba6 100644
--- a/actionpack/test/controller/resources_test.rb
+++ b/actionpack/test/controller/resources_test.rb
@@ -31,10 +31,10 @@ end
class ResourcesTest < ActionController::TestCase
def test_should_arrange_actions
- resource = ActionDispatch::Routing::DeprecatedMapper::Resource.new(:messages,
+ resource = ActionDispatch::Routing::DeprecatedMapper::Resource.new(:messages, {
:collection => { :rss => :get, :reorder => :post, :csv => :post },
:member => { :rss => :get, :atom => :get, :upload => :post, :fix => :post },
- :new => { :preview => :get, :draft => :get })
+ :new => { :preview => :get, :draft => :get }}, {})
assert_resource_methods [:rss], resource, :collection, :get
assert_resource_methods [:csv, :reorder], resource, :collection, :post
@@ -44,18 +44,18 @@ class ResourcesTest < ActionController::TestCase
end
def test_should_resource_controller_name_equal_resource_name_by_default
- resource = ActionDispatch::Routing::DeprecatedMapper::Resource.new(:messages, {})
+ resource = ActionDispatch::Routing::DeprecatedMapper::Resource.new(:messages, {}, {})
assert_equal 'messages', resource.controller
end
def test_should_resource_controller_name_equal_controller_option
- resource = ActionDispatch::Routing::DeprecatedMapper::Resource.new(:messages, :controller => 'posts')
+ resource = ActionDispatch::Routing::DeprecatedMapper::Resource.new(:messages, {:controller => 'posts'}, {})
assert_equal 'posts', resource.controller
end
def test_should_all_singleton_paths_be_the_same
[ :path, :nesting_path_prefix, :member_path ].each do |method|
- resource = ActionDispatch::Routing::DeprecatedMapper::SingletonResource.new(:messages, :path_prefix => 'admin')
+ resource = ActionDispatch::Routing::DeprecatedMapper::SingletonResource.new(:messages, {:path_prefix => 'admin'}, {})
assert_equal 'admin/messages', resource.send(method)
end
end
@@ -111,8 +111,8 @@ class ResourcesTest < ActionController::TestCase
end
def test_override_paths_for_default_restful_actions
- resource = ActionDispatch::Routing::DeprecatedMapper::Resource.new(:messages,
- :path_names => {:new => 'nuevo', :edit => 'editar'})
+ resource = ActionDispatch::Routing::DeprecatedMapper::Resource.new(:messages, {
+ :path_names => {:new => 'nuevo', :edit => 'editar'}}, {})
assert_equal resource.new_path, "#{resource.path}/nuevo"
end
@@ -125,7 +125,7 @@ class ResourcesTest < ActionController::TestCase
def test_with_custom_conditions
with_restful_routing :messages, :conditions => { :subdomain => 'app' } do
- assert ActionDispatch::Routing::Routes.recognize_path("/messages", :method => :get, :subdomain => 'app')
+ assert @router.recognize_path("/messages", :method => :get, :subdomain => 'app')
end
end
@@ -394,7 +394,7 @@ class ResourcesTest < ActionController::TestCase
assert_restful_routes_for :messages do |options|
assert_recognizes(options.merge(:action => "new"), :path => "/messages/new", :method => :get)
assert_raise(ActionController::RoutingError) do
- ActionController::Routing::Routes.recognize_path("/messages/new", :method => :post)
+ @router.recognize_path("/messages/new", :method => :post)
end
end
end
@@ -504,7 +504,7 @@ class ResourcesTest < ActionController::TestCase
def test_restful_routes_dont_generate_duplicates
with_restful_routing :messages do
- routes = ActionController::Routing::Routes.routes
+ routes = @router.routes
routes.each do |route|
routes.each do |r|
next if route === r # skip the comparison instance
@@ -1162,8 +1162,9 @@ class ResourcesTest < ActionController::TestCase
options[:shallow_options] = options[:options]
end
- new_action = ActionController::Base.resources_path_names[:new] || "new"
- edit_action = ActionController::Base.resources_path_names[:edit] || "edit"
+ new_action = @router.resources_path_names[:new] || "new"
+ edit_action = @router.resources_path_names[:edit] || "edit"
+
if options[:path_names]
new_action = options[:path_names][:new] if options[:path_names][:new]
edit_action = options[:path_names][:edit] if options[:path_names][:edit]
@@ -1229,6 +1230,7 @@ class ResourcesTest < ActionController::TestCase
end
@controller = "#{options[:options][:controller].camelize}Controller".constantize.new
+ @controller.singleton_class.send(:include, @router.url_helpers)
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
get :index, options[:options]
@@ -1298,6 +1300,7 @@ class ResourcesTest < ActionController::TestCase
def assert_singleton_named_routes_for(singleton_name, options = {})
(options[:options] ||= {})[:controller] ||= singleton_name.to_s.pluralize
@controller = "#{options[:options][:controller].camelize}Controller".constantize.new
+ @controller.singleton_class.send(:include, @router.url_helpers)
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
get :show, options[:options]
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index f390bbdc89..fc85b01394 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -52,29 +52,17 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase
end
class MockController
- attr_accessor :routes
+ def self.build(helpers)
+ Class.new do
+ def url_for(options)
+ options[:protocol] ||= "http"
+ options[:host] ||= "test.host"
- def initialize(routes)
- self.routes = routes
- end
-
- def url_for(options)
- only_path = options.delete(:only_path)
-
- port = options.delete(:port) || 80
- port_string = port == 80 ? '' : ":#{port}"
-
- protocol = options.delete(:protocol) || "http"
- host = options.delete(:host) || "test.host"
- anchor = "##{options.delete(:anchor)}" if options.key?(:anchor)
-
- path = routes.generate(options)
-
- only_path ? "#{path}#{anchor}" : "#{protocol}://#{host}#{port_string}#{path}#{anchor}"
- end
+ super(options)
+ end
- def request
- @request ||= ActionController::TestRequest.new
+ include helpers
+ end
end
end
@@ -268,9 +256,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase
end
def setup_for_named_route
- klass = Class.new(MockController)
- rs.install_helpers(klass)
- klass.new(rs)
+ MockController.build(rs.url_helpers).new
end
def test_named_route_without_hash
@@ -759,9 +745,7 @@ class RouteSetTest < ActiveSupport::TestCase
map.users '/admin/users', :controller => 'admin/users', :action => 'index'
end
- klass = Class.new(MockController)
- set.install_helpers(klass)
- klass.new(set)
+ MockController.build(set.url_helpers).new
end
def test_named_route_hash_access_method
diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb
index 0afebac68c..30c9a65b7c 100644
--- a/actionpack/test/controller/send_file_test.rb
+++ b/actionpack/test/controller/send_file_test.rb
@@ -46,44 +46,32 @@ class SendFileTest < ActionController::TestCase
response = nil
assert_nothing_raised { response = process('file') }
assert_not_nil response
- assert_kind_of String, response.body
- assert_equal file_data, response.body
+ body = response.body
+ assert_kind_of String, body
+ assert_equal file_data, body
end
def test_file_stream
- pending do
- response = nil
- assert_nothing_raised { response = process('file') }
- assert_not_nil response
- assert_kind_of Array, response.body_parts
-
- require 'stringio'
- output = StringIO.new
- output.binmode
- output.string.force_encoding(file_data.encoding) if output.string.respond_to?(:force_encoding)
- assert_nothing_raised { response.body_parts.each { |part| output << part.to_s } }
- assert_equal file_data, output.string
- end
- end
-
- def test_file_url_based_filename
- @controller.options = { :url_based_filename => true }
response = nil
assert_nothing_raised { response = process('file') }
assert_not_nil response
- assert_equal "attachment", response.headers["Content-Disposition"]
- end
+ assert response.body_parts.respond_to?(:each)
+ assert response.body_parts.respond_to?(:to_path)
- def test_x_sendfile_header
- @controller.options = { :x_sendfile => true }
+ require 'stringio'
+ output = StringIO.new
+ output.binmode
+ output.string.force_encoding(file_data.encoding) if output.string.respond_to?(:force_encoding)
+ assert_nothing_raised { response.body_parts.each { |part| output << part.to_s } }
+ assert_equal file_data, output.string
+ end
+ def test_file_url_based_filename
+ @controller.options = { :url_based_filename => true }
response = nil
assert_nothing_raised { response = process('file') }
assert_not_nil response
-
- assert_equal @controller.file_path, response.headers['X-Sendfile']
- assert response.body.blank?
- assert !response.etag?
+ assert_equal "attachment", response.headers["Content-Disposition"]
end
def test_data
@@ -104,9 +92,8 @@ class SendFileTest < ActionController::TestCase
end
# Test that send_file_headers! is setting the correct HTTP headers.
- def test_send_file_headers!
+ def test_send_file_headers_bang
options = {
- :length => 1,
:type => Mime::PNG,
:disposition => 'disposition',
:filename => 'filename'
@@ -121,13 +108,11 @@ class SendFileTest < ActionController::TestCase
@controller.send(:send_file_headers!, options)
h = @controller.headers
- assert_equal '1', h['Content-Length']
assert_equal 'image/png', @controller.content_type
assert_equal 'disposition; filename="filename"', h['Content-Disposition']
assert_equal 'binary', h['Content-Transfer-Encoding']
# test overriding Cache-Control: no-cache header to fix IE open/save dialog
- @controller.headers = { 'Cache-Control' => 'no-cache' }
@controller.send(:send_file_headers!, options)
@controller.response.prepare!
assert_equal 'private', h['Cache-Control']
@@ -135,7 +120,6 @@ class SendFileTest < ActionController::TestCase
def test_send_file_headers_with_mime_lookup_with_symbol
options = {
- :length => 1,
:type => :png
}
@@ -148,7 +132,6 @@ class SendFileTest < ActionController::TestCase
def test_send_file_headers_with_bad_symbol
options = {
- :length => 1,
:type => :this_type_is_not_registered
}
@@ -163,17 +146,16 @@ class SendFileTest < ActionController::TestCase
assert_equal 500, @response.status
end
+ define_method "test_send_#{method}_content_type" do
+ @controller.options = { :stream => false, :content_type => "application/x-ruby" }
+ assert_nothing_raised { assert_not_nil process(method) }
+ assert_equal "application/x-ruby", @response.content_type
+ end
+
define_method "test_default_send_#{method}_status" do
@controller.options = { :stream => false }
assert_nothing_raised { assert_not_nil process(method) }
assert_equal 200, @response.status
end
end
-
- def test_send_data_content_length_header
- @controller.headers = {}
- @controller.options = { :type => :text, :filename => 'file_with_utf8_text' }
- process('multibyte_text_data')
- assert_equal '29', @controller.headers['Content-Length']
- end
end
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index 0f074b32e6..f6ba275849 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -42,7 +42,7 @@ class TestTest < ActionController::TestCase
end
def test_uri
- render :text => request.request_uri
+ render :text => request.fullpath
end
def test_query_string
@@ -128,6 +128,7 @@ XML
@controller = TestController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
+ @request.env['PATH_INFO'] = nil
end
def test_raw_post_handling
@@ -199,7 +200,7 @@ XML
end
def test_process_with_request_uri_with_params_with_explicit_uri
- @request.request_uri = "/explicit/uri"
+ @request.env['PATH_INFO'] = "/explicit/uri"
process :test_uri, :id => 7
assert_equal "/explicit/uri", @response.body
end
@@ -210,7 +211,8 @@ XML
end
def test_process_with_query_string_with_explicit_uri
- @request.request_uri = "/explicit/uri?q=test?extra=question"
+ @request.env['PATH_INFO'] = '/explicit/uri'
+ @request.env['QUERY_STRING'] = 'q=test?extra=question'
process :test_query_string
assert_equal "q=test?extra=question", @response.body
end
@@ -476,8 +478,8 @@ XML
end
def test_with_routing_places_routes_back
- assert ActionController::Routing::Routes
- routes_id = ActionController::Routing::Routes.object_id
+ assert @router
+ routes_id = @router.object_id
begin
with_routing { raise 'fail' }
@@ -485,8 +487,8 @@ XML
rescue RuntimeError
end
- assert ActionController::Routing::Routes
- assert_equal routes_id, ActionController::Routing::Routes.object_id
+ assert @router
+ assert_equal routes_id, @router.object_id
end
def test_remote_addr
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 749fa5861f..fc7773dffe 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -5,7 +5,7 @@ module AbstractController
class UrlForTests < ActionController::TestCase
class W
- include ActionController::UrlFor
+ include SharedTestRoutes.url_helpers
end
def teardown
@@ -113,15 +113,13 @@ module AbstractController
end
def test_relative_url_root_is_respected
- orig_relative_url_root = ActionController::Base.relative_url_root
- ActionController::Base.relative_url_root = '/subdir'
+ # ROUTES TODO: Tests should not have to pass :relative_url_root directly. This
+ # should probably come from the router.
add_host!
assert_equal('https://www.basecamphq.com/subdir/c/a/i',
- W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https')
+ W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https', :script_name => '/subdir')
)
- ensure
- ActionController::Base.relative_url_root = orig_relative_url_root
end
def test_named_routes
@@ -132,7 +130,8 @@ module AbstractController
end
# We need to create a new class in order to install the new named route.
- kls = Class.new { include ActionController::UrlFor }
+ kls = Class.new { include set.url_helpers }
+
controller = kls.new
assert controller.respond_to?(:home_url)
assert_equal 'http://www.basecamphq.com/home/sweet/home/again',
@@ -145,22 +144,17 @@ module AbstractController
end
def test_relative_url_root_is_respected_for_named_routes
- orig_relative_url_root = ActionController::Base.relative_url_root
- ActionController::Base.relative_url_root = '/subdir'
-
with_routing do |set|
set.draw do |map|
match '/home/sweet/home/:user', :to => 'home#index', :as => :home
end
- kls = Class.new { include ActionController::UrlFor }
+ kls = Class.new { include set.url_helpers }
controller = kls.new
assert_equal 'http://www.basecamphq.com/subdir/home/sweet/home/again',
- controller.send(:home_url, :host => 'www.basecamphq.com', :user => 'again')
+ controller.send(:home_url, :host => 'www.basecamphq.com', :user => 'again', :script_name => "/subdir")
end
- ensure
- ActionController::Base.relative_url_root = orig_relative_url_root
end
def test_only_path
@@ -171,7 +165,7 @@ module AbstractController
end
# We need to create a new class in order to install the new named route.
- kls = Class.new { include ActionController::UrlFor }
+ kls = Class.new { include set.url_helpers }
controller = kls.new
assert controller.respond_to?(:home_url)
assert_equal '/brave/new/world',
@@ -239,7 +233,7 @@ module AbstractController
end
# We need to create a new class in order to install the new named route.
- kls = Class.new { include ActionController::UrlFor }
+ kls = Class.new { include set.url_helpers }
kls.default_url_options[:host] = 'www.basecamphq.com'
controller = kls.new
diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb
index c2b8cd85d8..7b46a48a1d 100644
--- a/actionpack/test/controller/url_rewriter_test.rb
+++ b/actionpack/test/controller/url_rewriter_test.rb
@@ -1,102 +1,85 @@
require 'abstract_unit'
require 'controller/fake_controllers'
-ActionController::UrlRewriter
-
class UrlRewriterTests < ActionController::TestCase
+ class Rewriter
+ def initialize(request)
+ @options = {
+ :host => request.host_with_port,
+ :protocol => request.protocol
+ }
+ end
+
+ def rewrite(router, options)
+ router.url_for(@options.merge(options))
+ end
+ end
+
def setup
@request = ActionController::TestRequest.new
@params = {}
- @rewriter = ActionController::UrlRewriter.new(@request, @params)
+ @rewriter = Rewriter.new(@request) #.new(@request, @params)
end
def test_port
assert_equal('http://test.host:1271/c/a/i',
- @rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :port => 1271)
+ @rewriter.rewrite(@router, :controller => 'c', :action => 'a', :id => 'i', :port => 1271)
)
end
def test_protocol_with_and_without_separator
assert_equal('https://test.host/c/a/i',
- @rewriter.rewrite(:protocol => 'https', :controller => 'c', :action => 'a', :id => 'i')
+ @rewriter.rewrite(@router, :protocol => 'https', :controller => 'c', :action => 'a', :id => 'i')
)
assert_equal('https://test.host/c/a/i',
- @rewriter.rewrite(:protocol => 'https://', :controller => 'c', :action => 'a', :id => 'i')
+ @rewriter.rewrite(@router, :protocol => 'https://', :controller => 'c', :action => 'a', :id => 'i')
)
end
def test_user_name_and_password
assert_equal(
'http://david:secret@test.host/c/a/i',
- @rewriter.rewrite(:user => "david", :password => "secret", :controller => 'c', :action => 'a', :id => 'i')
+ @rewriter.rewrite(@router, :user => "david", :password => "secret", :controller => 'c', :action => 'a', :id => 'i')
)
end
def test_user_name_and_password_with_escape_codes
assert_equal(
'http://openid.aol.com%2Fnextangler:one+two%3F@test.host/c/a/i',
- @rewriter.rewrite(:user => "openid.aol.com/nextangler", :password => "one two?", :controller => 'c', :action => 'a', :id => 'i')
+ @rewriter.rewrite(@router, :user => "openid.aol.com/nextangler", :password => "one two?", :controller => 'c', :action => 'a', :id => 'i')
)
end
def test_anchor
assert_equal(
'http://test.host/c/a/i#anchor',
- @rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :anchor => 'anchor')
+ @rewriter.rewrite(@router, :controller => 'c', :action => 'a', :id => 'i', :anchor => 'anchor')
)
end
def test_anchor_should_call_to_param
assert_equal(
'http://test.host/c/a/i#anchor',
- @rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anchor'))
+ @rewriter.rewrite(@router, :controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anchor'))
)
end
def test_anchor_should_be_cgi_escaped
assert_equal(
'http://test.host/c/a/i#anc%2Fhor',
- @rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anc/hor'))
+ @rewriter.rewrite(@router, :controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anc/hor'))
)
end
- def test_overwrite_params
- @params[:controller] = 'hi'
- @params[:action] = 'bye'
- @params[:id] = '2'
-
- assert_equal '/hi/hi/2', @rewriter.rewrite(:only_path => true, :overwrite_params => {:action => 'hi'})
- u = @rewriter.rewrite(:only_path => false, :overwrite_params => {:action => 'hi'})
- assert_match %r(/hi/hi/2$), u
- end
-
- def test_overwrite_removes_original
- @params[:controller] = 'search'
- @params[:action] = 'list'
- @params[:list_page] = 1
-
- assert_equal '/search/list?list_page=2', @rewriter.rewrite(:only_path => true, :overwrite_params => {"list_page" => 2})
- u = @rewriter.rewrite(:only_path => false, :overwrite_params => {:list_page => 2})
- assert_equal 'http://test.host/search/list?list_page=2', u
- end
-
- def test_to_str
- @params[:controller] = 'hi'
- @params[:action] = 'bye'
- @request.parameters[:id] = '2'
-
- assert_equal 'http://, test.host, /, hi, bye, {"id"=>"2"}', @rewriter.to_str
- end
-
def test_trailing_slash
options = {:controller => 'foo', :action => 'bar', :id => '3', :only_path => true}
- assert_equal '/foo/bar/3', @rewriter.rewrite(options)
- assert_equal '/foo/bar/3?query=string', @rewriter.rewrite(options.merge({:query => 'string'}))
+ assert_equal '/foo/bar/3', @rewriter.rewrite(@router, options)
+ assert_equal '/foo/bar/3?query=string', @rewriter.rewrite(@router, options.merge({:query => 'string'}))
options.update({:trailing_slash => true})
- assert_equal '/foo/bar/3/', @rewriter.rewrite(options)
+ assert_equal '/foo/bar/3/', @rewriter.rewrite(@router, options)
options.update({:query => 'string'})
- assert_equal '/foo/bar/3/?query=string', @rewriter.rewrite(options)
+ assert_equal '/foo/bar/3/?query=string', @rewriter.rewrite(@router, options)
end
end
diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb
index 56821332c5..b8972b04b6 100644
--- a/actionpack/test/controller/view_paths_test.rb
+++ b/actionpack/test/controller/view_paths_test.rb
@@ -36,9 +36,12 @@ class ViewLoadPathsTest < ActionController::TestCase
@old_behavior = ActiveSupport::Deprecation.behavior
@last_message = nil
ActiveSupport::Deprecation.behavior = Proc.new { |message, callback| @last_message = message }
+
+ @paths = TestController.view_paths
end
def teardown
+ TestController.view_paths = @paths
ActiveSupport::Deprecation.behavior = @old_behavior
end
diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb
index 5882a8cfa3..05545395fb 100644
--- a/actionpack/test/controller/webservice_test.rb
+++ b/actionpack/test/controller/webservice_test.rb
@@ -245,7 +245,7 @@ class WebServiceTest < ActionController::IntegrationTest
private
def with_params_parsers(parsers = {})
old_session = @integration_session
- @app = ActionDispatch::ParamsParser.new(ActionController::Routing::Routes, parsers)
+ @app = ActionDispatch::ParamsParser.new(app.router, parsers)
reset!
yield
ensure
diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb
new file mode 100644
index 0000000000..00ca5ec9dc
--- /dev/null
+++ b/actionpack/test/dispatch/mount_test.rb
@@ -0,0 +1,36 @@
+require 'abstract_unit'
+
+class TestRoutingMount < ActionDispatch::IntegrationTest
+ Router = ActionDispatch::Routing::RouteSet.new
+ Router.draw do
+ SprocketsApp = lambda { |env|
+ [200, {"Content-Type" => "text/html"}, ["#{env["SCRIPT_NAME"]} -- #{env["PATH_INFO"]}"]]
+ }
+
+ mount SprocketsApp, :at => "/sprockets"
+ mount SprocketsApp => "/shorthand"
+
+ scope "/its_a" do
+ mount SprocketsApp, :at => "/sprocket"
+ end
+ end
+
+ def app
+ Router
+ end
+
+ def test_mounting_sets_script_name
+ get "/sprockets/omg"
+ assert_equal "/sprockets -- /omg", response.body
+ end
+
+ def test_mounting_works_with_scope
+ get "/its_a/sprocket/omg"
+ assert_equal "/its_a/sprocket -- /omg", response.body
+ end
+
+ def test_mounting_with_shorthand
+ get "/shorthand/omg"
+ assert_equal "/shorthand -- /omg", response.body
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 2b5c19361a..badef4e92e 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -1,14 +1,6 @@
require 'abstract_unit'
class RequestTest < ActiveSupport::TestCase
- def setup
- ActionController::Base.relative_url_root = nil
- end
-
- def teardown
- ActionController::Base.relative_url_root = nil
- end
-
test "remote ip" do
request = stub_request 'REMOTE_ADDR' => '1.2.3.4'
assert_equal '1.2.3.4', request.remote_ip
@@ -50,7 +42,7 @@ class RequestTest < ActiveSupport::TestCase
request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
'HTTP_CLIENT_IP' => '2.2.2.2'
- e = assert_raise(ActionController::ActionControllerError) {
+ e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
request.remote_ip
}
assert_match /IP spoofing attack/, e.message
@@ -62,18 +54,17 @@ class RequestTest < ActiveSupport::TestCase
# example is WAP. Since the cellular network is not IP based, it's a
# leap of faith to assume that their proxies are ever going to set the
# HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly.
- ActionController::Base.ip_spoofing_check = false
request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
- 'HTTP_CLIENT_IP' => '2.2.2.2'
+ 'HTTP_CLIENT_IP' => '2.2.2.2',
+ :ip_spoofing_check => false
assert_equal '2.2.2.2', request.remote_ip
- ActionController::Base.ip_spoofing_check = true
request = stub_request 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
assert_equal '9.9.9.9', request.remote_ip
end
test "remote ip with user specified trusted proxies" do
- ActionController::Base.trusted_proxies = /^67\.205\.106\.73$/i
+ @trusted_proxies = /^67\.205\.106\.73$/i
request = stub_request 'REMOTE_ADDR' => '67.205.106.73',
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
@@ -96,8 +87,6 @@ class RequestTest < ActiveSupport::TestCase
request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 67.205.106.73'
assert_equal '3.4.5.6', request.remote_ip
-
- ActionController::Base.trusted_proxies = nil
end
test "domains" do
@@ -151,104 +140,34 @@ class RequestTest < ActiveSupport::TestCase
assert_equal ":8080", request.port_string
end
- test "request uri" do
- request = stub_request 'REQUEST_URI' => "http://www.rubyonrails.org/path/of/some/uri?mapped=1"
- assert_equal "/path/of/some/uri?mapped=1", request.request_uri
- assert_equal "/path/of/some/uri", request.path
-
- request = stub_request 'REQUEST_URI' => "http://www.rubyonrails.org/path/of/some/uri"
- assert_equal "/path/of/some/uri", request.request_uri
- assert_equal "/path/of/some/uri", request.path
-
- request = stub_request 'REQUEST_URI' => "/path/of/some/uri"
- assert_equal "/path/of/some/uri", request.request_uri
- assert_equal "/path/of/some/uri", request.path
-
- request = stub_request 'REQUEST_URI' => "/"
- assert_equal "/", request.request_uri
- assert_equal "/", request.path
-
- request = stub_request 'REQUEST_URI' => "/?m=b"
- assert_equal "/?m=b", request.request_uri
- assert_equal "/", request.path
-
- request = stub_request 'REQUEST_URI' => "/", 'SCRIPT_NAME' => '/dispatch.cgi'
- assert_equal "/", request.request_uri
- assert_equal "/", request.path
-
- ActionController::Base.relative_url_root = "/hieraki"
- request = stub_request 'REQUEST_URI' => "/hieraki/", 'SCRIPT_NAME' => "/hieraki/dispatch.cgi"
- assert_equal "/hieraki/", request.request_uri
- assert_equal "/", request.path
- ActionController::Base.relative_url_root = nil
-
- ActionController::Base.relative_url_root = "/collaboration/hieraki"
- request = stub_request 'REQUEST_URI' => "/collaboration/hieraki/books/edit/2",
- 'SCRIPT_NAME' => "/collaboration/hieraki/dispatch.cgi"
- assert_equal "/collaboration/hieraki/books/edit/2", request.request_uri
- assert_equal "/books/edit/2", request.path
- ActionController::Base.relative_url_root = nil
-
- # The following tests are for when REQUEST_URI is not supplied (as in IIS)
- request = stub_request 'PATH_INFO' => "/path/of/some/uri?mapped=1",
- 'SCRIPT_NAME' => nil,
- 'REQUEST_URI' => nil
- assert_equal "/path/of/some/uri?mapped=1", request.request_uri
- assert_equal "/path/of/some/uri", request.path
-
- ActionController::Base.relative_url_root = '/path'
- request = stub_request 'PATH_INFO' => "/path/of/some/uri?mapped=1",
- 'SCRIPT_NAME' => "/path/dispatch.rb",
- 'REQUEST_URI' => nil
- assert_equal "/path/of/some/uri?mapped=1", request.request_uri
- assert_equal "/of/some/uri", request.path
- ActionController::Base.relative_url_root = nil
-
- request = stub_request 'PATH_INFO' => "/path/of/some/uri",
- 'SCRIPT_NAME' => nil,
- 'REQUEST_URI' => nil
- assert_equal "/path/of/some/uri", request.request_uri
- assert_equal "/path/of/some/uri", request.path
-
- request = stub_request 'PATH_INFO' => '/', 'REQUEST_URI' => nil
- assert_equal "/", request.request_uri
- assert_equal "/", request.path
-
- request = stub_request 'PATH_INFO' => '/?m=b', 'REQUEST_URI' => nil
- assert_equal "/?m=b", request.request_uri
- assert_equal "/", request.path
-
- request = stub_request 'PATH_INFO' => "/",
- 'SCRIPT_NAME' => "/dispatch.cgi",
- 'REQUEST_URI' => nil
- assert_equal "/", request.request_uri
- assert_equal "/", request.path
-
- ActionController::Base.relative_url_root = '/hieraki'
- request = stub_request 'PATH_INFO' => "/hieraki/",
- 'SCRIPT_NAME' => "/hieraki/dispatch.cgi",
- 'REQUEST_URI' => nil
- assert_equal "/hieraki/", request.request_uri
- assert_equal "/", request.path
- ActionController::Base.relative_url_root = nil
-
- request = stub_request 'REQUEST_URI' => '/hieraki/dispatch.cgi'
- ActionController::Base.relative_url_root = '/hieraki'
- assert_equal "/dispatch.cgi", request.path
- ActionController::Base.relative_url_root = nil
-
- request = stub_request 'REQUEST_URI' => '/hieraki/dispatch.cgi'
- ActionController::Base.relative_url_root = '/foo'
- assert_equal "/hieraki/dispatch.cgi", request.path
- ActionController::Base.relative_url_root = nil
-
- # This test ensures that Rails uses REQUEST_URI over PATH_INFO
- ActionController::Base.relative_url_root = nil
- request = stub_request 'REQUEST_URI' => "/some/path",
- 'PATH_INFO' => "/another/path",
- 'SCRIPT_NAME' => "/dispatch.cgi"
- assert_equal "/some/path", request.request_uri
- assert_equal "/some/path", request.path
+ test "full path" do
+ request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri', 'QUERY_STRING' => 'mapped=1'
+ assert_equal "/path/of/some/uri?mapped=1", request.fullpath
+ assert_equal "/path/of/some/uri", request.path_info
+
+ request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri'
+ assert_equal "/path/of/some/uri", request.fullpath
+ assert_equal "/path/of/some/uri", request.path_info
+
+ request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/'
+ assert_equal "/", request.fullpath
+ assert_equal "/", request.path_info
+
+ request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/', 'QUERY_STRING' => 'm=b'
+ assert_equal "/?m=b", request.fullpath
+ assert_equal "/", request.path_info
+
+ request = stub_request 'SCRIPT_NAME' => '/hieraki', 'PATH_INFO' => '/'
+ assert_equal "/hieraki/", request.fullpath
+ assert_equal "/", request.path_info
+
+ request = stub_request 'SCRIPT_NAME' => '/collaboration/hieraki', 'PATH_INFO' => '/books/edit/2'
+ assert_equal "/collaboration/hieraki/books/edit/2", request.fullpath
+ assert_equal "/books/edit/2", request.path_info
+
+ request = stub_request 'SCRIPT_NAME' => '/path', 'PATH_INFO' => '/of/some/uri', 'QUERY_STRING' => 'mapped=1'
+ assert_equal "/path/of/some/uri?mapped=1", request.fullpath
+ assert_equal "/of/some/uri", request.path_info
end
@@ -462,7 +381,7 @@ class RequestTest < ActiveSupport::TestCase
[{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'],
[{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'],
[{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana'],
- [{'baz'=>[{'foo'=>'baz'}]}, {'baz'=>[{'foo'=>'[FILTERED]'}]}, [/foo/]]]
+ [{'baz'=>[{'foo'=>'baz'}, "1"]}, {'baz'=>[{'foo'=>'[FILTERED]'}, "1"]}, [/foo/]]]
test_hashes.each do |before_filter, after_filter, filter_words|
request = stub_request('action_dispatch.parameter_filter' => filter_words)
@@ -506,18 +425,14 @@ class RequestTest < ActiveSupport::TestCase
protected
- def stub_request(env={})
+ def stub_request(env = {})
+ ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
+ ip_app = ActionDispatch::RemoteIp.new(Proc.new { }, ip_spoofing_check, @trusted_proxies)
+ ip_app.call(env)
ActionDispatch::Request.new(env)
end
def with_set(*args)
args
end
-
- def with_accept_header(value)
- ActionController::Base.use_accept_header, old = value, ActionController::Base.use_accept_header
- yield
- ensure
- ActionController::Base.use_accept_header = old
- end
end
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 4697fa3e2b..c7f7f3102d 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -165,10 +165,8 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest
assert_equal('public', @response.headers['Cache-Control'])
assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers['ETag'])
- pending do
- assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
- assert_equal({:public => true}, @response.cache_control)
- end
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
+ assert_equal({:public => true}, @response.cache_control)
end
test "response cache control from rackish app" do
@@ -184,10 +182,8 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest
assert_equal('public', @response.headers['Cache-Control'])
assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers['ETag'])
- pending do
- assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
- assert_equal({:public => true}, @response.cache_control)
- end
+ assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
+ assert_equal({:public => true}, @response.cache_control)
end
test "response charset and content type from railsish app" do
@@ -202,10 +198,8 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest
get '/'
assert_response :success
- pending do
- assert_equal('utf-16', @response.charset)
- assert_equal(Mime::XML, @response.content_type)
- end
+ assert_equal('utf-16', @response.charset)
+ assert_equal(Mime::XML, @response.content_type)
assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type'])
end
@@ -220,10 +214,8 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest
get '/'
assert_response :success
- pending do
- assert_equal('utf-16', @response.charset)
- assert_equal(Mime::XML, @response.content_type)
- end
+ assert_equal('utf-16', @response.charset)
+ assert_equal(Mime::XML, @response.content_type)
assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type'])
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index bcb97e4ae0..f5fcf9b0df 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -15,6 +15,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
stub_controllers do |routes|
Routes = routes
Routes.draw do
+ default_url_options :host => "rubyonrails.org"
+
controller :sessions do
get 'login' => :new, :as => :login
post 'login' => :create
@@ -24,6 +26,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
resource :session do
get :create
+
+ resource :info
end
match 'account/logout' => redirect("/logout"), :as => :logout_redirect
@@ -104,7 +108,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
- resources :posts, :only => [:index, :show]
+ resources :posts, :only => [:index, :show] do
+ resources :comments, :except => :destroy
+ end
match 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
@@ -162,6 +168,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
Routes
end
+ include Routes.url_helpers
+
def test_logout
with_test_routes do
delete '/logout'
@@ -183,6 +191,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/login', url_for(:controller => 'sessions', :action => 'create', :only_path => true)
assert_equal '/login', url_for(:controller => 'sessions', :action => 'new', :only_path => true)
+
+ assert_equal 'http://rubyonrails.org/login', Routes.url_for(:controller => 'sessions', :action => 'create')
end
end
@@ -230,6 +240,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_session_info_nested_singleton_resource
+ with_test_routes do
+ get '/session/info'
+ assert_equal 'infos#show', @response.body
+ assert_equal '/session/info', session_info_path
+ end
+ end
+
def test_redirect_modulo
with_test_routes do
get '/account/modulo/name'
@@ -471,7 +489,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
- def test_posts
+ def test_resource_routes_with_only_and_except
with_test_routes do
get '/posts'
assert_equal 'posts#index', @response.body
@@ -481,9 +499,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'posts#show', @response.body
assert_equal '/posts/1', post_path(:id => 1)
+ get '/posts/1/comments'
+ assert_equal 'comments#index', @response.body
+ assert_equal '/posts/1/comments', post_comments_path(:post_id => 1)
+
assert_raise(ActionController::RoutingError) { post '/posts' }
assert_raise(ActionController::RoutingError) { put '/posts/1' }
assert_raise(ActionController::RoutingError) { delete '/posts/1' }
+ assert_raise(ActionController::RoutingError) { delete '/posts/1/comments' }
end
end
@@ -721,14 +744,6 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
private
def with_test_routes
- real_routes, temp_routes = ActionController::Routing::Routes, Routes
-
- ActionController::Routing.module_eval { remove_const :Routes }
- ActionController::Routing.module_eval { const_set :Routes, temp_routes }
-
yield
- ensure
- ActionController::Routing.module_eval { remove_const :Routes }
- ActionController::Routing.const_set(:Routes, real_routes)
end
end
diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb
new file mode 100644
index 0000000000..18b5b7ee00
--- /dev/null
+++ b/actionpack/test/dispatch/url_generation_test.rb
@@ -0,0 +1,38 @@
+require 'abstract_unit'
+
+module TestUrlGeneration
+ class WithMountPoint < ActionDispatch::IntegrationTest
+ Router = ActionDispatch::Routing::RouteSet.new
+ Router.draw { match "/foo", :to => "my_route_generating#index", :as => :foo }
+
+ class ::MyRouteGeneratingController < ActionController::Base
+ include Router.url_helpers
+ def index
+ render :text => foo_path
+ end
+ end
+
+ include Router.url_helpers
+
+ def _router
+ Router
+ end
+
+ def app
+ Router
+ end
+
+ test "generating URLS normally" do
+ assert_equal "/foo", foo_path
+ end
+
+ test "accepting a :script_name option" do
+ assert_equal "/bar/foo", foo_path(:script_name => "/bar")
+ end
+
+ test "the request's SCRIPT_NAME takes precedence over the router's" do
+ get "/foo", {}, 'SCRIPT_NAME' => "/new"
+ assert_equal "/new/foo", response.body
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/fixtures/hello.html b/actionpack/test/fixtures/hello.html
new file mode 100644
index 0000000000..6769dd60bd
--- /dev/null
+++ b/actionpack/test/fixtures/hello.html
@@ -0,0 +1 @@
+Hello world! \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/layout_render_file.erb b/actionpack/test/fixtures/test/layout_render_file.erb
new file mode 100644
index 0000000000..2f8e921c5f
--- /dev/null
+++ b/actionpack/test/fixtures/test/layout_render_file.erb
@@ -0,0 +1,2 @@
+<% content_for :title do %>title<% end -%>
+<%= render :file => 'layouts/yield' -%> \ No newline at end of file
diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb
index 7346cb22bc..bf3e175f1f 100644
--- a/actionpack/test/lib/controller/fake_models.rb
+++ b/actionpack/test/lib/controller/fake_models.rb
@@ -6,10 +6,6 @@ class Customer < Struct.new(:name, :id)
undef_method :to_json
- def to_param
- id.to_s
- end
-
def to_xml(options={})
if options[:builder]
options[:builder].name name
@@ -21,13 +17,14 @@ class Customer < Struct.new(:name, :id)
def to_js(options={})
"name: #{name.inspect}"
end
+ alias :to_text :to_js
def errors
[]
end
- def destroyed?
- false
+ def persisted?
+ id.present?
end
end
@@ -42,8 +39,8 @@ module Quiz
extend ActiveModel::Naming
include ActiveModel::Conversion
- def to_param
- id.to_s
+ def persisted?
+ id.present?
end
end
@@ -58,12 +55,12 @@ class Post < Struct.new(:title, :author_name, :body, :secret, :written_on, :cost
alias_method :secret?, :secret
- def new_record=(boolean)
- @new_record = boolean
+ def persisted=(boolean)
+ @persisted = boolean
end
- def new_record?
- @new_record
+ def persisted?
+ @persisted
end
attr_accessor :author
@@ -83,8 +80,9 @@ class Comment
attr_reader :id
attr_reader :post_id
def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end
+ def to_key; id ? [id] : nil end
def save; @id = 1; @post_id = 1 end
- def new_record?; @id.nil? end
+ def persisted?; @id.present? end
def to_param; @id; end
def name
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
@@ -102,8 +100,9 @@ class Tag
attr_reader :id
attr_reader :post_id
def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end
+ def to_key; id ? [id] : nil end
def save; @id = 1; @post_id = 1 end
- def new_record?; @id.nil? end
+ def persisted?; @id.present? end
def to_param; @id; end
def value
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
@@ -121,8 +120,9 @@ class CommentRelevance
attr_reader :id
attr_reader :comment_id
def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end
+ def to_key; id ? [id] : nil end
def save; @id = 1; @comment_id = 1 end
- def new_record?; @id.nil? end
+ def persisted?; @id.present? end
def to_param; @id; end
def value
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
@@ -136,8 +136,9 @@ class TagRelevance
attr_reader :id
attr_reader :tag_id
def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end
+ def to_key; id ? [id] : nil end
def save; @id = 1; @tag_id = 1 end
- def new_record?; @id.nil? end
+ def persisted?; @id.present? end
def to_param; @id; end
def value
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
diff --git a/actionpack/test/lib/fixture_template.rb b/actionpack/test/lib/fixture_template.rb
index 6b9e7c5270..02248d84ad 100644
--- a/actionpack/test/lib/fixture_template.rb
+++ b/actionpack/test/lib/fixture_template.rb
@@ -1,23 +1,28 @@
module ActionView #:nodoc:
class FixtureResolver < PathResolver
- def initialize(hash = {}, options = {})
- super(options)
+ attr_reader :hash
+
+ def initialize(hash = {})
+ super()
@hash = hash
end
private
- def query(path, exts)
+ def query(partial, path, exts)
query = Regexp.escape(path)
exts.each do |ext|
- query << '(?:' << ext.map {|e| e && Regexp.escape(".#{e}") }.join('|') << ')'
+ query << '(' << ext.map {|e| e && Regexp.escape(".#{e}") }.join('|') << ')'
end
templates = []
@hash.select { |k,v| k =~ /^#{query}$/ }.each do |path, source|
- templates << Template.new(source, path, *path_to_details(path))
+ handler, format = extract_handler_and_format(path)
+ templates << Template.new(source, path, handler,
+ :partial => partial, :virtual_path => path, :format => format)
end
- templates.sort_by {|t| -t.details.values.compact.size }
+
+ templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
end
end
diff --git a/actionpack/test/template/active_model_helper_test.rb b/actionpack/test/template/active_model_helper_test.rb
index 3e01ae78c3..371aa53c68 100644
--- a/actionpack/test/template/active_model_helper_test.rb
+++ b/actionpack/test/template/active_model_helper_test.rb
@@ -64,7 +64,7 @@ class ActiveModelHelperTest < ActionView::TestCase
}.new
end
- def @post.new_record?() true end
+ def @post.persisted?() false end
def @post.to_param() nil end
def @post.column_for_attribute(attr_name)
@@ -155,7 +155,7 @@ class ActiveModelHelperTest < ActionView::TestCase
silence_warnings do
class << @post
- def new_record?() false end
+ def persisted?() true end
def to_param() id end
def id() 1 end
end
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 586de66714..d9a89959da 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -1,14 +1,16 @@
require 'abstract_unit'
+require 'active_support/ordered_options'
-class AssetTagHelperTest < ActionView::TestCase
- tests ActionView::Helpers::AssetTagHelper
+class FakeController
+ attr_accessor :request
- DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG.merge(
- :assets_dir => File.dirname(__FILE__) + "/../fixtures/public",
- :javascripts_dir => File.dirname(__FILE__) + "/../fixtures/public/javascripts",
- :stylesheets_dir => File.dirname(__FILE__) + "/../fixtures/public/stylesheets")
+ def config
+ @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config)
+ end
+end
- include ActiveSupport::Configurable
+class AssetTagHelperTest < ActionView::TestCase
+ tests ActionView::Helpers::AssetTagHelper
def setup
super
@@ -32,8 +34,7 @@ class AssetTagHelperTest < ActionView::TestCase
)
end
- @controller = Class.new do
- attr_accessor :request
+ @controller = Class.new(BasicController) do
def url_for(*args) "http://www.example.com" end
end.new
@@ -50,7 +51,6 @@ class AssetTagHelperTest < ActionView::TestCase
def teardown
ActionController::Base.perform_caching = false
- ActionController::Base.asset_host = nil
ENV.delete('RAILS_ASSET_ID')
end
@@ -141,13 +141,16 @@ class AssetTagHelperTest < ActionView::TestCase
ImageLinkToTag = {
%(image_tag("xml.png")) => %(<img alt="Xml" src="/images/xml.png" />),
- %(image_tag("..jpg")) => %(<img alt="" src="/images/..jpg" />),
+ %(image_tag("..jpg")) => %(<img alt="..jpg" src="/images/..jpg" />),
%(image_tag("rss.gif", :alt => "rss syndication")) => %(<img alt="rss syndication" src="/images/rss.gif" />),
%(image_tag("gold.png", :size => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />),
%(image_tag("gold.png", "size" => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />),
%(image_tag("error.png", "size" => "45")) => %(<img alt="Error" src="/images/error.png" />),
%(image_tag("error.png", "size" => "45 x 70")) => %(<img alt="Error" src="/images/error.png" />),
%(image_tag("error.png", "size" => "x")) => %(<img alt="Error" src="/images/error.png" />),
+ %(image_tag("google.com.png")) => %(<img alt="Google.com" src="/images/google.com.png" />),
+ %(image_tag("slash..png")) => %(<img alt="Slash." src="/images/slash..png" />),
+ %(image_tag(".pdf.png")) => %(<img alt=".pdf" src="/images/.pdf.png" />),
%(image_tag("http://www.rubyonrails.com/images/rails.png")) => %(<img alt="Rails" src="http://www.rubyonrails.com/images/rails.png" />),
%(image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) => %(<img alt="Mouse" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" src="/images/mouse.png" />),
%(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(<img alt="Mouse" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" src="/images/mouse.png" />)
@@ -372,11 +375,9 @@ class AssetTagHelperTest < ActionView::TestCase
end
def test_timebased_asset_id_with_relative_url_root
- ActionController::Base.relative_url_root = "/collaboration/hieraki"
- expected_time = File.stat(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).mtime.to_i.to_s
- assert_equal %(<img alt="Rails" src="#{ActionController::Base.relative_url_root}/images/rails.png?#{expected_time}" />), image_tag("rails.png")
- ensure
- ActionController::Base.relative_url_root = ""
+ @controller.config.relative_url_root = "/collaboration/hieraki"
+ expected_time = File.stat(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).mtime.to_i.to_s
+ assert_equal %(<img alt="Rails" src="#{@controller.config.relative_url_root}/images/rails.png?#{expected_time}" />), image_tag("rails.png")
end
def test_should_skip_asset_id_on_complete_url
@@ -402,7 +403,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_image_path_with_caching_and_proc_asset_host_using_request
ENV['RAILS_ASSET_ID'] = ''
- ActionController::Base.asset_host = Proc.new do |source, request|
+ @controller.config.asset_host = Proc.new do |source, request|
if request.ssl?
"#{request.protocol}#{request.host_with_port}"
else
@@ -410,8 +411,6 @@ class AssetTagHelperTest < ActionView::TestCase
end
end
- ActionController::Base.perform_caching = true
-
@controller.request.stubs(:ssl?).returns(false)
assert_equal "http://assets15.example.com/images/xml.png", image_path("xml.png")
@@ -422,7 +421,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_javascript_include_tag_when_caching_on
ENV["RAILS_ASSET_ID"] = ""
- ActionController::Base.asset_host = 'http://a0.example.com'
+ @controller.config.asset_host = 'http://a0.example.com'
ActionController::Base.perform_caching = true
assert_dom_equal(
@@ -454,7 +453,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_javascript_include_tag_when_caching_on_with_proc_asset_host
ENV['RAILS_ASSET_ID'] = ''
- ActionController::Base.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" }
+ @controller.config.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" }
ActionController::Base.perform_caching = true
assert_equal '/javascripts/scripts.js'.length, 23
@@ -471,7 +470,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_javascript_include_tag_when_caching_on_with_2_argument_proc_asset_host
ENV['RAILS_ASSET_ID'] = ''
- ActionController::Base.asset_host = Proc.new { |source, request|
+ @controller.config.asset_host = Proc.new { |source, request|
if request.ssl?
"#{request.protocol}#{request.host_with_port}"
else
@@ -508,7 +507,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_javascript_include_tag_when_caching_on_with_2_argument_object_asset_host
ENV['RAILS_ASSET_ID'] = ''
- ActionController::Base.asset_host = Class.new do
+ @controller.config.asset_host = Class.new do
def call(source, request)
if request.ssl?
"#{request.protocol}#{request.host_with_port}"
@@ -548,7 +547,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_javascript_include_tag_when_caching_on_and_using_subdirectory
ENV["RAILS_ASSET_ID"] = ""
- ActionController::Base.asset_host = 'http://a%d.example.com'
+ @controller.config.asset_host = 'http://a%d.example.com'
ActionController::Base.perform_caching = true
hash = '/javascripts/cache/money.js'.hash % 4
@@ -564,7 +563,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_javascript_include_tag_with_all_and_recursive_puts_defaults_at_the_start_of_the_file
ENV["RAILS_ASSET_ID"] = ""
- ActionController::Base.asset_host = 'http://a0.example.com'
+ @controller.config.asset_host = 'http://a0.example.com'
ActionController::Base.perform_caching = true
assert_dom_equal(
@@ -585,7 +584,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_javascript_include_tag_with_all_puts_defaults_at_the_start_of_the_file
ENV["RAILS_ASSET_ID"] = ""
- ActionController::Base.asset_host = 'http://a0.example.com'
+ @controller.config.asset_host = 'http://a0.example.com'
ActionController::Base.perform_caching = true
assert_dom_equal(
@@ -606,7 +605,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_javascript_include_tag_with_relative_url_root
ENV["RAILS_ASSET_ID"] = ""
- ActionController::Base.relative_url_root = "/collaboration/hieraki"
+ @controller.config.relative_url_root = "/collaboration/hieraki"
ActionController::Base.perform_caching = true
assert_dom_equal(
@@ -624,7 +623,6 @@ class AssetTagHelperTest < ActionView::TestCase
assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js'))
ensure
- ActionController::Base.relative_url_root = nil
FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js'))
FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js'))
end
@@ -694,7 +692,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_stylesheet_link_tag_when_caching_on
ENV["RAILS_ASSET_ID"] = ""
- ActionController::Base.asset_host = 'http://a0.example.com'
+ @controller.config.asset_host = 'http://a0.example.com'
ActionController::Base.perform_caching = true
assert_dom_equal(
@@ -804,7 +802,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_stylesheet_link_tag_when_caching_on_with_proc_asset_host
ENV["RAILS_ASSET_ID"] = ""
- ActionController::Base.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" }
+ @controller.config.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" }
ActionController::Base.perform_caching = true
assert_equal '/stylesheets/styles.css'.length, 23
@@ -821,7 +819,7 @@ class AssetTagHelperTest < ActionView::TestCase
def test_caching_stylesheet_link_tag_with_relative_url_root
ENV["RAILS_ASSET_ID"] = ""
- ActionController::Base.relative_url_root = "/collaboration/hieraki"
+ @controller.config.relative_url_root = "/collaboration/hieraki"
ActionController::Base.perform_caching = true
assert_dom_equal(
@@ -841,7 +839,6 @@ class AssetTagHelperTest < ActionView::TestCase
assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css'))
ensure
- ActionController::Base.relative_url_root = nil
FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css'))
FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css'))
end
@@ -879,21 +876,16 @@ end
class AssetTagHelperNonVhostTest < ActionView::TestCase
tests ActionView::Helpers::AssetTagHelper
- DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG
- include ActiveSupport::Configurable
-
def setup
super
- ActionController::Base.relative_url_root = "/collaboration/hieraki"
-
- @controller = Class.new do
- attr_accessor :request
-
+ @controller = Class.new(BasicController) do
def url_for(options)
"http://www.example.com/collaboration/hieraki"
end
end.new
+ @controller.config.relative_url_root = "/collaboration/hieraki"
+
@request = Class.new do
def protocol
'gopher://'
@@ -905,10 +897,6 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
end
- def teardown
- ActionController::Base.relative_url_root = nil
- end
-
def test_should_compute_proper_path
assert_dom_equal(%(<link href="http://www.example.com/collaboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />), auto_discovery_link_tag)
assert_dom_equal(%(/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
@@ -923,43 +911,33 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
end
def test_should_compute_proper_path_with_asset_host
- ActionController::Base.asset_host = "http://assets.example.com"
+ @controller.config.asset_host = "http://assets.example.com"
assert_dom_equal(%(<link href="http://www.example.com/collaboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />), auto_discovery_link_tag)
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png"))
assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src='http://assets.example.com/collaboration/hieraki/images/mouse_over.png'" onmouseout="this.src='http://assets.example.com/collaboration/hieraki/images/mouse.png'" src="http://assets.example.com/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src='http://assets.example.com/collaboration/hieraki/images/mouse_over2.png'" onmouseout="this.src='http://assets.example.com/collaboration/hieraki/images/mouse2.png'" src="http://assets.example.com/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
- ensure
- ActionController::Base.asset_host = ""
end
def test_should_ignore_asset_host_on_complete_url
- ActionController::Base.asset_host = "http://assets.example.com"
+ @controller.config.asset_host = "http://assets.example.com"
assert_dom_equal(%(<link href="http://bar.example.com/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" />), stylesheet_link_tag("http://bar.example.com/stylesheets/style.css"))
- ensure
- ActionController::Base.asset_host = ""
end
def test_should_wildcard_asset_host_between_zero_and_four
- ActionController::Base.asset_host = 'http://a%d.example.com'
+ @controller.config.asset_host = 'http://a%d.example.com'
assert_match %r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path('xml.png')
- ensure
- ActionController::Base.asset_host = nil
end
def test_asset_host_without_protocol_should_use_request_protocol
- ActionController::Base.asset_host = 'a.example.com'
+ @controller.config.asset_host = 'a.example.com'
assert_equal 'gopher://a.example.com/collaboration/hieraki/images/xml.png', image_path('xml.png')
- ensure
- ActionController::Base.asset_host = nil
end
def test_asset_host_without_protocol_should_use_request_protocol_even_if_path_present
- ActionController::Base.asset_host = 'a.example.com/files/go/here'
+ @controller.config.asset_host = 'a.example.com/files/go/here'
assert_equal 'gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_path('xml.png')
- ensure
- ActionController::Base.asset_host = nil
end
def test_assert_css_and_js_of_the_same_name_return_correct_extension
diff --git a/actionpack/test/template/atom_feed_helper_test.rb b/actionpack/test/template/atom_feed_helper_test.rb
index 347cb98303..869ea22469 100644
--- a/actionpack/test/template/atom_feed_helper_test.rb
+++ b/actionpack/test/template/atom_feed_helper_test.rb
@@ -4,8 +4,8 @@ class Scroll < Struct.new(:id, :to_param, :title, :body, :updated_at, :created_a
extend ActiveModel::Naming
include ActiveModel::Conversion
- def new_record?
- true
+ def persisted?
+ false
end
end
@@ -34,7 +34,7 @@ class ScrollsController < ActionController::Base
feed.updated((@scrolls.first.created_at))
for scroll in @scrolls
- feed.entry(scroll, :url => "/otherstuff/" + scroll.to_param, :updated => Time.utc(2007, 1, scroll.id)) do |entry|
+ feed.entry(scroll, :url => "/otherstuff/" + scroll.to_param.to_s, :updated => Time.utc(2007, 1, scroll.id)) do |entry|
entry.title(scroll.title)
entry.content(scroll.body, :type => 'html')
@@ -55,7 +55,7 @@ class ScrollsController < ActionController::Base
end
for scroll in @scrolls
- feed.entry(scroll, :url => "/otherstuff/" + scroll.to_param, :updated => Time.utc(2007, 1, scroll.id)) do |entry|
+ feed.entry(scroll, :url => "/otherstuff/" + scroll.to_param.to_s, :updated => Time.utc(2007, 1, scroll.id)) do |entry|
entry.title(scroll.title)
entry.content(scroll.body, :type => 'html')
end
diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb
index 632988bb2e..2c719757e4 100644
--- a/actionpack/test/template/compiled_templates_test.rb
+++ b/actionpack/test/template/compiled_templates_test.rb
@@ -14,9 +14,6 @@ class CompiledTemplatesTest < Test::Unit::TestCase
assert_equal "two", render(:file => "test/render_file_with_locals_and_default.erb", :locals => { :secret => "two" })
end
- # This is broken in 1.8.6 (not supported in Rails 3.0) because the cache uses a Hash
- # key. Since Ruby 1.8.6 implements Hash#hash using the hash's object_id, it will never
- # successfully get a cache hit here.
def test_template_changes_are_not_reflected_with_cached_templates
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
modify_template "test/hello_world.erb", "Goodbye world!" do
@@ -44,7 +41,7 @@ class CompiledTemplatesTest < Test::Unit::TestCase
end
def render_without_cache(*args)
- path = ActionView::FileSystemResolverWithFallback.new(FIXTURE_LOAD_PATH)
+ path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
view_paths = ActionView::Base.process_view_paths(path)
ActionView::Base.new(view_paths, {}).render(*args)
end
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index fb51b67185..da2477b6f8 100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -1229,11 +1229,28 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, date_select("post", "written_on", :order => [ :month, :year ])
end
+ def test_date_select_without_day_and_with_disabled_html_option
+ @post = Post.new
+ @post.written_on = Date.new(2004, 6, 15)
+
+ expected = "<input type=\"hidden\" id=\"post_written_on_3i\" disabled=\"disabled\" name=\"post[written_on(3i)]\" value=\"1\" />\n"
+
+ expected << %{<select id="post_written_on_2i" disabled="disabled" name="post[written_on(2i)]">\n}
+ expected << %{<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n}
+ expected << "</select>\n"
+
+ expected << %{<select id="post_written_on_1i" disabled="disabled" name="post[written_on(1i)]">\n}
+ expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n}
+ expected << "</select>\n"
+
+ assert_dom_equal expected, date_select("post", "written_on", { :order => [ :month, :year ] }, :disabled => true)
+ end
+
def test_date_select_within_fields_for
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
- fields_for :post, @post do |f|
+ output_buffer = fields_for :post, @post do |f|
concat f.date_select(:written_on)
end
@@ -1249,7 +1266,7 @@ class DateHelperTest < ActionView::TestCase
@post.written_on = Date.new(2004, 6, 15)
id = 27
- fields_for :post, @post, :index => id do |f|
+ output_buffer = fields_for :post, @post, :index => id do |f|
concat f.date_select(:written_on)
end
@@ -1265,7 +1282,7 @@ class DateHelperTest < ActionView::TestCase
@post.written_on = Date.new(2004, 6, 15)
id = nil
- fields_for :post, @post, :index => id do |f|
+ output_buffer = fields_for :post, @post, :index => id do |f|
concat f.date_select(:written_on)
end
@@ -1461,7 +1478,7 @@ class DateHelperTest < ActionView::TestCase
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
- fields_for :post, @post do |f|
+ output_buffer = fields_for :post, @post do |f|
concat f.date_select(:written_on, {}, :class => 'selector')
end
@@ -1625,7 +1642,7 @@ class DateHelperTest < ActionView::TestCase
@post = Post.new
@post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
- fields_for :post, @post do |f|
+ output_buffer = fields_for :post, @post do |f|
concat f.time_select(:written_on, {}, :class => 'selector')
end
@@ -1713,6 +1730,25 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, time_select("post", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute'})
end
+ def test_time_select_with_disabled_html_option
+ @post = Post.new
+ @post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
+
+ expected = %{<input type="hidden" id="post_written_on_1i" disabled="disabled" name="post[written_on(1i)]" value="2004" />\n}
+ expected << %{<input type="hidden" id="post_written_on_2i" disabled="disabled" name="post[written_on(2i)]" value="6" />\n}
+ expected << %{<input type="hidden" id="post_written_on_3i" disabled="disabled" name="post[written_on(3i)]" value="15" />\n}
+
+ expected << %(<select id="post_written_on_4i" disabled="disabled" name="post[written_on(4i)]">\n)
+ 0.upto(23) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 15}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+ expected << " : "
+ expected << %(<select id="post_written_on_5i" disabled="disabled" name="post[written_on(5i)]">\n)
+ 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+
+ assert_dom_equal expected, time_select("post", "written_on", {}, :disabled => true)
+ end
+
def test_datetime_select
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
@@ -1780,7 +1816,7 @@ class DateHelperTest < ActionView::TestCase
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
- fields_for :post, @post do |f|
+ output_buffer = fields_for :post, @post do |f|
concat f.datetime_select(:updated_at, {}, :class => 'selector')
end
@@ -2016,7 +2052,7 @@ class DateHelperTest < ActionView::TestCase
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
id = 456
- fields_for :post, @post, :index => id do |f|
+ output_buffer = fields_for :post, @post, :index => id do |f|
concat f.datetime_select(:updated_at)
end
@@ -2173,6 +2209,66 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, datetime_select("post", "updated_at", :discard_year => true, :discard_month => true)
end
+ def test_datetime_select_discard_year_and_month_with_disabled_html_option
+ @post = Post.new
+ @post.updated_at = Time.local(2004, 6, 15, 15, 16, 35)
+
+ expected = %{<input type="hidden" id="post_updated_at_1i" disabled="disabled" name="post[updated_at(1i)]" value="2004" />\n}
+ expected << %{<input type="hidden" id="post_updated_at_2i" disabled="disabled" name="post[updated_at(2i)]" value="6" />\n}
+ expected << %{<input type="hidden" id="post_updated_at_3i" disabled="disabled" name="post[updated_at(3i)]" value="15" />\n}
+
+ expected << %{<select id="post_updated_at_4i" disabled="disabled" name="post[updated_at(4i)]">\n}
+ 0.upto(23) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 15}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+ expected << " : "
+ expected << %{<select id="post_updated_at_5i" disabled="disabled" name="post[updated_at(5i)]">\n}
+ 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+
+ assert_dom_equal expected, datetime_select("post", "updated_at", { :discard_year => true, :discard_month => true }, :disabled => true)
+ end
+
+ def test_datetime_select_discard_hour
+ @post = Post.new
+ @post.updated_at = Time.local(2004, 6, 15, 15, 16, 35)
+
+ expected = %{<select id="post_updated_at_1i" name="post[updated_at(1i)]">\n}
+ 1999.upto(2009) { |i| expected << %(<option value="#{i}"#{' selected="selected"' if i == 2004}>#{i}</option>\n) }
+ expected << "</select>\n"
+ expected << %{<select id="post_updated_at_2i" name="post[updated_at(2i)]">\n}
+ 1.upto(12) { |i| expected << %(<option value="#{i}"#{' selected="selected"' if i == 6}>#{Date::MONTHNAMES[i]}</option>\n) }
+ expected << "</select>\n"
+ expected << %{<select id="post_updated_at_3i" name="post[updated_at(3i)]">\n}
+ 1.upto(31) { |i| expected << %(<option value="#{i}"#{' selected="selected"' if i == 15}>#{i}</option>\n) }
+ expected << "</select>\n"
+
+ assert_dom_equal expected, datetime_select("post", "updated_at", :discard_hour => true)
+ end
+
+ def test_datetime_select_discard_minute
+ @post = Post.new
+ @post.updated_at = Time.local(2004, 6, 15, 15, 16, 35)
+
+ expected = %{<select id="post_updated_at_1i" name="post[updated_at(1i)]">\n}
+ 1999.upto(2009) { |i| expected << %(<option value="#{i}"#{' selected="selected"' if i == 2004}>#{i}</option>\n) }
+ expected << "</select>\n"
+ expected << %{<select id="post_updated_at_2i" name="post[updated_at(2i)]">\n}
+ 1.upto(12) { |i| expected << %(<option value="#{i}"#{' selected="selected"' if i == 6}>#{Date::MONTHNAMES[i]}</option>\n) }
+ expected << "</select>\n"
+ expected << %{<select id="post_updated_at_3i" name="post[updated_at(3i)]">\n}
+ 1.upto(31) { |i| expected << %(<option value="#{i}"#{' selected="selected"' if i == 15}>#{i}</option>\n) }
+ expected << "</select>\n"
+
+ expected << " &mdash; "
+
+ expected << %{<select id="post_updated_at_4i" name="post[updated_at(4i)]">\n}
+ 0.upto(23) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 15}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+ expected << %{<input type="hidden" id="post_updated_at_5i" name="post[updated_at(5i)]" value="16" />\n}
+
+ assert_dom_equal expected, datetime_select("post", "updated_at", :discard_minute => true)
+ end
+
def test_datetime_select_invalid_order
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 15, 16, 35)
diff --git a/actionpack/test/template/erb/tag_helper_test.rb b/actionpack/test/template/erb/tag_helper_test.rb
new file mode 100644
index 0000000000..cc96a43901
--- /dev/null
+++ b/actionpack/test/template/erb/tag_helper_test.rb
@@ -0,0 +1,82 @@
+require "abstract_unit"
+
+module ERBTest
+ class ViewContext
+ mock_controller = Class.new do
+ include SharedTestRoutes.url_helpers
+ end
+
+ include ActionView::Helpers::TagHelper
+ include ActionView::Helpers::JavaScriptHelper
+ include ActionView::Helpers::FormHelper
+
+ attr_accessor :output_buffer
+
+ def protect_against_forgery?() false end
+
+ define_method(:controller) do
+ mock_controller.new
+ end
+ end
+
+ class DeprecatedViewContext < ViewContext
+ include ActionView::Helpers::DeprecatedBlockHelpers
+ end
+
+ module SharedTagHelpers
+ extend ActiveSupport::Testing::Declarative
+
+ def render_content(start, inside)
+ template = block_helper(start, inside)
+ ActionView::Template::Handlers::Erubis.new(template).evaluate(context.new)
+ end
+
+ test "percent equals works for content_tag and does not require parenthesis on method call" do
+ assert_equal "<div>Hello world</div>", render_content("content_tag :div", "Hello world")
+ end
+
+ test "percent equals works for javascript_tag" do
+ expected_output = "<script type=\"text/javascript\">\n//<![CDATA[\nalert('Hello')\n//]]>\n</script>"
+ assert_equal expected_output, render_content("javascript_tag", "alert('Hello')")
+ end
+
+ test "percent equals works for javascript_tag with options" do
+ expected_output = "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('Hello')\n//]]>\n</script>"
+ assert_equal expected_output, render_content("javascript_tag(:id => 'the_js_tag')", "alert('Hello')")
+ end
+
+ test "percent equals works with form tags" do
+ expected_output = "<form action=\"foo\" method=\"post\">hello</form>"
+ assert_equal expected_output, render_content("form_tag('foo')", "<%= 'hello' %>")
+ end
+
+ test "percent equals works with fieldset tags" do
+ expected_output = "<fieldset><legend>foo</legend>hello</fieldset>"
+ assert_equal expected_output, render_content("field_set_tag('foo')", "<%= 'hello' %>")
+ end
+ end
+
+ class TagHelperTest < ActiveSupport::TestCase
+ def context
+ ViewContext
+ end
+
+ def block_helper(str, rest)
+ "<%= #{str} do %>#{rest}<% end %>"
+ end
+
+ include SharedTagHelpers
+ end
+
+ class DeprecatedTagHelperTest < ActiveSupport::TestCase
+ def context
+ DeprecatedViewContext
+ end
+
+ def block_helper(str, rest)
+ "<% __in_erb_template=true %><% #{str} do %>#{rest}<% end %>"
+ end
+
+ include SharedTagHelpers
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 7b909fff82..7c5ccfd6ed 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -4,6 +4,10 @@ require 'controller/fake_models'
class FormHelperTest < ActionView::TestCase
tests ActionView::Helpers::FormHelper
+ def form_for(*)
+ @output_buffer = super
+ end
+
def setup
super
@@ -53,6 +57,7 @@ class FormHelperTest < ActionView::TestCase
def @post.id_before_type_cast; 123; end
def @post.to_param; '123'; end
+ @post.persisted = true
@post.title = "Hello World"
@post.author_name = ""
@post.body = "Back to the hill and over it again!"
@@ -529,7 +534,7 @@ class FormHelperTest < ActionView::TestCase
def test_submit_with_object_as_new_record_and_locale_strings
old_locale, I18n.locale = I18n.locale, :submit
- def @post.new_record?() true; end
+ @post.persisted = false
form_for(:post, @post) do |f|
concat f.submit
end
@@ -589,9 +594,9 @@ class FormHelperTest < ActionView::TestCase
def test_nested_fields_for
form_for(:post, @post) do |f|
- f.fields_for(:comment, @post) do |c|
+ concat f.fields_for(:comment, @post) { |c|
concat c.text_field(:title)
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -604,9 +609,9 @@ class FormHelperTest < ActionView::TestCase
def test_nested_fields_for_with_nested_collections
form_for('post[]', @post) do |f|
concat f.text_field(:title)
- f.fields_for('comment[]', @comment) do |c|
+ concat f.fields_for('comment[]', @comment) { |c|
concat c.text_field(:name)
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -620,9 +625,9 @@ class FormHelperTest < ActionView::TestCase
def test_nested_fields_for_with_index_and_parent_fields
form_for('post', @post, :index => 1) do |c|
concat c.text_field(:title)
- c.fields_for('comment', @comment, :index => 1) do |r|
+ concat c.fields_for('comment', @comment, :index => 1) { |r|
concat r.text_field(:name)
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -634,10 +639,10 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for_with_index_and_nested_fields_for
- form_for(:post, @post, :index => 1) do |f|
- f.fields_for(:comment, @post) do |c|
+ output_buffer = form_for(:post, @post, :index => 1) do |f|
+ concat f.fields_for(:comment, @post) { |c|
concat c.text_field(:title)
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -649,9 +654,9 @@ class FormHelperTest < ActionView::TestCase
def test_nested_fields_for_with_index_on_both
form_for(:post, @post, :index => 1) do |f|
- f.fields_for(:comment, @post, :index => 5) do |c|
+ concat f.fields_for(:comment, @post, :index => 5) { |c|
concat c.text_field(:title)
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -663,9 +668,9 @@ class FormHelperTest < ActionView::TestCase
def test_nested_fields_for_with_auto_index
form_for("post[]", @post) do |f|
- f.fields_for(:comment, @post) do |c|
+ concat f.fields_for(:comment, @post) { |c|
concat c.text_field(:title)
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -677,9 +682,9 @@ class FormHelperTest < ActionView::TestCase
def test_nested_fields_for_with_index_radio_button
form_for(:post, @post) do |f|
- f.fields_for(:comment, @post, :index => 5) do |c|
+ concat f.fields_for(:comment, @post, :index => 5) { |c|
concat c.radio_button(:title, "hello")
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -691,9 +696,9 @@ class FormHelperTest < ActionView::TestCase
def test_nested_fields_for_with_auto_index_on_both
form_for("post[]", @post) do |f|
- f.fields_for("comment[]", @post) do |c|
+ concat f.fields_for("comment[]", @post) { |c|
concat c.text_field(:title)
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -704,16 +709,16 @@ class FormHelperTest < ActionView::TestCase
end
def test_nested_fields_for_with_index_and_auto_index
- form_for("post[]", @post) do |f|
- f.fields_for(:comment, @post, :index => 5) do |c|
+ output_buffer = form_for("post[]", @post) do |f|
+ concat f.fields_for(:comment, @post, :index => 5) { |c|
concat c.text_field(:title)
- end
+ }
end
- form_for(:post, @post, :index => 1) do |f|
- f.fields_for("comment[]", @post) do |c|
+ output_buffer << form_for(:post, @post, :index => 1) do |f|
+ concat f.fields_for("comment[]", @post) { |c|
concat c.text_field(:title)
- end
+ }
end
expected = "<form action='http://www.example.com' method='post'>" +
@@ -731,9 +736,9 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
- f.fields_for(:author) do |af|
+ concat f.fields_for(:author) { |af|
concat af.text_field(:name)
- end
+ }
end
expected = '<form action="http://www.example.com" method="post">' +
@@ -758,9 +763,9 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
- f.fields_for(:author) do |af|
+ concat f.fields_for(:author) { |af|
concat af.text_field(:name)
- end
+ }
end
expected = '<form action="http://www.example.com" method="post">' +
@@ -777,10 +782,10 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
- f.fields_for(:author) do |af|
+ concat f.fields_for(:author) { |af|
concat af.hidden_field(:id)
concat af.text_field(:name)
- end
+ }
end
expected = '<form action="http://www.example.com" method="post">' +
@@ -798,9 +803,9 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
@post.comments.each do |comment|
- f.fields_for(:comments, comment) do |cf|
+ concat f.fields_for(:comments, comment) { |cf|
concat cf.text_field(:name)
- end
+ }
end
end
@@ -821,10 +826,10 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
@post.comments.each do |comment|
- f.fields_for(:comments, comment) do |cf|
+ concat f.fields_for(:comments, comment) { |cf|
concat cf.hidden_field(:id)
concat cf.text_field(:name)
- end
+ }
end
end
@@ -845,9 +850,9 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
@post.comments.each do |comment|
- f.fields_for(:comments, comment) do |cf|
+ concat f.fields_for(:comments, comment) { |cf|
concat cf.text_field(:name)
- end
+ }
end
end
@@ -866,9 +871,9 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
@post.comments.each do |comment|
- f.fields_for(:comments, comment) do |cf|
+ concat f.fields_for(:comments, comment) { |cf|
concat cf.text_field(:name)
- end
+ }
end
end
@@ -902,9 +907,9 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
- f.fields_for(:comments, @post.comments) do |cf|
+ concat f.fields_for(:comments, @post.comments) { |cf|
concat cf.text_field(:name)
- end
+ }
end
expected = '<form action="http://www.example.com" method="post">' +
@@ -924,9 +929,9 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
- f.fields_for(:comments, comments) do |cf|
+ concat f.fields_for(:comments, comments) { |cf|
concat cf.text_field(:name)
- end
+ }
end
expected = '<form action="http://www.example.com" method="post">' +
@@ -946,10 +951,10 @@ class FormHelperTest < ActionView::TestCase
form_for(:post, @post) do |f|
concat f.text_field(:title)
- f.fields_for(:comments) do |cf|
+ concat f.fields_for(:comments) { |cf|
concat cf.text_field(:name)
yielded_comments << cf.object
- end
+ }
end
expected = '<form action="http://www.example.com" method="post">' +
@@ -967,9 +972,9 @@ class FormHelperTest < ActionView::TestCase
@post.comments = []
form_for(:post, @post) do |f|
- f.fields_for(:comments, Comment.new(321), :child_index => 'abc') do |cf|
+ concat f.fields_for(:comments, Comment.new(321), :child_index => 'abc') { |cf|
concat cf.text_field(:name)
- end
+ }
end
expected = '<form action="http://www.example.com" method="post">' +
@@ -987,24 +992,24 @@ class FormHelperTest < ActionView::TestCase
@post.tags[0].relevances = []
@post.tags[1].relevances = []
form_for(:post, @post) do |f|
- f.fields_for(:comments, @post.comments[0]) do |cf|
+ concat f.fields_for(:comments, @post.comments[0]) { |cf|
concat cf.text_field(:name)
- cf.fields_for(:relevances, CommentRelevance.new(314)) do |crf|
+ concat cf.fields_for(:relevances, CommentRelevance.new(314)) { |crf|
concat crf.text_field(:value)
- end
- end
- f.fields_for(:tags, @post.tags[0]) do |tf|
+ }
+ }
+ concat f.fields_for(:tags, @post.tags[0]) { |tf|
concat tf.text_field(:value)
- tf.fields_for(:relevances, TagRelevance.new(3141)) do |trf|
+ concat tf.fields_for(:relevances, TagRelevance.new(3141)) { |trf|
concat trf.text_field(:value)
- end
- end
- f.fields_for('tags', @post.tags[1]) do |tf|
+ }
+ }
+ concat f.fields_for('tags', @post.tags[1]) { |tf|
concat tf.text_field(:value)
- tf.fields_for(:relevances, TagRelevance.new(31415)) do |trf|
+ concat tf.fields_for(:relevances, TagRelevance.new(31415)) { |trf|
concat trf.text_field(:value)
- end
- end
+ }
+ }
end
expected = '<form action="http://www.example.com" method="post">' +
@@ -1026,7 +1031,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for
- fields_for(:post, @post) do |f|
+ output_buffer = fields_for(:post, @post) do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
@@ -1042,7 +1047,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for_with_index
- fields_for("post[]", @post) do |f|
+ output_buffer = fields_for("post[]", @post) do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
@@ -1058,7 +1063,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for_with_nil_index_option_override
- fields_for("post[]", @post, :index => nil) do |f|
+ output_buffer = fields_for("post[]", @post, :index => nil) do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
@@ -1074,7 +1079,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for_with_index_option_override
- fields_for("post[]", @post, :index => "abc") do |f|
+ output_buffer = fields_for("post[]", @post, :index => "abc") do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
@@ -1090,7 +1095,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for_without_object
- fields_for(:post) do |f|
+ output_buffer = fields_for(:post) do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
@@ -1106,7 +1111,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for_with_only_object
- fields_for(@post) do |f|
+ output_buffer = fields_for(@post) do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
@@ -1122,7 +1127,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for_object_with_bracketed_name
- fields_for("author[post]", @post) do |f|
+ output_buffer = fields_for("author[post]", @post) do |f|
concat f.label(:title)
concat f.text_field(:title)
end
@@ -1133,7 +1138,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for_object_with_bracketed_name_and_index
- fields_for("author[post]", @post, :index => 1) do |f|
+ output_buffer = fields_for("author[post]", @post, :index => 1) do |f|
concat f.label(:title)
concat f.text_field(:title)
end
@@ -1152,9 +1157,9 @@ class FormHelperTest < ActionView::TestCase
concat post_form.text_field(:title)
concat post_form.text_area(:body)
- fields_for(:parent_post, @post) do |parent_fields|
+ concat fields_for(:parent_post, @post) { |parent_fields|
concat parent_fields.check_box(:secret)
- end
+ }
end
expected =
@@ -1173,9 +1178,9 @@ class FormHelperTest < ActionView::TestCase
concat post_form.text_field(:title)
concat post_form.text_area(:body)
- post_form.fields_for(@comment) do |comment_fields|
+ concat post_form.fields_for(@comment) { |comment_fields|
concat comment_fields.text_field(:name)
- end
+ }
end
expected =
@@ -1272,7 +1277,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_fields_for_with_labelled_builder
- fields_for(:post, @post, :builder => LabelledFormBuilder) do |f|
+ output_buffer = fields_for(:post, @post, :builder => LabelledFormBuilder) do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
@@ -1363,7 +1368,7 @@ class FormHelperTest < ActionView::TestCase
def test_form_for_with_new_object
post = Post.new
- post.new_record = true
+ post.persisted = false
def post.id() nil end
form_for(post) do |f| end
@@ -1373,9 +1378,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for_with_existing_object_in_list
- @post.new_record = false
@comment.save
-
form_for([@post, @comment]) {}
expected = %(<form action="#{comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0;display:inline"><input name="_method" type="hidden" value="put" /></div></form>)
@@ -1383,8 +1386,6 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for_with_new_object_in_list
- @post.new_record = false
-
form_for([@post, @comment]) {}
expected = %(<form action="#{comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
@@ -1392,9 +1393,7 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for_with_existing_object_and_namespace_in_list
- @post.new_record = false
@comment.save
-
form_for([:admin, @post, @comment]) {}
expected = %(<form action="#{admin_comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0;display:inline"><input name="_method" type="hidden" value="put" /></div></form>)
@@ -1402,8 +1401,6 @@ class FormHelperTest < ActionView::TestCase
end
def test_form_for_with_new_object_and_namespace_in_list
- @post.new_record = false
-
form_for([:admin, @post, @comment]) {}
expected = %(<form action="#{admin_comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index aa40e46aa8..5799e3db53 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -293,7 +293,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@post = Post.new
@post.category = "<mus>"
- fields_for :post, @post do |f|
+ output_buffer = fields_for :post, @post do |f|
concat f.select(:category, %w( abe <mus> hest))
end
@@ -307,7 +307,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@post = Post.new
@post.category = "<mus>"
- fields_for :post, @post, :index => 108 do |f|
+ output_buffer = fields_for :post, @post, :index => 108 do |f|
concat f.select(:category, %w( abe <mus> hest))
end
@@ -322,7 +322,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@post.category = "<mus>"
def @post.to_param; 108; end
- fields_for "post[]", @post do |f|
+ output_buffer = fields_for "post[]", @post do |f|
concat f.select(:category, %w( abe <mus> hest))
end
@@ -336,7 +336,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@post = Post.new
options = "<option value=\"abe\">abe</option><option value=\"mus\">mus</option><option value=\"hest\">hest</option>"
- fields_for :post, @post do |f|
+ output_buffer = fields_for :post, @post do |f|
concat f.select(:category, options, :prompt => 'The prompt')
end
@@ -462,7 +462,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@post = Post.new
@post.author_name = "Babe"
- fields_for :post, @post do |f|
+ output_buffer = fields_for :post, @post do |f|
concat f.collection_select(:author_name, dummy_posts, :author_name, :author_name)
end
@@ -476,7 +476,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@post = Post.new
@post.author_name = "Babe"
- fields_for :post, @post, :index => 815 do |f|
+ output_buffer = fields_for :post, @post, :index => 815 do |f|
concat f.collection_select(:author_name, dummy_posts, :author_name, :author_name)
end
@@ -491,7 +491,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@post.author_name = "Babe"
def @post.to_param; 815; end
- fields_for "post[]", @post do |f|
+ output_buffer = fields_for "post[]", @post do |f|
concat f.collection_select(:author_name, dummy_posts, :author_name, :author_name)
end
@@ -570,7 +570,7 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_select_under_fields_for
@firm = Firm.new("D")
- fields_for :firm, @firm do |f|
+ output_buffer = fields_for :firm, @firm do |f|
concat f.time_zone_select(:time_zone)
end
@@ -589,7 +589,7 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_select_under_fields_for_with_index
@firm = Firm.new("D")
- fields_for :firm, @firm, :index => 305 do |f|
+ output_buffer = fields_for :firm, @firm, :index => 305 do |f|
concat f.time_zone_select(:time_zone)
end
@@ -609,7 +609,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@firm = Firm.new("D")
def @firm.to_param; 305; end
- fields_for "firm[]", @firm do |f|
+ output_buffer = fields_for "firm[]", @firm do |f|
concat f.time_zone_select(:time_zone)
end
@@ -787,7 +787,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@post = Post.new
@post.origin = 'dk'
- fields_for :post, @post do |f|
+ output_buffer = fields_for :post, @post do |f|
concat f.grouped_collection_select("origin", @continents, :countries, :continent_name, :country_id, :country_name)
end
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 6ac5df1ea9..868a35c476 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -3,17 +3,16 @@ require 'abstract_unit'
class FormTagHelperTest < ActionView::TestCase
tests ActionView::Helpers::FormTagHelper
- include ActiveSupport::Configurable
- DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG
+ # include ActiveSupport::Configurable
+ # DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG
def setup
super
- @controller = Class.new do
+ @controller = Class.new(BasicController) do
def url_for(options)
"http://www.example.com"
end
- end
- @controller = @controller.new
+ end.new
end
VALID_HTML_ID = /^[A-Za-z][-_:.A-Za-z0-9]*$/ # see http://www.w3.org/TR/html4/types.html#type-name
@@ -60,16 +59,14 @@ class FormTagHelperTest < ActionView::TestCase
end
def test_form_tag_with_block_in_erb
- __in_erb_template = ''
- form_tag("http://example.com") { concat "Hello world!" }
+ output_buffer = form_tag("http://example.com") { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post">Hello world!</form>)
assert_dom_equal expected, output_buffer
end
def test_form_tag_with_block_and_method_in_erb
- __in_erb_template = ''
- form_tag("http://example.com", :method => :put) { concat "Hello world!" }
+ output_buffer = form_tag("http://example.com", :method => :put) { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post"><div style='margin:0;padding:0;display:inline'><input type="hidden" name="_method" value="put" /></div>Hello world!</form>)
assert_dom_equal expected, output_buffer
@@ -127,19 +124,19 @@ class FormTagHelperTest < ActionView::TestCase
end
def test_select_tag
- actual = select_tag "people", "<option>david</option>"
+ actual = select_tag "people", "<option>david</option>".html_safe
expected = %(<select id="people" name="people"><option>david</option></select>)
assert_dom_equal expected, actual
end
def test_select_tag_with_multiple
- actual = select_tag "colors", "<option>Red</option><option>Blue</option><option>Green</option>", :multiple => :true
+ actual = select_tag "colors", "<option>Red</option><option>Blue</option><option>Green</option>".html_safe, :multiple => :true
expected = %(<select id="colors" multiple="multiple" name="colors"><option>Red</option><option>Blue</option><option>Green</option></select>)
assert_dom_equal expected, actual
end
def test_select_tag_disabled
- actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>", :disabled => :true
+ actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, :disabled => :true
expected = %(<select id="places" disabled="disabled" name="places"><option>Home</option><option>Work</option><option>Pub</option></select>)
assert_dom_equal expected, actual
end
@@ -150,13 +147,13 @@ class FormTagHelperTest < ActionView::TestCase
end
def test_select_tag_with_include_blank
- actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>", :include_blank => true
+ actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, :include_blank => true
expected = %(<select id="places" name="places"><option value=""></option><option>Home</option><option>Work</option><option>Pub</option></select>)
assert_dom_equal expected, actual
end
def test_select_tag_with_include_blank_with_string
- actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>", :include_blank => "string"
+ actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, :include_blank => "string"
expected = %(<select id="places" name="places"><option value="">string</option><option>Home</option><option>Work</option><option>Pub</option></select>)
assert_dom_equal expected, actual
end
@@ -282,9 +279,9 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal %(<input checked="checked" disabled="disabled" id="admin" name="admin" readonly="readonly" type="checkbox" value="1" />), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes")
assert_dom_equal %(<input checked="checked" id="admin" name="admin" type="checkbox" value="1" />), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil)
assert_dom_equal %(<input type="checkbox" />), tag(:input, :type => "checkbox", :checked => false)
- assert_dom_equal %(<select id="people" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people", "<option>david</option>", :multiple => true)
- assert_dom_equal %(<select id="people_" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people[]", "<option>david</option>", :multiple => true)
- assert_dom_equal %(<select id="people" name="people"><option>david</option></select>), select_tag("people", "<option>david</option>", :multiple => nil)
+ assert_dom_equal %(<select id="people" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people", "<option>david</option>".html_safe, :multiple => true)
+ assert_dom_equal %(<select id="people_" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people[]", "<option>david</option>".html_safe, :multiple => true)
+ assert_dom_equal %(<select id="people" name="people"><option>david</option></select>), select_tag("people", "<option>david</option>".html_safe, :multiple => nil)
end
def test_stringify_symbol_keys
@@ -333,26 +330,22 @@ class FormTagHelperTest < ActionView::TestCase
end
def test_field_set_tag_in_erb
- __in_erb_template = ''
- field_set_tag("Your details") { concat "Hello world!" }
+ output_buffer = field_set_tag("Your details") { concat "Hello world!" }
expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>)
assert_dom_equal expected, output_buffer
- self.output_buffer = ''.html_safe
- field_set_tag { concat "Hello world!" }
+ output_buffer = field_set_tag { concat "Hello world!" }
expected = %(<fieldset>Hello world!</fieldset>)
assert_dom_equal expected, output_buffer
- self.output_buffer = ''.html_safe
- field_set_tag('') { concat "Hello world!" }
+ output_buffer = field_set_tag('') { concat "Hello world!" }
expected = %(<fieldset>Hello world!</fieldset>)
assert_dom_equal expected, output_buffer
- self.output_buffer = ''.html_safe
- field_set_tag('', :class => 'format') { concat "Hello world!" }
+ output_buffer = field_set_tag('', :class => 'format') { concat "Hello world!" }
expected = %(<fieldset class="format">Hello world!</fieldset>)
assert_dom_equal expected, output_buffer
diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb
index b3e7abc387..f49b763881 100644
--- a/actionpack/test/template/javascript_helper_test.rb
+++ b/actionpack/test/template/javascript_helper_test.rb
@@ -7,8 +7,9 @@ class JavaScriptHelperTest < ActionView::TestCase
attr_accessor :formats, :output_buffer
- def reset_formats(format)
- @format = format
+ def update_details(details)
+ @details = details
+ yield if block_given?
end
def setup
@@ -73,18 +74,6 @@ class JavaScriptHelperTest < ActionView::TestCase
javascript_tag("alert('hello')", :id => "the_js_tag")
end
- def test_javascript_tag_with_block_in_erb
- __in_erb_template = ''
- javascript_tag { concat "alert('hello')" }
- assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", output_buffer
- end
-
- def test_javascript_tag_with_block_and_options_in_erb
- __in_erb_template = ''
- javascript_tag(:id => "the_js_tag") { concat "alert('hello')" }
- assert_dom_equal "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", output_buffer
- end
-
def test_javascript_cdata_section
assert_dom_equal "\n//<![CDATA[\nalert('hello')\n//]]>\n", javascript_cdata_section("alert('hello')")
end
diff --git a/actionpack/test/template/subscriber_test.rb b/actionpack/test/template/log_subscriber_test.rb
index 8bacab7088..5076dfa70f 100644
--- a/actionpack/test/template/subscriber_test.rb
+++ b/actionpack/test/template/log_subscriber_test.rb
@@ -1,22 +1,22 @@
require "abstract_unit"
-require "rails/subscriber/test_helper"
-require "action_view/railties/subscriber"
+require "rails/log_subscriber/test_helper"
+require "action_view/railties/log_subscriber"
require "controller/fake_models"
-class AVSubscriberTest < ActiveSupport::TestCase
- include Rails::Subscriber::TestHelper
+class AVLogSubscriberTest < ActiveSupport::TestCase
+ include Rails::LogSubscriber::TestHelper
def setup
+ super
@old_logger = ActionController::Base.logger
@view = ActionView::Base.new(ActionController::Base.view_paths, {})
Rails.stubs(:root).returns(File.expand_path(FIXTURE_LOAD_PATH))
- Rails::Subscriber.add(:action_view, ActionView::Railties::Subscriber.new)
- super
+ Rails::LogSubscriber.add(:action_view, ActionView::Railties::LogSubscriber.new)
end
def teardown
super
- Rails::Subscriber.subscribers.clear
+ Rails::LogSubscriber.log_subscribers.clear
ActionController::Base.logger = @old_logger
end
diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb
new file mode 100644
index 0000000000..697ebc694a
--- /dev/null
+++ b/actionpack/test/template/lookup_context_test.rb
@@ -0,0 +1,165 @@
+require "abstract_unit"
+require "abstract_controller/rendering"
+
+ActionView::LookupContext::DetailsKey.class_eval do
+ def self.details_keys
+ @details_keys
+ end
+end
+
+class LookupContextTest < ActiveSupport::TestCase
+ def setup
+ @lookup_context = ActionView::LookupContext.new(FIXTURE_LOAD_PATH, {})
+ end
+
+ def teardown
+ I18n.locale = :en
+ ActionView::LookupContext::DetailsKey.details_keys.clear
+ end
+
+ test "process view paths on initialization" do
+ assert_kind_of ActionView::PathSet, @lookup_context.view_paths
+ end
+
+ test "normalizes details on initialization" do
+ formats = Mime::SET + [nil]
+ locale = [I18n.locale, nil]
+ assert_equal Hash[:formats => formats, :locale => locale], @lookup_context.details
+ end
+
+ test "allows me to set details" do
+ @lookup_context.details = { :formats => [:html], :locale => :pt }
+ assert_equal Hash[:formats => [:html, nil], :locale => [:pt, nil]], @lookup_context.details
+ end
+
+ test "does not allow details to be modified in place" do
+ assert @lookup_context.details.frozen?
+ end
+
+ test "allows me to update an specific detail" do
+ @lookup_context.update_details(:locale => :pt)
+ assert_equal :pt, I18n.locale
+ formats = Mime::SET + [nil]
+ locale = [I18n.locale, nil]
+ assert_equal Hash[:formats => formats, :locale => locale], @lookup_context.details
+ end
+
+ test "allows me to change some details to execute an specific block of code" do
+ formats = Mime::SET + [nil]
+ @lookup_context.update_details(:locale => :pt) do
+ assert_equal Hash[:formats => formats, :locale => [:pt, nil]], @lookup_context.details
+ end
+ assert_equal Hash[:formats => formats, :locale => [:en, nil]], @lookup_context.details
+ end
+
+ test "provides getters and setters for formats" do
+ @lookup_context.formats = :html
+ assert_equal [:html], @lookup_context.formats
+ end
+
+ test "handles */* formats" do
+ @lookup_context.formats = [:"*/*"]
+ assert_equal Mime::SET, @lookup_context.formats
+ end
+
+ test "provides getters and setters for locale" do
+ @lookup_context.locale = :pt
+ assert_equal :pt, @lookup_context.locale
+ end
+
+ test "changing lookup_context locale, changes I18n.locale" do
+ @lookup_context.locale = :pt
+ assert_equal :pt, I18n.locale
+ end
+
+ test "delegates changing the locale to the I18n configuration object if it contains a lookup_context object" do
+ begin
+ I18n.config = AbstractController::I18nProxy.new(I18n.config, @lookup_context)
+ @lookup_context.locale = :pt
+ assert_equal :pt, I18n.locale
+ assert_equal :pt, @lookup_context.locale
+ ensure
+ I18n.config = I18n.config.i18n_config
+ end
+
+ assert_equal :pt, I18n.locale
+ end
+
+ test "find templates using the given view paths and configured details" do
+ template = @lookup_context.find("hello_world", "test")
+ assert_equal "Hello world!", template.source
+
+ @lookup_context.locale = :da
+ template = @lookup_context.find("hello_world", "test")
+ assert_equal "Hey verden", template.source
+ end
+
+ test "adds fallbacks to view paths when required" do
+ assert_equal 1, @lookup_context.view_paths.size
+
+ @lookup_context.with_fallbacks do
+ assert_equal 3, @lookup_context.view_paths.size
+ assert @lookup_context.view_paths.include?(ActionView::FileSystemResolver.new(""))
+ assert @lookup_context.view_paths.include?(ActionView::FileSystemResolver.new("/"))
+ end
+ end
+
+ test "add fallbacks just once in nested fallbacks calls" do
+ @lookup_context.with_fallbacks do
+ @lookup_context.with_fallbacks do
+ assert_equal 3, @lookup_context.view_paths.size
+ end
+ end
+ end
+
+ test "generates a new details key for each details hash" do
+ keys = []
+ keys << @lookup_context.details_key
+ assert_equal 1, keys.uniq.size
+
+ @lookup_context.locale = :da
+ keys << @lookup_context.details_key
+ assert_equal 2, keys.uniq.size
+
+ @lookup_context.locale = :en
+ keys << @lookup_context.details_key
+ assert_equal 2, keys.uniq.size
+
+ @lookup_context.formats = :html
+ keys << @lookup_context.details_key
+ assert_equal 3, keys.uniq.size
+
+ @lookup_context.formats = nil
+ keys << @lookup_context.details_key
+ assert_equal 3, keys.uniq.size
+ end
+
+ test "gives the key forward to the resolver, so it can be used as cache key" do
+ @lookup_context.view_paths = ActionView::FixtureResolver.new("test/_foo.erb" => "Foo")
+ template = @lookup_context.find("foo", "test", true)
+ assert_equal "Foo", template.source
+
+ # Now we are going to change the template, but it won't change the returned template
+ # since we will hit the cache.
+ @lookup_context.view_paths.first.hash["test/_foo.erb"] = "Bar"
+ template = @lookup_context.find("foo", "test", true)
+ assert_equal "Foo", template.source
+
+ # This time we will change the locale. The updated template should be picked since
+ # lookup_context generated a new key after we changed the locale.
+ @lookup_context.locale = :da
+ template = @lookup_context.find("foo", "test", true)
+ assert_equal "Bar", template.source
+
+ # Now we will change back the locale and it will still pick the old template.
+ # This is expected because lookup_context will reuse the previous key for :en locale.
+ @lookup_context.locale = :en
+ template = @lookup_context.find("foo", "test", true)
+ assert_equal "Foo", template.source
+
+ # Finally, we can expire the cache. And the expected template will be used.
+ @lookup_context.view_paths.first.clear_cache
+ template = @lookup_context.find("foo", "test", true)
+ assert_equal "Bar", template.source
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
index d95bdc2b90..619293dc43 100644
--- a/actionpack/test/template/prototype_helper_test.rb
+++ b/actionpack/test/template/prototype_helper_test.rb
@@ -4,6 +4,7 @@ require 'active_model'
class Bunny < Struct.new(:Bunny, :id)
extend ActiveModel::Naming
include ActiveModel::Conversion
+ def to_key() id ? [id] : nil end
end
class Author
@@ -11,6 +12,7 @@ class Author
include ActiveModel::Conversion
attr_reader :id
+ def to_key() id ? [id] : nil end
def save; @id = 1 end
def new_record?; @id.nil? end
def name
@@ -23,6 +25,7 @@ class Article
include ActiveModel::Conversion
attr_reader :id
attr_reader :author_id
+ def to_key() id ? [id] : nil end
def save; @id = 1; @author_id = 1 end
def new_record?; @id.nil? end
def name
@@ -36,8 +39,9 @@ class Author::Nested < Author; end
class PrototypeHelperBaseTest < ActionView::TestCase
attr_accessor :formats, :output_buffer
- def reset_formats(format)
- @format = format
+ def update_details(details)
+ @details = details
+ yield if block_given?
end
def setup
diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb
index 1cd18c0692..74d7bba4fe 100644
--- a/actionpack/test/template/record_tag_helper_test.rb
+++ b/actionpack/test/template/record_tag_helper_test.rb
@@ -18,6 +18,7 @@ class RecordTagHelperTest < ActionView::TestCase
def setup
super
@post = Post.new
+ @post.persisted = true
end
def test_content_tag_for
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index fdf3db1cdb..cea8ab1bce 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -33,17 +33,17 @@ module RenderTestCases
end
def test_render_file_with_localization
- old_locale, I18n.locale = I18n.locale, :da
+ old_locale, @view.locale = @view.locale, :da
assert_equal "Hey verden", @view.render(:file => "test/hello_world")
ensure
- I18n.locale = old_locale
+ @view.locale = old_locale
end
def test_render_file_with_dashed_locale
- old_locale, I18n.locale = I18n.locale, :"pt-BR"
+ old_locale, @view.locale = @view.locale, :"pt-BR"
assert_equal "Ola mundo", @view.render(:file => "test/hello_world")
ensure
- I18n.locale = old_locale
+ @view.locale = old_locale
end
def test_render_file_at_top_level
@@ -108,7 +108,7 @@ module RenderTestCases
@view.render(:partial => "test/raise")
flunk "Render did not raise Template::Error"
rescue ActionView::Template::Error => e
- assert_match "undefined local variable or method `doesnt_exist'", e.message
+ assert_match %r!method.*doesnt_exist!, e.message
assert_equal "", e.sub_template_message
assert_equal "1", e.line_number
assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name
@@ -118,7 +118,7 @@ module RenderTestCases
@view.render(:file => "test/sub_template_raise")
flunk "Render did not raise Template::Error"
rescue ActionView::Template::Error => e
- assert_match "undefined local variable or method `doesnt_exist'", e.message
+ assert_match %r!method.*doesnt_exist!, e.message
assert_equal "Trace of template inclusion: #{File.expand_path("#{FIXTURE_LOAD_PATH}/test/sub_template_raise.html.erb")}", e.sub_template_message
assert_equal "1", e.line_number
assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name
@@ -233,6 +233,11 @@ module RenderTestCases
@view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield")
end
+ def test_render_with_file_in_layout
+ assert_equal %(\n<title>title</title>\n\n),
+ @view.render(:file => "test/layout_render_file.erb")
+ end
+
if '1.9'.respond_to?(:force_encoding)
def test_render_utf8_template_with_magic_comment
with_external_encoding Encoding::ASCII_8BIT do
@@ -265,7 +270,7 @@ class CachedViewRenderTest < ActiveSupport::TestCase
# Ensure view path cache is primed
def setup
view_paths = ActionController::Base.view_paths
- assert_equal ActionView::FileSystemResolverWithFallback, view_paths.first.class
+ assert_equal ActionView::FileSystemResolver, view_paths.first.class
setup_view(view_paths)
end
end
@@ -276,9 +281,9 @@ class LazyViewRenderTest < ActiveSupport::TestCase
# Test the same thing as above, but make sure the view path
# is not eager loaded
def setup
- path = ActionView::FileSystemResolverWithFallback.new(FIXTURE_LOAD_PATH)
+ path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
view_paths = ActionView::Base.process_view_paths(path)
- assert_equal ActionView::FileSystemResolverWithFallback, view_paths.first.class
+ assert_equal ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH), view_paths.first
setup_view(view_paths)
end
end
diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb
index 433f6514cf..256d9bdcde 100644
--- a/actionpack/test/template/tag_helper_test.rb
+++ b/actionpack/test/template/tag_helper_test.rb
@@ -37,18 +37,18 @@ class TagHelperTest < ActionView::TestCase
assert content_tag("a", "Create", "href" => "create").html_safe?
assert_equal content_tag("a", "Create", "href" => "create"),
content_tag("a", "Create", :href => "create")
+ assert_equal "<p>&lt;script&gt;evil_js&lt;/script&gt;</p>",
+ content_tag(:p, '<script>evil_js</script>')
end
def test_content_tag_with_block_in_erb
- __in_erb_template = ''
- content_tag(:div) { concat "Hello world!" }
- assert_dom_equal "<div>Hello world!</div>", output_buffer
+ buffer = content_tag(:div) { concat "Hello world!" }
+ assert_dom_equal "<div>Hello world!</div>", buffer
end
def test_content_tag_with_block_and_options_in_erb
- __in_erb_template = ''
- content_tag(:div, :class => "green") { concat "Hello world!" }
- assert_dom_equal %(<div class="green">Hello world!</div>), output_buffer
+ buffer = content_tag(:div, :class => "green") { concat "Hello world!" }
+ assert_dom_equal %(<div class="green">Hello world!</div>), buffer
end
def test_content_tag_with_block_and_options_out_of_erb
@@ -66,10 +66,10 @@ class TagHelperTest < ActionView::TestCase
output_buffer
end
+ # TAG TODO: Move this into a real template
def test_content_tag_nested_in_content_tag_in_erb
- __in_erb_template = true
- content_tag("p") { concat content_tag("b", "Hello") }
- assert_equal '<p><b>Hello</b></p>', output_buffer
+ buffer = content_tag("p") { concat content_tag("b", "Hello") }
+ assert_equal '<p><b>Hello</b></p>', buffer
end
def test_content_tag_with_escaped_array_class
diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb
index be2c6b3108..195a6ea3ae 100644
--- a/actionpack/test/template/test_case_test.rb
+++ b/actionpack/test/template/test_case_test.rb
@@ -89,16 +89,23 @@ module ActionView
end
test "helper class that is being tested is always included in view instance" do
- self.class.helper_class.module_eval do
- def render_from_helper
- render :partial => 'customer', :collection => @customers
+ # This ensure is a hidious hack to deal with these tests bleeding
+ # methods between eachother
+ begin
+ self.class.helper_class.module_eval do
+ def render_from_helper
+ render :partial => 'customer', :collection => @customers
+ end
end
- end
- TestController.stubs(:controller_path).returns('test')
+ TestController.stubs(:controller_path).returns('test')
- @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')]
- assert_match /Hello: EloyHello: Manfred/, render(:partial => 'test/from_helper')
+ @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')]
+ assert_match /Hello: EloyHello: Manfred/, render(:partial => 'test/from_helper')
+
+ ensure
+ self.class.helper_class.send(:remove_method, :render_from_helper)
+ end
end
test "no additional helpers should shared across test cases" do
@@ -107,7 +114,7 @@ module ActionView
end
test "is able to use routes" do
- controller.request.assign_parameters('foo', 'index')
+ controller.request.assign_parameters(@router, 'foo', 'index')
assert_equal '/foo', url_for
assert_equal '/bar', url_for(:controller => 'bar')
end
@@ -147,10 +154,16 @@ module ActionView
end
test "is able to make methods available to the view" do
- _helpers.module_eval do
- def render_from_helper; from_test_case end
+ # This ensure is a hidious hack to deal with these tests bleeding
+ # methods between eachother
+ begin
+ _helpers.module_eval do
+ def render_from_helper; from_test_case end
+ end
+ assert_equal 'Word!', render(:partial => 'test/from_helper')
+ ensure
+ _helpers.send(:remove_method, :render_from_helper)
end
- assert_equal 'Word!', render(:partial => 'test/from_helper')
end
def from_test_case; 'Word!'; end
diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb
index 4b73c44f7e..699fb2f5bc 100644
--- a/actionpack/test/template/translation_helper_test.rb
+++ b/actionpack/test/template/translation_helper_test.rb
@@ -18,6 +18,11 @@ class TranslationHelperTest < ActiveSupport::TestCase
assert_equal expected, translate(:foo)
end
+ def test_translation_of_an_array
+ I18n.expects(:translate).with(["foo", "bar"], :raise => true).returns(["foo", "bar"])
+ assert_equal ["foo", "bar"], translate(["foo", "bar"])
+ end
+
def test_delegates_localize_to_i18n
@time = Time.utc(2008, 7, 8, 12, 18, 38)
I18n.expects(:localize).with(@time)
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index e904e88f49..165cb655da 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -1,22 +1,21 @@
# encoding: utf-8
require 'abstract_unit'
+require 'active_support/ordered_options'
require 'controller/fake_controllers'
-RequestMock = Struct.new("Request", :request_uri, :protocol, :host_with_port, :env)
-
class UrlHelperTest < ActionView::TestCase
- include ActiveSupport::Configurable
- DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG
def setup
super
- @controller = Class.new do
- attr_accessor :url, :request
+ @controller = Class.new(BasicController) do
+ attr_accessor :url
def url_for(options)
url
end
end
+
@controller = @controller.new
+ @request = @controller.request = ActionDispatch::TestRequest.new
@controller.url = "http://www.example.com"
end
@@ -38,12 +37,13 @@ class UrlHelperTest < ActionView::TestCase
end
def test_url_for_with_back
- @controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {'HTTP_REFERER' => 'http://www.example.com/referer'})
+ @request.env['HTTP_REFERER'] = 'http://www.example.com/referer'
assert_equal 'http://www.example.com/referer', url_for(:back)
end
def test_url_for_with_back_and_no_referer
- @controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {})
+ @request.env['HOST_NAME'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
assert_equal 'javascript:history.back()', url_for(:back)
end
@@ -122,7 +122,6 @@ class UrlHelperTest < ActionView::TestCase
url = {:controller => 'weblog', :action => 'show'}
@controller = ActionController::Base.new
@controller.request = ActionController::TestRequest.new
- @controller.url = ActionController::UrlRewriter.new(@controller.request, url)
assert_dom_equal(%q{<a href="/weblog/show">Test Link</a>}, link_to('Test Link', url))
end
@@ -131,7 +130,6 @@ class UrlHelperTest < ActionView::TestCase
url = {:controller => 'weblog', :action => 'show', :host => 'www.example.com'}
@controller = ActionController::Base.new
@controller.request = ActionController::TestRequest.new
- @controller.url = ActionController::UrlRewriter.new(@controller.request, url)
assert_dom_equal(%q{<a href="http://www.example.com/weblog/show">Test Link</a>}, link_to('Test Link', url))
end
@@ -144,22 +142,28 @@ class UrlHelperTest < ActionView::TestCase
end
def test_link_tag_with_back
- @controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {'HTTP_REFERER' => 'http://www.example.com/referer'})
+ @request.env['HOST_NAME'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
+ @request.env['HTTP_REFERER'] = 'http://www.example.com/referer'
assert_dom_equal "<a href=\"http://www.example.com/referer\">go back</a>", link_to('go back', :back)
end
def test_link_tag_with_back_and_no_referer
- @controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {})
+ @request.env['HOST_NAME'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
assert_dom_equal "<a href=\"javascript:history.back()\">go back</a>", link_to('go back', :back)
end
def test_link_tag_with_back
- @controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {'HTTP_REFERER' => 'http://www.example.com/referer'})
+ @request.env['HOST_NAME'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
+ @request.env['HTTP_REFERER'] = 'http://www.example.com/referer'
assert_dom_equal "<a href=\"http://www.example.com/referer\">go back</a>", link_to('go back', :back)
end
def test_link_tag_with_back_and_no_referer
- @controller.request = RequestMock.new("http://www.example.com/weblog/show", nil, nil, {})
+ @request.env['HOST_NAME'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
assert_dom_equal "<a href=\"javascript:history.back()\">go back</a>", link_to('go back', :back)
end
@@ -263,55 +267,60 @@ class UrlHelperTest < ActionView::TestCase
end
def test_current_page_with_simple_url
- @controller.request = RequestMock.new("http://www.example.com/weblog/show")
+ @request.env['HTTP_HOST'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
@controller.url = "http://www.example.com/weblog/show"
assert current_page?({ :action => "show", :controller => "weblog" })
assert current_page?("http://www.example.com/weblog/show")
end
def test_current_page_ignoring_params
- @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1")
+ @request.env['HTTP_HOST'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
+ @request.env['QUERY_STRING'] = 'order=desc&page=1'
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
assert current_page?({ :action => "show", :controller => "weblog" })
assert current_page?("http://www.example.com/weblog/show")
end
def test_current_page_with_params_that_match
- @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1")
+ @request.env['HTTP_HOST'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
+ @request.env['QUERY_STRING'] = 'order=desc&page=1'
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
assert current_page?({ :action => "show", :controller => "weblog", :order => "desc", :page => "1" })
assert current_page?("http://www.example.com/weblog/show?order=desc&amp;page=1")
end
def test_link_unless_current
- @controller.request = RequestMock.new("http://www.example.com/weblog/show")
+ @request.env['HTTP_HOST'] = 'www.example.com'
+ @request.env['PATH_INFO'] = '/weblog/show'
@controller.url = "http://www.example.com/weblog/show"
assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show")
- @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc")
+ @request.env['QUERY_STRING'] = 'order=desc'
@controller.url = "http://www.example.com/weblog/show"
assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show")
- @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1")
+ @request.env['QUERY_STRING'] = 'order=desc&page=1'
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog", :order=>'desc', :page=>'1' })
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1")
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1")
- @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc")
+ @request.env['QUERY_STRING'] = 'order=desc'
@controller.url = "http://www.example.com/weblog/show?order=asc"
assert_equal "<a href=\"http://www.example.com/weblog/show?order=asc\">Showing</a>", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
assert_equal "<a href=\"http://www.example.com/weblog/show?order=asc\">Showing</a>", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=asc")
- @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1")
+ @request.env['QUERY_STRING'] = 'order=desc&page=1'
@controller.url = "http://www.example.com/weblog/show?order=desc&page=2"
assert_equal "<a href=\"http://www.example.com/weblog/show?order=desc&page=2\">Showing</a>", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
assert_equal "<a href=\"http://www.example.com/weblog/show?order=desc&amp;page=2\">Showing</a>", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=2")
-
- @controller.request = RequestMock.new("http://www.example.com/weblog/show")
+ @request.env['QUERY_STRING'] = ''
@controller.url = "http://www.example.com/weblog/list"
assert_equal "<a href=\"http://www.example.com/weblog/list\">Listing</a>",
link_to_unless_current("Listing", :action => "list", :controller => "weblog")
@@ -346,7 +355,7 @@ class UrlHelperTest < ActionView::TestCase
end
def test_mail_to_with_img
- assert_dom_equal %(<a href="mailto:feedback@example.com"><img src="/feedback.png" /></a>), mail_to('feedback@example.com', '<img src="/feedback.png" />')
+ assert_dom_equal %(<a href="mailto:feedback@example.com"><img src="/feedback.png" /></a>), mail_to('feedback@example.com', '<img src="/feedback.png" />'.html_safe)
end
def test_mail_to_with_hex
@@ -464,8 +473,6 @@ end
class LinkToUnlessCurrentWithControllerTest < ActionController::TestCase
def setup
super
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
@controller = TasksController.new
end
@@ -499,14 +506,14 @@ end
class Workshop
extend ActiveModel::Naming
include ActiveModel::Conversion
- attr_accessor :id, :new_record
+ attr_accessor :id
- def initialize(id, new_record)
- @id, @new_record = id, new_record
+ def initialize(id)
+ @id = id
end
- def new_record?
- @new_record
+ def persisted?
+ id.present?
end
def to_s
@@ -517,14 +524,14 @@ end
class Session
extend ActiveModel::Naming
include ActiveModel::Conversion
- attr_accessor :id, :workshop_id, :new_record
+ attr_accessor :id, :workshop_id
- def initialize(id, new_record)
- @id, @new_record = id, new_record
+ def initialize(id)
+ @id = id
end
- def new_record?
- @new_record
+ def persisted?
+ id.present?
end
def to_s
@@ -534,12 +541,12 @@ end
class WorkshopsController < ActionController::Base
def index
- @workshop = Workshop.new(1, true)
+ @workshop = Workshop.new(nil)
render :inline => "<%= url_for(@workshop) %>\n<%= link_to('Workshop', @workshop) %>"
end
def show
- @workshop = Workshop.new(params[:id], false)
+ @workshop = Workshop.new(params[:id])
render :inline => "<%= url_for(@workshop) %>\n<%= link_to('Workshop', @workshop) %>"
end
@@ -548,14 +555,14 @@ end
class SessionsController < ActionController::Base
def index
- @workshop = Workshop.new(params[:workshop_id], false)
- @session = Session.new(1, true)
+ @workshop = Workshop.new(params[:workshop_id])
+ @session = Session.new(nil)
render :inline => "<%= url_for([@workshop, @session]) %>\n<%= link_to('Session', [@workshop, @session]) %>"
end
def show
- @workshop = Workshop.new(params[:workshop_id], false)
- @session = Session.new(params[:id], false)
+ @workshop = Workshop.new(params[:workshop_id])
+ @session = Session.new(params[:id])
render :inline => "<%= url_for([@workshop, @session]) %>\n<%= link_to('Session', [@workshop, @session]) %>"
end
@@ -565,8 +572,7 @@ end
class PolymorphicControllerTest < ActionController::TestCase
def setup
super
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
+ @response = ActionController::TestResponse.new
end
def test_new_resource