aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG8
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb56
-rw-r--r--actionpack/lib/action_controller/metal.rb2
-rw-r--r--actionpack/lib/action_controller/metal/responder.rb18
-rw-r--r--actionpack/lib/action_controller/railtie.rb3
-rw-r--r--actionpack/lib/action_controller/railties/log_subscriber.rb56
-rw-r--r--actionpack/lib/action_controller/test_case.rb18
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb5
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb11
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb149
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb43
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb9
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb83
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb31
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb42
-rw-r--r--actionpack/lib/action_view/base.rb7
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb18
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb47
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb29
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb14
-rw-r--r--actionpack/lib/action_view/helpers/scriptaculous_helper.rb6
-rw-r--r--actionpack/lib/action_view/log_subscriber.rb27
-rw-r--r--actionpack/lib/action_view/railtie.rb17
-rw-r--r--actionpack/lib/action_view/railties/log_subscriber.rb27
-rw-r--r--actionpack/lib/action_view/template/resolver.rb2
-rw-r--r--actionpack/lib/action_view/test_case.rb46
-rw-r--r--actionpack/test/abstract/callbacks_test.rb14
-rw-r--r--actionpack/test/abstract_unit.rb15
-rw-r--r--actionpack/test/activerecord/active_record_store_test.rb47
-rw-r--r--actionpack/test/activerecord/controller_runtime_test.rb10
-rw-r--r--actionpack/test/controller/flash_test.rb20
-rw-r--r--actionpack/test/controller/log_subscriber_test.rb10
-rw-r--r--actionpack/test/controller/new_base/base_test.rb38
-rw-r--r--actionpack/test/controller/url_for_test.rb12
-rw-r--r--actionpack/test/dispatch/routing_test.rb189
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb43
-rw-r--r--actionpack/test/dispatch/session/mem_cache_store_test.rb67
-rw-r--r--actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb10
-rw-r--r--actionpack/test/template/active_model_helper_test.rb7
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb22
-rw-r--r--actionpack/test/template/form_helper_test.rb15
-rw-r--r--actionpack/test/template/log_subscriber_test.rb10
-rw-r--r--actionpack/test/template/test_case_test.rb45
-rw-r--r--actionpack/test/template/url_helper_test.rb22
48 files changed, 1024 insertions, 355 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index a00f63dcd4..b17a48003c 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,13 @@
*Rails 3.0.0 [Release Candidate] (unreleased)*
+* Allow :path to be given to match/get/post/put/delete instead of :path_names in the new router [Carlos Antônio da Silva]
+
+* Added resources_path_names to the new router DSL [José Valim]
+
+* Allow options to be given to the namespace method in the new router [Carlos Antônio da Silva]
+
+* Deprecate :name_prefix in the new router DSL [José Valim]
+
* Add shallow routes back to the new router [Diego Carrion, Andrew White]
resources :posts do
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 8e95315252..1dede257f9 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
s.add_dependency('i18n', '~> 0.4.1')
s.add_dependency('rack', '~> 1.1.0')
s.add_dependency('rack-test', '~> 0.5.4')
- s.add_dependency('rack-mount', '~> 0.6.4')
+ s.add_dependency('rack-mount', '~> 0.6.5')
s.add_dependency('tzinfo', '~> 0.3.16')
s.add_dependency('erubis', '~> 2.6.5')
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 8611d0d3c3..a70ba0d2e3 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -1,3 +1,5 @@
+require "action_controller/log_subscriber"
+
module ActionController
class Base < Metal
abstract!
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
new file mode 100644
index 0000000000..ece270b3ce
--- /dev/null
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -0,0 +1,56 @@
+require 'active_support/core_ext/object/blank'
+
+module ActionController
+ class LogSubscriber < ActiveSupport::LogSubscriber
+ INTERNAL_PARAMS = %w(controller action format _method only_path)
+
+ def start_processing(event)
+ payload = event.payload
+ params = payload[:params].except(*INTERNAL_PARAMS)
+
+ info " Processing by #{payload[:controller]}##{payload[:action]} as #{payload[:formats].first.to_s.upcase}"
+ info " Parameters: #{params.inspect}" unless params.empty?
+ end
+
+ def process_action(event)
+ payload = event.payload
+ additions = ActionController::Base.log_process_action(payload)
+
+ message = "Completed #{payload[:status]} #{Rack::Utils::HTTP_STATUS_CODES[payload[:status]]} in %.0fms" % event.duration
+ message << " (#{additions.join(" | ")})" unless additions.blank?
+
+ info(message)
+ end
+
+ def send_file(event)
+ message = "Sent file %s"
+ message << " (%.1fms)"
+ info(message % [event.payload[:path], event.duration])
+ end
+
+ def redirect_to(event)
+ info "Redirected to #{event.payload[:location]}"
+ end
+
+ def send_data(event)
+ info("Sent data %s (%.1fms)" % [event.payload[:filename], event.duration])
+ end
+
+ %w(write_fragment read_fragment exist_fragment?
+ expire_fragment expire_page write_page).each do |method|
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
+ def #{method}(event)
+ key_or_path = event.payload[:key] || event.payload[:path]
+ human_name = #{method.to_s.humanize.inspect}
+ info("\#{human_name} \#{key_or_path} (%.1fms)" % event.duration)
+ end
+ METHOD
+ end
+
+ def logger
+ ActionController::Base.logger
+ end
+ end
+end
+
+ActionController::LogSubscriber.attach_to :action_controller \ No newline at end of file
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 159d1f0748..2281c500c5 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -61,7 +61,7 @@ module ActionController
# ==== Returns
# String
def self.controller_name
- @controller_name ||= controller_path.split("/").last
+ @controller_name ||= self.name.demodulize.sub(/Controller$/, '').underscore
end
# Delegates to the class' #controller_name
diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb
index 22bdcd0f3c..cb644dfd16 100644
--- a/actionpack/lib/action_controller/metal/responder.rb
+++ b/actionpack/lib/action_controller/metal/responder.rb
@@ -89,9 +89,7 @@ module ActionController #:nodoc:
def initialize(controller, resources, options={})
@controller = controller
- @request = controller.request
- @format = controller.formats.first
- @resource = resources.is_a?(Array) ? resources.last : resources
+ @resource = resources.last
@resources = resources
@options = options
@action = options.delete(:action)
@@ -101,6 +99,14 @@ module ActionController #:nodoc:
delegate :head, :render, :redirect_to, :to => :controller
delegate :get?, :post?, :put?, :delete?, :to => :request
+ def request
+ @request ||= @controller.request
+ end
+
+ def format
+ @format ||= @controller.formats.first
+ end
+
# Undefine :to_json and :to_yaml since it's defined on Object
undef_method(:to_json) if method_defined?(:to_json)
undef_method(:to_yaml) if method_defined?(:to_yaml)
@@ -147,7 +153,7 @@ module ActionController #:nodoc:
elsif has_errors? && default_action
render :action => default_action
else
- redirect_to resource_location
+ redirect_to navigation_location
end
end
@@ -160,7 +166,7 @@ module ActionController #:nodoc:
elsif has_errors?
display resource.errors, :status => :unprocessable_entity
elsif post?
- display resource, :status => :created, :location => resource_location
+ display resource, :status => :created, :location => api_location
else
head :ok
end
@@ -178,6 +184,8 @@ module ActionController #:nodoc:
def resource_location
options[:location] || resources
end
+ alias :navigation_location :resource_location
+ alias :api_location :resource_location
# If a given response block was given, use it, otherwise call render on
# controller.
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index 0e3cdffadc..86395c4d93 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -6,7 +6,6 @@ require "active_support/core_ext/class/subclasses"
require "active_support/deprecation/proxy_wrappers"
require "active_support/deprecation"
-require "action_controller/railties/log_subscriber"
require "action_controller/railties/url_helpers"
module ActionController
@@ -35,8 +34,6 @@ module ActionController
end
end
- log_subscriber :action_controller, ActionController::Railties::LogSubscriber.new
-
initializer "action_controller.set_configs" do |app|
paths = app.config.paths
ac = app.config.action_controller
diff --git a/actionpack/lib/action_controller/railties/log_subscriber.rb b/actionpack/lib/action_controller/railties/log_subscriber.rb
deleted file mode 100644
index 00ac3bdf67..0000000000
--- a/actionpack/lib/action_controller/railties/log_subscriber.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require 'active_support/core_ext/object/blank'
-
-module ActionController
- module Railties
- class LogSubscriber < Rails::LogSubscriber
- INTERNAL_PARAMS = %w(controller action format _method only_path)
-
- def start_processing(event)
- payload = event.payload
- params = payload[:params].except(*INTERNAL_PARAMS)
-
- info " Processing by #{payload[:controller]}##{payload[:action]} as #{payload[:formats].first.to_s.upcase}"
- info " Parameters: #{params.inspect}" unless params.empty?
- end
-
- def process_action(event)
- payload = event.payload
- additions = ActionController::Base.log_process_action(payload)
-
- message = "Completed #{payload[:status]} #{Rack::Utils::HTTP_STATUS_CODES[payload[:status]]} in %.0fms" % event.duration
- message << " (#{additions.join(" | ")})" unless additions.blank?
-
- info(message)
- end
-
- def send_file(event)
- message = "Sent file %s"
- message << " (%.1fms)"
- info(message % [event.payload[:path], event.duration])
- end
-
- def redirect_to(event)
- info "Redirected to #{event.payload[:location]}"
- end
-
- def send_data(event)
- info("Sent data %s (%.1fms)" % [event.payload[:filename], event.duration])
- end
-
- %w(write_fragment read_fragment exist_fragment?
- expire_fragment expire_page write_page).each do |method|
- class_eval <<-METHOD, __FILE__, __LINE__ + 1
- def #{method}(event)
- key_or_path = event.payload[:key] || event.payload[:path]
- human_name = #{method.to_s.humanize.inspect}
- info("\#{human_name} \#{key_or_path} (%.1fms)" % event.duration)
- end
- METHOD
- end
-
- def logger
- ActionController::Base.logger
- end
- end
- end
-end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 7f9eb2cfd1..650eb16ac0 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -40,7 +40,7 @@ module ActionController
ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
end
- # Asserts that the request was rendered with the appropriate template file or partials
+ # Asserts that the request was rendered with the appropriate template file or partials.
#
# ==== Examples
#
@@ -53,6 +53,12 @@ module ActionController
# # assert that no partials were rendered
# assert_template :partial => false
#
+ # In a view test case, you can also assert that specific locals are passed
+ # to partials:
+ #
+ # # assert that the "_customer" partial was rendered with a specific object
+ # assert_template :partial => '_customer', :locals => { :customer => @customer }
+ #
def assert_template(options = {}, message = nil)
validate_request!
@@ -72,9 +78,13 @@ module ActionController
end
when Hash
if expected_partial = options[:partial]
- if expected_count = options[:count]
+ if expected_locals = options[:locals]
+ actual_locals = @locals[expected_partial.to_s.sub(/^_/,'')]
+ expected_locals.each_pair do |k,v|
+ assert_equal(v, actual_locals[k])
+ end
+ elsif expected_count = options[:count]
actual_count = @partials[expected_partial]
- # actual_count = found.nil? ? 0 : found[1]
msg = build_message(message,
"expecting ? to be rendered ? time(s) but rendered ? time(s)",
expected_partial, expected_count, actual_count)
@@ -183,6 +193,8 @@ module ActionController
replace(session.stringify_keys)
@loaded = true
end
+
+ def exists?; true; end
end
# Superclass for ActionController functional tests. Functional tests allow you to
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 98f4f5ae18..fd23b1df79 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -194,9 +194,12 @@ module ActionDispatch
@env['rack.input']
end
+ # TODO This should be broken apart into AD::Request::Session and probably
+ # be included by the session middleware.
def reset_session
- self.session_options.delete(:id)
+ session.destroy if session
self.session = {}
+ @env['action_dispatch.request.flash_hash'] = nil
end
def session=(session) #:nodoc:
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index 18771fe782..bfa30cf5af 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -4,7 +4,7 @@ module ActionDispatch
# read a notice you put there or <tt>flash["notice"] = "hello"</tt>
# to put a new one.
def flash
- session['flash'] ||= Flash::FlashHash.new
+ @env['action_dispatch.request.flash_hash'] ||= (session["flash"] || Flash::FlashHash.new)
end
end
@@ -176,7 +176,14 @@ module ActionDispatch
@app.call(env)
ensure
- if (session = env['rack.session']) && session.key?('flash') && session['flash'].empty?
+ session = env['rack.session'] || {}
+ flash_hash = env['action_dispatch.request.flash_hash']
+
+ if flash_hash && (!flash_hash.empty? || session.key?('flash'))
+ session["flash"] = flash_hash
+ end
+
+ if session.key?('flash') && session['flash'].empty?
session.delete('flash')
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 3e8d64b0c6..08bc80dbc2 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -12,6 +12,35 @@ module ActionDispatch
ENV_SESSION_KEY = 'rack.session'.freeze
ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
+ # thin wrapper around Hash that allows us to lazily
+ # load session id into session_options
+ class OptionsHash < Hash
+ def initialize(by, env, default_options)
+ @by = by
+ @env = env
+ @session_id_loaded = false
+ merge!(default_options)
+ end
+
+ def [](key)
+ if key == :id
+ load_session_id! unless super(:id) || has_session_id?
+ end
+ super(key)
+ end
+
+ private
+
+ def has_session_id?
+ @session_id_loaded
+ end
+
+ def load_session_id!
+ self[:id] = @by.send(:extract_session_id, @env)
+ @session_id_loaded = true
+ end
+ end
+
class SessionHash < Hash
def initialize(by, env)
super()
@@ -21,66 +50,75 @@ module ActionDispatch
end
def [](key)
- load! unless @loaded
+ load_for_read!
+ super(key.to_s)
+ end
+
+ def has_key?(key)
+ load_for_read!
super(key.to_s)
end
def []=(key, value)
- load! unless @loaded
+ load_for_write!
super(key.to_s, value)
end
def to_hash
+ load_for_read!
h = {}.replace(self)
h.delete_if { |k,v| v.nil? }
h
end
def update(hash)
- load! unless @loaded
+ load_for_write!
super(hash.stringify_keys)
end
def delete(key)
- load! unless @loaded
+ load_for_write!
super(key.to_s)
end
def inspect
- load! unless @loaded
+ load_for_read!
super
end
+ def exists?
+ return @exists if instance_variable_defined?(:@exists)
+ @exists = @by.send(:exists?, @env)
+ end
+
def loaded?
@loaded
end
+ def destroy
+ clear
+ @by.send(:destroy, @env) if @by
+ @env[ENV_SESSION_OPTIONS_KEY][:id] = nil if @env && @env[ENV_SESSION_OPTIONS_KEY]
+ @loaded = false
+ end
+
private
- def load!
- stale_session_check! do
- id, session = @by.send(:load_session, @env)
- (@env[ENV_SESSION_OPTIONS_KEY] ||= {})[:id] = id
- replace(session.stringify_keys)
- @loaded = true
- end
+
+ def load_for_read!
+ load! if !loaded? && exists?
end
- def stale_session_check!
- yield
- rescue ArgumentError => argument_error
- if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
- begin
- # Note that the regexp does not allow $1 to end with a ':'
- $1.constantize
- rescue LoadError, NameError => const_error
- raise ActionDispatch::Session::SessionRestoreError, "Session contains objects whose class definition isn't available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n"
- end
-
- retry
- else
- raise
- end
+ def load_for_write!
+ load! unless loaded?
+ end
+
+ def load!
+ id, session = @by.send(:load_session, @env)
+ @env[ENV_SESSION_OPTIONS_KEY][:id] = id
+ replace(session.stringify_keys)
+ @loaded = true
end
+
end
DEFAULT_OPTIONS = {
@@ -108,8 +146,8 @@ module ActionDispatch
session_data = env[ENV_SESSION_KEY]
options = env[ENV_SESSION_OPTIONS_KEY]
- if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
- session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
+ if !session_data.is_a?(AbstractStore::SessionHash) || session_data.loaded? || options[:expire_after]
+ session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
sid = options[:id] || generate_sid
session_data = session_data.to_hash
@@ -133,7 +171,7 @@ module ActionDispatch
def prepare!(env)
env[ENV_SESSION_KEY] = SessionHash.new(self, env)
- env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
+ env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
end
def generate_sid
@@ -141,15 +179,30 @@ module ActionDispatch
end
def set_cookie(request, options)
- request.cookie_jar[@key] = options
+ if request.cookie_jar[@key] != options[:value] || !options[:expires].nil?
+ request.cookie_jar[@key] = options
+ end
end
def load_session(env)
- request = Rack::Request.new(env)
- sid = request.cookies[@key]
- sid ||= request.params[@key] unless @cookie_only
- sid, session = get_session(env, sid)
- [sid, session]
+ stale_session_check! do
+ sid = current_session_id(env)
+ sid, session = get_session(env, sid)
+ [sid, session]
+ end
+ end
+
+ def extract_session_id(env)
+ stale_session_check! do
+ request = ActionDispatch::Request.new(env)
+ sid = request.cookies[@key]
+ sid ||= request.params[@key] unless @cookie_only
+ sid
+ end
+ end
+
+ def current_session_id(env)
+ env[ENV_SESSION_OPTIONS_KEY][:id]
end
def ensure_session_key!
@@ -161,6 +214,26 @@ module ActionDispatch
end
end
+ def stale_session_check!
+ yield
+ rescue ArgumentError => argument_error
+ if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
+ begin
+ # Note that the regexp does not allow $1 to end with a ':'
+ $1.constantize
+ rescue LoadError, NameError => const_error
+ raise ActionDispatch::Session::SessionRestoreError, "Session contains objects whose class definition isn't available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n"
+ end
+ retry
+ else
+ raise
+ end
+ end
+
+ def exists?(env)
+ current_session_id(env).present?
+ end
+
def get_session(env, sid)
raise '#get_session needs to be implemented.'
end
@@ -169,6 +242,10 @@ module ActionDispatch
raise '#set_session needs to be implemented and should return ' <<
'the value to be stored in the cookie (usually the sid)'
end
+
+ def destroy(env)
+ raise '#destroy needs to be implemented.'
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index 92a86ee229..dce47c63bc 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -39,16 +39,6 @@ module ActionDispatch
#
# Note that changing digest or secret invalidates all existing sessions!
class CookieStore < AbstractStore
- class OptionsHash < Hash
- def initialize(by, env, default_options)
- @session_data = env[AbstractStore::ENV_SESSION_KEY]
- merge!(default_options)
- end
-
- def [](key)
- key == :id ? @session_data[:session_id] : super(key)
- end
- end
def initialize(app, options = {})
super(app, options.merge!(:cookie_only => true))
@@ -57,19 +47,32 @@ module ActionDispatch
private
- def prepare!(env)
- env[ENV_SESSION_KEY] = SessionHash.new(self, env)
- env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
- end
-
def load_session(env)
- request = ActionDispatch::Request.new(env)
- data = request.cookie_jar.signed[@key]
+ data = unpacked_cookie_data(env)
data = persistent_session_id!(data)
- data.stringify_keys!
[data["session_id"], data]
end
+ def extract_session_id(env)
+ if data = unpacked_cookie_data(env)
+ data["session_id"]
+ else
+ nil
+ end
+ end
+
+ def unpacked_cookie_data(env)
+ env["action_dispatch.request.unsigned_session_cookie"] ||= begin
+ stale_session_check! do
+ request = ActionDispatch::Request.new(env)
+ if data = request.cookie_jar.signed[@key]
+ data.stringify_keys!
+ end
+ data || {}
+ end
+ end
+ end
+
def set_cookie(request, options)
request.cookie_jar.signed[@key] = options
end
@@ -78,6 +81,10 @@ module ActionDispatch
persistent_session_id!(session_data, sid)
end
+ def destroy(env)
+ # session data is stored on client; nothing to do here
+ end
+
def persistent_session_id!(data, sid=nil)
data ||= {}
data["session_id"] ||= sid || generate_sid
diff --git a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
index 8df8f977e8..28e3dbd732 100644
--- a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
@@ -42,6 +42,15 @@ module ActionDispatch
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
false
end
+
+ def destroy(env)
+ if sid = current_session_id(env)
+ @pool.delete(sid)
+ end
+ rescue MemCache::MemCacheError, Errno::ECONNREFUSED
+ false
+ end
+
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index c31f681411..388f695187 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -55,7 +55,7 @@ module ActionDispatch
path = args.first
end
- if @scope[:module] && options[:to]
+ if @scope[:module] && options[:to] && !options[:to].is_a?(Proc)
if options[:to].to_s.include?("#")
options[:to] = "#{@scope[:module]}/#{options[:to]}"
elsif @scope[:controller].nil?
@@ -194,7 +194,7 @@ module ActionDispatch
# for root cases, where the latter is the correct one.
def self.normalize_path(path)
path = Rack::Mount::Utils.normalize_path(path)
- path.sub!(%r{/(\(+)/?:}, '\1/:') unless path =~ %r{^/\(+:.*\)$}
+ path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^/]+\)$}
path
end
@@ -299,6 +299,11 @@ module ActionDispatch
options = args.extract_options!
options = options.dup
+ if name_prefix = options.delete(:name_prefix)
+ options[:as] ||= name_prefix
+ ActiveSupport::Deprecation.warn ":name_prefix was deprecated in the new router syntax. Use :as instead.", caller
+ end
+
case args.first
when String
options[:path] = args.first
@@ -341,9 +346,11 @@ module ActionDispatch
scope(controller.to_sym) { yield }
end
- def namespace(path)
+ def namespace(path, options = {})
path = path.to_s
- scope(:path => path, :name_prefix => path, :module => path, :shallow_path => path, :shallow_prefix => path) { yield }
+ options = { :path => path, :as => path, :module => path,
+ :shallow_path => path, :shallow_prefix => path }.merge!(options)
+ scope(options) { yield }
end
def constraints(constraints = {})
@@ -359,10 +366,10 @@ module ActionDispatch
options = (@scope[:options] || {}).merge(options)
- if @scope[:name_prefix] && !options[:as].blank?
- options[:as] = "#{@scope[:name_prefix]}_#{options[:as]}"
- elsif @scope[:name_prefix] && options[:as] == ""
- options[:as] = @scope[:name_prefix].to_s
+ if @scope[:as] && !options[:as].blank?
+ options[:as] = "#{@scope[:as]}_#{options[:as]}"
+ elsif @scope[:as] && options[:as] == ""
+ options[:as] = @scope[:as].to_s
end
args.push(options)
@@ -382,7 +389,7 @@ module ActionDispatch
Mapper.normalize_path("#{parent}/#{child}")
end
- def merge_name_prefix_scope(parent, child)
+ def merge_as_scope(parent, child)
parent ? "#{parent}_#{child}" : child
end
@@ -411,7 +418,9 @@ module ActionDispatch
end
def merge_blocks_scope(parent, child)
- (parent || []) + [child]
+ merged = parent ? parent.dup : []
+ merged << child if child
+ merged
end
def merge_options_scope(parent, child)
@@ -434,7 +443,8 @@ module ActionDispatch
def initialize(entities, options = {})
@name = entities.to_s
@path = options.delete(:path) || @name
- @controller = options.delete(:controller) || @name.to_s.pluralize
+ @controller = (options.delete(:controller) || @name).to_s
+ @as = options.delete(:as)
@options = options
end
@@ -453,7 +463,7 @@ module ActionDispatch
end
def name
- options[:as] || @name
+ @as || @name
end
def plural
@@ -505,7 +515,7 @@ module ActionDispatch
def nested_options
{}.tap do |opts|
- opts[:name_prefix] = member_name
+ opts[:as] = member_name
opts["#{singular}_id".to_sym] = id_constraint if id_constraint?
opts[:options] = { :shallow => shallow? } unless options[:shallow].nil?
end
@@ -537,14 +547,18 @@ module ActionDispatch
[:show, :create, :update, :destroy, :new, :edit]
end
- def initialize(entity, options = {})
- super
+ def initialize(entities, options)
+ @name = entities.to_s
+ @path = options.delete(:path) || @name
+ @controller = (options.delete(:controller) || @name.to_s.pluralize).to_s
+ @as = options.delete(:as)
+ @options = options
end
def member_name
name
end
- alias_method :collection_name, :member_name
+ alias :collection_name :member_name
def nested_path
path
@@ -552,7 +566,7 @@ module ActionDispatch
def nested_options
{}.tap do |opts|
- opts[:name_prefix] = member_name
+ opts[:as] = member_name
opts[:options] = { :shallow => shallow? } unless @options[:shallow].nil?
end
end
@@ -571,6 +585,10 @@ module ActionDispatch
@scope[:path_names] = @set.resources_path_names
end
+ def resources_path_names(options)
+ @scope[:path_names].merge!(options)
+ end
+
def resource(*resources, &block)
options = resources.extract_options!
options = (@scope[:options] || {}).merge(options)
@@ -673,7 +691,7 @@ module ActionDispatch
if @scope[:shallow_path].blank?
scope(*parent_resource.nested_scope) { yield }
else
- scope(@scope[:shallow_path], :name_prefix => @scope[:shallow_prefix]) do
+ scope(@scope[:shallow_path], :as => @scope[:shallow_prefix]) do
scope(*parent_resource.nested_scope) { yield }
end
end
@@ -684,7 +702,7 @@ module ActionDispatch
end
end
- def namespace(path)
+ def namespace(path, options = {})
if resource_scope?
nested { super }
else
@@ -726,10 +744,10 @@ module ActionDispatch
return member { match(*args) }
end
- path_names = options.delete(:path_names)
+ path = options.delete(:path)
if args.first.is_a?(Symbol)
- path = path_for_action(args.first, path_names)
+ path = path_for_action(args.first, path)
options = options_for_action(args.first, options)
with_exclusive_scope do
@@ -758,7 +776,7 @@ module ActionDispatch
def root(options={})
if @scope[:scope_level] == :resources
with_scope_level(:nested) do
- scope(parent_resource.path, :name_prefix => parent_resource.collection_name) do
+ scope(parent_resource.path, :as => parent_resource.collection_name) do
super(options)
end
end
@@ -806,14 +824,14 @@ module ActionDispatch
def with_exclusive_scope
begin
- old_name_prefix, old_path = @scope[:name_prefix], @scope[:path]
- @scope[:name_prefix], @scope[:path] = nil, nil
+ old_name_prefix, old_path = @scope[:as], @scope[:path]
+ @scope[:as], @scope[:path] = nil, nil
with_scope_level(:exclusive) do
yield
end
ensure
- @scope[:name_prefix], @scope[:path] = old_name_prefix, old_path
+ @scope[:as], @scope[:path] = old_name_prefix, old_path
end
end
@@ -850,7 +868,7 @@ module ActionDispatch
end
end
- def path_for_action(action, path_names)
+ def path_for_action(action, path)
case action
when :index, :create
"#{@scope[:path]}(.:format)"
@@ -871,12 +889,12 @@ module ActionDispatch
else
case @scope[:scope_level]
when :collection, :new
- "#{@scope[:path]}/#{action_path(action)}(.:format)"
+ "#{@scope[:path]}/#{action_path(action, path)}(.:format)"
else
if parent_resource.shallow?
- "#{@scope[:shallow_path]}/#{parent_resource.path}/:id/#{action_path(action)}(.:format)"
+ "#{@scope[:shallow_path]}/#{parent_resource.path}/:id/#{action_path(action, path)}(.:format)"
else
- "#{@scope[:path]}/#{action_path(action)}(.:format)"
+ "#{@scope[:path]}/#{action_path(action, path)}(.:format)"
end
end
end
@@ -895,9 +913,8 @@ module ActionDispatch
end
end
- def action_path(name, path_names = nil)
- path_names ||= @scope[:path_names]
- path_names[name.to_sym] || name.to_s
+ def action_path(name, path = nil)
+ path || @scope[:path_names][name.to_sym] || name.to_s
end
def options_for_action(action, options)
@@ -908,7 +925,7 @@ module ActionDispatch
end
def name_for_action(action)
- name_prefix = @scope[:name_prefix].blank? ? "" : "#{@scope[:name_prefix]}_"
+ name_prefix = @scope[:as].blank? ? "" : "#{@scope[:as]}_"
shallow_prefix = @scope[:shallow_prefix].blank? ? "" : "#{@scope[:shallow_prefix]}_"
case action
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 57a73dde75..7be79d3200 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -185,7 +185,7 @@ module ActionDispatch
end
end
- attr_accessor :routes, :named_routes
+ attr_accessor :set, :routes, :named_routes
attr_accessor :disable_clear_and_finalize, :resources_path_names
attr_accessor :default_url_options, :request_class
@@ -296,6 +296,7 @@ module ActionDispatch
@extras = extras
normalize_options!
+ normalize_recall!
normalize_controller_action_id!
use_relative_controller!
controller.sub!(%r{^/}, '') if controller
@@ -336,6 +337,15 @@ module ActionDispatch
end
end
+ def normalize_recall!
+ # If the target route is not a standard route then remove controller and action
+ # from the options otherwise they will appear in the url parameters
+ if block_or_proc_route_target?
+ recall.delete(:controller) unless segment_keys.include?(:controller)
+ recall.delete(:action) unless segment_keys.include?(:action)
+ 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
@@ -371,7 +381,7 @@ module ActionDispatch
def generate
error = ActionController::RoutingError.new("No route matches #{options.inspect}")
- path, params = @set.generate(:path_info, named_route, options, recall, opts)
+ path, params = @set.set.generate(:path_info, named_route, options, recall, opts)
raise error unless path
@@ -402,6 +412,19 @@ module ActionDispatch
return false unless current_controller
controller.to_param != current_controller.to_param
end
+
+ private
+ def named_route_exists?
+ named_route && set.named_routes[named_route]
+ end
+
+ def block_or_proc_route_target?
+ named_route_exists? && !set.named_routes[named_route].app.is_a?(Dispatcher)
+ end
+
+ def segment_keys
+ named_route_exists? ? set.named_routes[named_route].segment_keys : []
+ end
end
# Generate the path indicated by the arguments, and return an array of
@@ -415,7 +438,7 @@ module ActionDispatch
end
def generate(options, recall = {}, extras = false)
- Generator.new(options, recall, @set, extras).generate
+ Generator.new(options, recall, self, extras).generate
end
RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash]
@@ -447,7 +470,7 @@ module ActionDispatch
# 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]
+ rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor]
rewritten_url
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 1499c03bdf..9338fa9e70 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -53,7 +53,6 @@ module ActionDispatch
extras.each_key { |key| expected_options.delete key } unless extras.nil?
expected_options.stringify_keys!
- routing_diff = expected_options.diff(request.path_parameters)
msg = build_message(message, "The recognized options <?> did not match <?>, difference: <?>",
request.path_parameters, expected_options, expected_options.diff(request.path_parameters))
assert_block(msg) { request.path_parameters == expected_options }
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index b490547da7..2fc9e2b7d6 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -7,9 +7,7 @@ require 'action_controller/vendor/html-scanner'
module ActionDispatch
module Assertions
- unless const_defined?(:NO_STRIP)
- NO_STRIP = %w{pre script style textarea}
- end
+ NO_STRIP = %w{pre script style textarea}
# Adds the +assert_select+ method for use in Rails functional
# test cases, which can be used to make assertions on the response HTML of a controller
@@ -581,27 +579,25 @@ module ActionDispatch
end
protected
- unless const_defined?(:RJS_STATEMENTS)
- RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
- RJS_ANY_ID = "\"([^\"])*\""
- RJS_STATEMENTS = {
- :chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)",
- :chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)",
- :replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
- :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
- :redirect => "window.location.href = #{RJS_ANY_ID}"
- }
- [:remove, :show, :hide, :toggle].each do |action|
- RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)"
- end
- RJS_INSERTIONS = ["top", "bottom", "before", "after"]
- RJS_INSERTIONS.each do |insertion|
- RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)"
- end
- RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)"
- RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
- RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
+ RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
+ RJS_ANY_ID = "\"([^\"])*\""
+ RJS_STATEMENTS = {
+ :chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)",
+ :chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)",
+ :replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
+ :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
+ :redirect => "window.location.href = #{RJS_ANY_ID}"
+ }
+ [:remove, :show, :hide, :toggle].each do |action|
+ RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)"
+ end
+ RJS_INSERTIONS = ["top", "bottom", "before", "after"]
+ RJS_INSERTIONS.each do |insertion|
+ RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)"
end
+ RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)"
+ RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
+ RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
# +assert_select+ and +css_select+ call this to obtain the content in the HTML
# page, or from all the RJS statements, depending on the type of response.
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index a7ba9f374a..956c88a553 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -3,6 +3,7 @@ require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/array/wrap'
require 'active_support/ordered_options'
+require 'action_view/log_subscriber'
module ActionView #:nodoc:
class NonConcattingString < ActiveSupport::SafeBuffer
@@ -204,8 +205,12 @@ module ActionView #:nodoc:
value.dup : ActionView::PathSet.new(Array.wrap(value))
end
+ def assign(new_assigns) # :nodoc:
+ self.assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
+ end
+
def initialize(lookup_context = nil, assigns_for_first_render = {}, controller = nil, formats = nil) #:nodoc:
- self.assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) }
+ assign(assigns_for_first_render)
self.helpers = self.class.helpers || Module.new
if @_controller = controller
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index 0f9b04cb5f..6bb0875bc3 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -36,12 +36,16 @@ module ActionView
end
end
- %w(tag content_tag to_date_select_tag to_datetime_select_tag to_time_select_tag).each do |meth|
+ %w(content_tag to_date_select_tag to_datetime_select_tag to_time_select_tag).each do |meth|
module_eval "def #{meth}(*) error_wrapping(super) end", __FILE__, __LINE__
end
+ def tag(type, options, *)
+ tag_generate_errors?(options) ? error_wrapping(super) : super
+ end
+
def error_wrapping(html_tag)
- if object.respond_to?(:errors) && object.errors.respond_to?(:full_messages) && object.errors[@method_name].any?
+ if object_has_errors?
Base.field_error_proc.call(html_tag, self)
else
html_tag
@@ -51,6 +55,16 @@ module ActionView
def error_message
object.errors[@method_name]
end
+
+ private
+
+ def object_has_errors?
+ object.respond_to?(:errors) && object.errors.respond_to?(:full_messages) && error_message.any?
+ end
+
+ def tag_generate_errors?(options)
+ options['type'] != 'hidden'
+ end
end
class FormBuilder
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index d094b0d8d8..a3c43d3e93 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -194,7 +194,19 @@ module ActionView
# RewriteEngine On
# RewriteRule ^/release-\d+/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L]
module AssetTagHelper
- JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls', 'rails'].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
+ mattr_reader :javascript_expansions
+ @@javascript_expansions = { }
+
+ mattr_reader :stylesheet_expansions
+ @@stylesheet_expansions = {}
+
+ # You can enable or disable the asset tag timestamps cache.
+ # With the cache enabled, the asset tag helper methods will make fewer
+ # expensive file system calls. However this prevents you from modifying
+ # any asset files while the server is running.
+ #
+ # ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
+ mattr_accessor :cache_asset_timestamps
# Returns a link tag that browsers and news readers can use to auto-detect
# an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or
@@ -351,8 +363,6 @@ module ActionView
end
end
- @@javascript_expansions = { :defaults => JAVASCRIPT_DEFAULT_SOURCES.dup }
-
# Register one or more javascript files to be included when <tt>symbol</tt>
# is passed to <tt>javascript_include_tag</tt>. This method is typically intended
# to be called from plugin initialization to register javascript files
@@ -368,8 +378,6 @@ module ActionView
@@javascript_expansions.merge!(expansions)
end
- @@stylesheet_expansions = {}
-
# Register one or more stylesheet files to be included when <tt>symbol</tt>
# is passed to <tt>stylesheet_link_tag</tt>. This method is typically intended
# to be called from plugin initialization to register stylesheet files
@@ -385,18 +393,6 @@ module ActionView
@@stylesheet_expansions.merge!(expansions)
end
- # Register one or more additional JavaScript files to be included when
- # <tt>javascript_include_tag :defaults</tt> is called. This method is
- # typically intended to be called from plugin initialization to register additional
- # .js files that the plugin installed in <tt>public/javascripts</tt>.
- def self.register_javascript_include_default(*sources)
- @@javascript_expansions[:defaults].concat(sources)
- end
-
- def self.reset_javascript_include_default #:nodoc:
- @@javascript_expansions[:defaults] = JAVASCRIPT_DEFAULT_SOURCES.dup
- end
-
# Computes the path to a stylesheet asset in the public stylesheets directory.
# If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs).
# Full paths from the document root will be passed through.
@@ -707,23 +703,8 @@ module ActionView
tag("audio", options)
end
- def self.cache_asset_timestamps
- @@cache_asset_timestamps
- end
-
- # You can enable or disable the asset tag timestamps cache.
- # With the cache enabled, the asset tag helper methods will make fewer
- # expensive file system calls. However this prevents you from modifying
- # any asset files while the server is running.
- #
- # ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
- def self.cache_asset_timestamps=(value)
- @@cache_asset_timestamps = value
- end
-
- @@cache_asset_timestamps = true
-
private
+
def rewrite_extension?(source, dir, ext)
source_ext = File.extname(source)[1..-1]
ext && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}"))))
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 7d7b6a1d91..f097b9a5a3 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -582,10 +582,10 @@ module ActionView
extend ActiveSupport::Memoizable
include ActionView::Helpers::TagHelper
- DEFAULT_PREFIX = 'date'.freeze unless const_defined?('DEFAULT_PREFIX')
+ DEFAULT_PREFIX = 'date'.freeze
POSITION = {
:year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6
- }.freeze unless const_defined?('POSITION')
+ }.freeze
def initialize(datetime, options = {}, html_options = {})
@options = options.dup
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 8efed98bd2..d1b10a9281 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -124,7 +124,6 @@ module ActionView
# model:
#
# <%= form_for :person do |f| %>
- # <%= f.error_messages %>
# First name: <%= f.text_field :first_name %><br />
# Last name : <%= f.text_field :last_name %><br />
# Biography : <%= f.text_area :biography %><br />
@@ -221,15 +220,15 @@ module ActionView
# <% end %>
#
# === Unobtrusive JavaScript
- #
- # Specifying:
- #
+ #
+ # Specifying:
+ #
# :remote => true
#
# in the options hash creates a form that will allow the unobtrusive JavaScript drivers to modify its
- # behaviour. The expected default behaviour is an XMLHttpRequest in the background instead of the regular
+ # behaviour. The expected default behaviour is an XMLHttpRequest in the background instead of the regular
# POST arrangement, but ultimately the behaviour is the choice of the JavaScript driver implementor.
- # Even though it's using JavaScript to serialize the form elements, the form submission will work just like
+ # Even though it's using JavaScript to serialize the form elements, the form submission will work just like
# a regular submission as viewed by the receiving side (all elements available in <tt>params</tt>).
#
# Example:
@@ -839,9 +838,9 @@ module ActionView
attr_reader :method_name, :object_name
- DEFAULT_FIELD_OPTIONS = { "size" => 30 }.freeze unless const_defined?(:DEFAULT_FIELD_OPTIONS)
- DEFAULT_RADIO_OPTIONS = { }.freeze unless const_defined?(:DEFAULT_RADIO_OPTIONS)
- DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 }.freeze unless const_defined?(:DEFAULT_TEXT_AREA_OPTIONS)
+ DEFAULT_FIELD_OPTIONS = { "size" => 30 }.freeze
+ DEFAULT_RADIO_OPTIONS = { }.freeze
+ DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 }.freeze
def initialize(object_name, method_name, template_object, object = nil)
@object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
@@ -898,7 +897,7 @@ module ActionView
options.delete("size")
end
options["type"] ||= field_type
- options["value"] ||= value_before_type_cast(object) unless field_type == "file"
+ options["value"] = options.fetch("value"){ value_before_type_cast(object) } unless field_type == "file"
options["value"] &&= html_escape(options["value"])
add_default_name_and_id(options)
tag("input", options)
@@ -1031,7 +1030,7 @@ module ActionView
private
def add_default_name_and_id_for_value(tag_value, options)
unless tag_value.nil?
- pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase
+ pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase
specified_id = options["id"]
add_default_name_and_id(options)
options["id"] += "_#{pretty_tag_value}" if specified_id.blank? && options["id"].present?
@@ -1043,14 +1042,14 @@ module ActionView
def add_default_name_and_id(options)
if options.has_key?("index")
options["name"] ||= tag_name_with_index(options["index"])
- options["id"] = options.fetch("id", tag_id_with_index(options["index"]))
+ options["id"] = options.fetch("id"){ tag_id_with_index(options["index"]) }
options.delete("index")
elsif defined?(@auto_index)
options["name"] ||= tag_name_with_index(@auto_index)
- options["id"] = options.fetch("id", tag_id_with_index(@auto_index))
+ options["id"] = options.fetch("id"){ tag_id_with_index(@auto_index) }
else
options["name"] ||= tag_name + (options.has_key?('multiple') ? '[]' : '')
- options["id"] = options.fetch("id", tag_id)
+ options["id"] = options.fetch("id"){ tag_id }
end
end
@@ -1181,7 +1180,7 @@ module ActionView
# <%= form_for @post do |f| %>
# <%= f.submit %>
# <% end %>
- #
+ #
# In the example above, if @post is a new record, it will use "Create Post" as
# submit button label, otherwise, it uses "Update Post".
#
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 3038b07143..bfb8f74a00 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -95,14 +95,12 @@ module ActionView
# See JavaScriptGenerator for information on updating multiple elements
# on the page in an Ajax response.
module PrototypeHelper
- unless const_defined? :CALLBACKS
- CALLBACKS = Set.new([ :create, :uninitialized, :loading, :loaded,
- :interactive, :complete, :failure, :success ] +
- (100..599).to_a)
- AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
- :asynchronous, :method, :insertion, :position,
- :form, :with, :update, :script, :type ]).merge(CALLBACKS)
- end
+ CALLBACKS = Set.new([ :create, :uninitialized, :loading, :loaded,
+ :interactive, :complete, :failure, :success ] +
+ (100..599).to_a)
+ AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
+ :asynchronous, :method, :insertion, :position,
+ :form, :with, :update, :script, :type ]).merge(CALLBACKS)
# Returns the JavaScript needed for a remote function.
# Takes the same arguments as link_to_remote.
diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb
index 7f7776e9c0..8610c2469e 100644
--- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb
+++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb
@@ -4,7 +4,7 @@ require 'active_support/json'
module ActionView
# = Action View Scriptaculous Helpers
module Helpers
- # Provides a set of helpers for calling Scriptaculous[http://script.aculo.us/]
+ # Provides a set of helpers for calling Scriptaculous[http://script.aculo.us/]
# JavaScript functions, including those which create Ajax controls and visual
# effects.
#
@@ -18,9 +18,7 @@ module ActionView
# See the documentation at http://script.aculo.us for more information on
# using these helpers in your application.
module ScriptaculousHelper
- unless const_defined? :TOGGLE_EFFECTS
- TOGGLE_EFFECTS = [:toggle_appear, :toggle_slide, :toggle_blind]
- end
+ TOGGLE_EFFECTS = [:toggle_appear, :toggle_slide, :toggle_blind]
# Returns a JavaScript snippet to be used on the Ajax callbacks for
# starting visual effects.
diff --git a/actionpack/lib/action_view/log_subscriber.rb b/actionpack/lib/action_view/log_subscriber.rb
new file mode 100644
index 0000000000..4a52937c58
--- /dev/null
+++ b/actionpack/lib/action_view/log_subscriber.rb
@@ -0,0 +1,27 @@
+module ActionView
+ # = Action View Log Subscriber
+ #
+ # Provides functionality so that Rails can output logs from Action View.
+ class LogSubscriber < ActiveSupport::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]
+ message << (" (%.1fms)" % event.duration)
+ info(message)
+ end
+ alias :render_partial :render_template
+ alias :render_collection :render_template
+
+ def logger
+ ActionController::Base.logger
+ end
+
+ protected
+
+ def from_rails_root(string)
+ string.sub("#{Rails.root}/", "").sub(/^app\/views\//, "")
+ end
+ end
+end
+
+ActionView::LogSubscriber.attach_to :action_view \ No newline at end of file
diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb
index e8ea15f47c..33dfcbb803 100644
--- a/actionpack/lib/action_view/railtie.rb
+++ b/actionpack/lib/action_view/railtie.rb
@@ -5,9 +5,8 @@ module ActionView
# = Action View Railtie
class Railtie < Rails::Railtie
config.action_view = ActiveSupport::OrderedOptions.new
-
- require "action_view/railties/log_subscriber"
- log_subscriber :action_view, ActionView::Railties::LogSubscriber.new
+ config.action_view.stylesheet_expansions = {}
+ config.action_view.javascript_expansions = { :defaults => ['prototype', 'effects', 'dragdrop', 'controls', 'rails'] }
initializer "action_view.cache_asset_timestamps" do |app|
unless app.config.cache_classes
@@ -17,6 +16,18 @@ module ActionView
end
end
+ initializer "action_view.javascript_expansions" do |app|
+ ActiveSupport.on_load(:action_view) do
+ ActionView::Helpers::AssetTagHelper.register_javascript_expansion(
+ app.config.action_view.delete(:javascript_expansions)
+ )
+
+ ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion(
+ app.config.action_view.delete(:stylesheet_expansions)
+ )
+ end
+ end
+
initializer "action_view.set_configs" do |app|
ActiveSupport.on_load(:action_view) do
app.config.action_view.each do |k,v|
diff --git a/actionpack/lib/action_view/railties/log_subscriber.rb b/actionpack/lib/action_view/railties/log_subscriber.rb
deleted file mode 100644
index cb2ad0711e..0000000000
--- a/actionpack/lib/action_view/railties/log_subscriber.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-module ActionView
- # = Action View Log Subscriber
- #
- # Provides functionality so that Rails can output logs from Action View.
- module Railties
- 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]
- message << (" (%.1fms)" % event.duration)
- info(message)
- end
- alias :render_partial :render_template
- alias :render_collection :render_template
-
- def logger
- ActionController::Base.logger
- end
-
- protected
-
- def from_rails_root(string)
- string.sub("#{Rails.root}/", "").sub(/^app\/views\//, "")
- end
- end
- end
-end \ No newline at end of file
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 2cf7e955ab..c9e20ca14e 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -99,7 +99,7 @@ module ActionView
def initialize(path)
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
super()
- @path = Pathname.new(path).expand_path
+ @path = File.expand_path(path)
end
def eql?(resolver)
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index b698b4cfec..757e4cf77c 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -99,10 +99,15 @@ module ActionView
end
def render(options = {}, local_assigns = {}, &block)
- @rendered << output = _view.render(options, local_assigns, &block)
+ view.assign(_assigns)
+ @rendered << output = view.render(options, local_assigns, &block)
output
end
+ def locals
+ @locals ||= {}
+ end
+
included do
setup :setup_with_controller
end
@@ -132,36 +137,51 @@ module ActionView
end
end
- def _view
- @_view ||= begin
- view = ActionView::Base.new(ActionController::Base.view_paths, _assigns, @controller)
+ module Locals
+ attr_accessor :locals
+
+ def _render_partial(options)
+ locals[options[:partial]] = options[:locals]
+ super(options)
+ end
+ end
+
+ # The instance of ActionView::Base that is used by +render+.
+ def view
+ @view ||= begin
+ view = ActionView::Base.new(ActionController::Base.view_paths, {}, @controller)
view.singleton_class.send :include, _helpers
view.singleton_class.send :include, @controller._router.url_helpers
view.singleton_class.send :delegate, :alert, :notice, :to => "request.flash"
+ view.extend(Locals)
+ view.locals = self.locals
view.output_buffer = self.output_buffer
view
end
end
+ alias_method :_view, :view
+
EXCLUDE_IVARS = %w{
+ @_assertion_wrapped
@_result
+ @controller
+ @layouts
+ @locals
+ @method_name
@output_buffer
+ @partials
@rendered
+ @request
+ @routes
@templates
- @view_context_class
- @layouts
- @partials
- @controller
-
- @method_name
- @fixture_cache
- @loaded_fixtures
@test_passed
+ @view
+ @view_context_class
}
def _instance_variables
instance_variables - EXCLUDE_IVARS
- instance_variables
end
def _assigns
diff --git a/actionpack/test/abstract/callbacks_test.rb b/actionpack/test/abstract/callbacks_test.rb
index 0ce1dc506b..232a1679e0 100644
--- a/actionpack/test/abstract/callbacks_test.rb
+++ b/actionpack/test/abstract/callbacks_test.rb
@@ -47,8 +47,12 @@ module AbstractController
end
def index
- self.response_body = @text
- end
+ self.response_body = @text.to_s
+ end
+ end
+
+ class Callback2Overwrite < Callback2
+ before_filter :first, :except => :index
end
class TestCallbacks2 < ActiveSupport::TestCase
@@ -70,6 +74,12 @@ module AbstractController
@controller.process(:index)
assert_equal "FIRSTSECOND", @controller.instance_variable_get("@aroundz")
end
+
+ test "before_filter with overwritten condition" do
+ @controller = Callback2Overwrite.new
+ result = @controller.process(:index)
+ assert_equal "", @controller.response_body
+ end
end
class Callback3 < ControllerWithCallbacks
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 84c5395610..2640e96453 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -202,6 +202,21 @@ class ActionController::IntegrationTest < ActiveSupport::TestCase
self.class.app = old_app
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
end
+
+ def with_autoload_path(path)
+ path = File.join(File.dirname(__FILE__), "fixtures", path)
+ if ActiveSupport::Dependencies.autoload_paths.include?(path)
+ yield
+ else
+ begin
+ ActiveSupport::Dependencies.autoload_paths << path
+ yield
+ ensure
+ ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
+ ActiveSupport::Dependencies.clear
+ end
+ end
+ end
end
# Temporary base class
diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb
index 6d4b8e1e40..bdd1a0a15c 100644
--- a/actionpack/test/activerecord/active_record_store_test.rb
+++ b/actionpack/test/activerecord/active_record_store_test.rb
@@ -17,7 +17,6 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
end
def get_session_id
- session[:foo]
render :text => "#{request.session_options[:id]}"
end
@@ -58,6 +57,10 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
get '/get_session_value'
assert_response :success
assert_equal 'foo: "baz"', response.body
+
+ get '/call_reset_session'
+ assert_response :success
+ assert_not_equal [], headers['Set-Cookie']
end
end
end
@@ -92,6 +95,34 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
end
end
+ def test_getting_session_value_after_session_reset
+ with_test_route_set do
+ get '/set_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+ session_cookie = cookies.send(:hash_for)['_session_id']
+
+ get '/call_reset_session'
+ assert_response :success
+ assert_not_equal [], headers['Set-Cookie']
+
+ cookies << session_cookie # replace our new session_id with our old, pre-reset session_id
+
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from the database"
+ end
+ end
+
+ def test_getting_from_nonexistent_session
+ with_test_route_set do
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: nil', response.body
+ assert_nil cookies['_session_id'], "should only create session on write, not read"
+ end
+ end
+
def test_getting_session_id
with_test_route_set do
get '/set_session_value'
@@ -101,7 +132,19 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
get '/get_session_id'
assert_response :success
- assert_equal session_id, response.body
+ assert_equal session_id, response.body, "should be able to read session id without accessing the session hash"
+ end
+ end
+
+ def test_doesnt_write_session_cookie_if_session_id_is_already_exists
+ with_test_route_set do
+ get '/set_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+
+ get '/get_session_value'
+ assert_response :success
+ assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists"
end
end
diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionpack/test/activerecord/controller_runtime_test.rb
index 331f861d8f..cfd86d704d 100644
--- a/actionpack/test/activerecord/controller_runtime_test.rb
+++ b/actionpack/test/activerecord/controller_runtime_test.rb
@@ -1,8 +1,8 @@
require 'active_record_unit'
require 'active_record/railties/controller_runtime'
require 'fixtures/project'
-require 'rails/log_subscriber/test_helper'
-require 'action_controller/railties/log_subscriber'
+require 'active_support/log_subscriber/test_helper'
+require 'action_controller/log_subscriber'
ActionController::Base.send :include, ActiveRecord::Railties::ControllerRuntime
@@ -13,18 +13,18 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase
end
end
- include Rails::LogSubscriber::TestHelper
+ include ActiveSupport::LogSubscriber::TestHelper
tests LogSubscriberController
def setup
super
@old_logger = ActionController::Base.logger
- Rails::LogSubscriber.add(:action_controller, ActionController::Railties::LogSubscriber.new)
+ ActionController::LogSubscriber.attach_to :action_controller
end
def teardown
super
- Rails::LogSubscriber.log_subscribers.clear
+ ActiveSupport::LogSubscriber.log_subscribers.clear
ActionController::Base.logger = @old_logger
end
diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb
index 5c636cbab8..4be09f8c83 100644
--- a/actionpack/test/controller/flash_test.rb
+++ b/actionpack/test/controller/flash_test.rb
@@ -236,6 +236,15 @@ class FlashIntegrationTest < ActionController::IntegrationTest
end
end
+ def test_just_using_flash_does_not_stream_a_cookie_back
+ with_test_route_set do
+ get '/use_flash'
+ assert_response :success
+ assert_nil @response.headers["Set-Cookie"]
+ assert_equal "flash: ", @response.body
+ end
+ end
+
private
# Overwrite get to send SessionSecret in env hash
@@ -247,10 +256,15 @@ class FlashIntegrationTest < ActionController::IntegrationTest
def with_test_route_set
with_routing do |set|
set.draw do |map|
- match ':action', :to => ActionDispatch::Session::CookieStore.new(
- FlashIntegrationTest::TestController, :key => FlashIntegrationTest::SessionKey, :secret => FlashIntegrationTest::SessionSecret
- )
+ match ':action', :to => FlashIntegrationTest::TestController
+ end
+
+ @app = self.class.build_app(set) do |middleware|
+ middleware.use ActionDispatch::Session::CookieStore, :key => SessionKey
+ middleware.use ActionDispatch::Flash
+ middleware.delete "ActionDispatch::ShowExceptions"
end
+
yield
end
end
diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb
index b11eba2f89..0a18741f0c 100644
--- a/actionpack/test/controller/log_subscriber_test.rb
+++ b/actionpack/test/controller/log_subscriber_test.rb
@@ -1,6 +1,6 @@
require "abstract_unit"
-require "rails/log_subscriber/test_helper"
-require "action_controller/railties/log_subscriber"
+require "active_support/log_subscriber/test_helper"
+require "action_controller/log_subscriber"
module Another
class LogSubscribersController < ActionController::Base
@@ -37,7 +37,7 @@ end
class ACLogSubscriberTest < ActionController::TestCase
tests Another::LogSubscribersController
- include Rails::LogSubscriber::TestHelper
+ include ActiveSupport::LogSubscriber::TestHelper
def setup
super
@@ -47,12 +47,12 @@ class ACLogSubscriberTest < ActionController::TestCase
@cache_path = File.expand_path('../temp/test_cache', File.dirname(__FILE__))
ActionController::Base.page_cache_directory = @cache_path
@controller.cache_store = :file_store, @cache_path
- Rails::LogSubscriber.add(:action_controller, ActionController::Railties::LogSubscriber.new)
+ ActionController::LogSubscriber.attach_to :action_controller
end
def teardown
super
- Rails::LogSubscriber.log_subscribers.clear
+ ActiveSupport::LogSubscriber.log_subscribers.clear
FileUtils.rm_rf(@cache_path)
ActionController::Base.logger = @old_logger
end
diff --git a/actionpack/test/controller/new_base/base_test.rb b/actionpack/test/controller/new_base/base_test.rb
index 0b40f8ce95..8fa5d20372 100644
--- a/actionpack/test/controller/new_base/base_test.rb
+++ b/actionpack/test/controller/new_base/base_test.rb
@@ -31,9 +31,17 @@ module Dispatching
end
class EmptyController < ActionController::Base ; end
+ class SubEmptyController < EmptyController ; end
+ class NonDefaultPathController < ActionController::Base
+ def self.controller_path; "i_am_not_default"; end
+ end
module Submodule
class ContainedEmptyController < ActionController::Base ; end
+ class ContainedSubEmptyController < ContainedEmptyController ; end
+ class ContainedNonDefaultPathController < ActionController::Base
+ def self.controller_path; "i_am_extremly_not_default"; end
+ end
end
class BaseTest < Rack::TestCase
@@ -65,16 +73,46 @@ module Dispatching
assert_equal EmptyController.controller_path, EmptyController.new.controller_path
end
+ test "non-default controller path" do
+ assert_equal 'i_am_not_default', NonDefaultPathController.controller_path
+ assert_equal NonDefaultPathController.controller_path, NonDefaultPathController.new.controller_path
+ end
+
+ test "sub controller path" do
+ assert_equal 'dispatching/sub_empty', SubEmptyController.controller_path
+ assert_equal SubEmptyController.controller_path, SubEmptyController.new.controller_path
+ end
+
test "namespaced controller path" do
assert_equal 'dispatching/submodule/contained_empty', Submodule::ContainedEmptyController.controller_path
assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path
end
+ test "namespaced non-default controller path" do
+ assert_equal 'i_am_extremly_not_default', Submodule::ContainedNonDefaultPathController.controller_path
+ assert_equal Submodule::ContainedNonDefaultPathController.controller_path, Submodule::ContainedNonDefaultPathController.new.controller_path
+ end
+
+ test "namespaced sub controller path" do
+ assert_equal 'dispatching/submodule/contained_sub_empty', Submodule::ContainedSubEmptyController.controller_path
+ assert_equal Submodule::ContainedSubEmptyController.controller_path, Submodule::ContainedSubEmptyController.new.controller_path
+ end
+
test "controller name" do
assert_equal 'empty', EmptyController.controller_name
assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name
end
+ test "non-default path controller name" do
+ assert_equal 'non_default_path', NonDefaultPathController.controller_name
+ assert_equal 'contained_non_default_path', Submodule::ContainedNonDefaultPathController.controller_name
+ end
+
+ test "sub controller name" do
+ assert_equal 'sub_empty', SubEmptyController.controller_name
+ assert_equal 'contained_sub_empty', Submodule::ContainedSubEmptyController.controller_name
+ end
+
test "action methods" do
assert_equal Set.new(%w(
index
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 907acf9573..4b30b0af36 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -34,9 +34,15 @@ module AbstractController
)
end
- def test_anchor_should_be_cgi_escaped
- assert_equal('/c/a#anc%2Fhor',
- W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('anc/hor'))
+ def test_anchor_should_escape_unsafe_pchar
+ assert_equal('/c/a#%23anchor',
+ W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('#anchor'))
+ )
+ end
+
+ def test_anchor_should_not_escape_safe_pchar
+ assert_equal('/c/a#name=user&email=user@domain.com',
+ W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('name=user&email=user@domain.com'))
)
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 495255c22b..cf92b039e3 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -16,6 +16,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
Routes = routes
Routes.draw do
default_url_options :host => "rubyonrails.org"
+ resources_path_names :correlation_indexes => "info_about_correlation_indexes"
controller :sessions do
get 'login' => :new
@@ -70,12 +71,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get 'admin/passwords' => "queenbee#passwords", :constraints => ::TestRoutingMapper::IpRestrictor
- scope 'pt', :name_prefix => 'pt' do
+ scope 'pt', :as => 'pt' do
resources :projects, :path_names => { :edit => 'editar', :new => 'novo' }, :path => 'projetos' do
post :preview, :on => :new
+ put :close, :on => :member, :path => 'fechar'
+ get :open, :on => :new, :path => 'abrir'
end
- resource :admin, :path_names => { :new => 'novo' }, :path => 'administrador' do
+ resource :admin, :path_names => { :new => 'novo', :activate => 'ativar' }, :path => 'administrador' do
post :preview, :on => :new
+ put :activate, :on => :member
end
resources :products, :path_names => { :new => 'novo' } do
new do
@@ -86,6 +90,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
resources :projects, :controller => :project do
resources :involvements, :attachments
+ get :correlation_indexes, :on => :collection
resources :participants do
put :update_all, :on => :collection
@@ -112,6 +117,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
member do
+ get :some_path_with_name
put :accessible_projects
post :resend, :generate_new_password
end
@@ -207,6 +213,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "profile" => "customers#profile", :as => :profile, :on => :member
post "preview" => "customers#preview", :as => :preview, :on => :new
end
+ scope(':version', :version => /.+/) do
+ resources :users, :id => /.+?/, :format => /json|xml/
+ end
end
match 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
@@ -242,10 +251,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ namespace :users, :path => 'usuarios' do
+ root :to => 'home#index'
+ end
+
controller :articles do
- scope '/articles', :name_prefix => 'article' do
+ scope '/articles', :as => 'article' do
scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do
- match '/:id', :to => :with_id
+ match '/:id', :to => :with_id, :as => ""
end
end
end
@@ -290,6 +303,21 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
match '/' => 'mes#index'
end
+ namespace :private do
+ root :to => redirect('/private/index')
+ match "index", :to => 'private#index'
+ end
+
+ get "(/:username)/followers" => "followers#index"
+ get "/groups(/user/:username)" => "groups#index"
+ get "(/user/:username)/photos" => "photos#index"
+
+ scope '(groups)' do
+ scope '(discussions)' do
+ resources :messages
+ end
+ end
+
match "whatever/:controller(/:action(/:id))"
resource :profile do
@@ -299,6 +327,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
post :preview
end
end
+
+ resources :content
+
+ match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/
end
end
@@ -411,6 +443,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_namespace_redirect
+ with_test_routes do
+ get '/private'
+ assert_equal 301, @response.status
+ assert_equal 'http://www.example.com/private/index', @response.headers['Location']
+ assert_equal 'Moved Permanently', @response.body
+ end
+ end
+
def test_session_singleton_resource
with_test_routes do
get '/session'
@@ -706,6 +747,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_projects_with_resources_path_names
+ with_test_routes do
+ get '/projects/info_about_correlation_indexes'
+ assert_equal 'project#correlation_indexes', @response.body
+ assert_equal '/projects/info_about_correlation_indexes', correlation_indexes_projects_path
+ end
+ end
+
def test_projects_posts
with_test_routes do
get '/projects/1/posts'
@@ -839,6 +888,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/pt/administrador/novo'
assert_equal 'admins#new', @response.body
assert_equal '/pt/administrador/novo', new_pt_admin_path
+
+ put '/pt/administrador/ativar'
+ assert_equal 'admins#activate', @response.body
+ assert_equal '/pt/administrador/ativar', activate_pt_admin_path
+ end
+ end
+
+ def test_path_option_override
+ with_test_routes do
+ get '/pt/projetos/novo/abrir'
+ assert_equal 'projects#open', @response.body
+ assert_equal '/pt/projetos/novo/abrir', open_new_pt_project_path
+
+ put '/pt/projetos/1/fechar'
+ assert_equal 'projects#close', @response.body
+ assert_equal '/pt/projetos/1/fechar', close_pt_project_path(1)
end
end
@@ -932,6 +997,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_namespace_with_options
+ with_test_routes do
+ get '/usuarios'
+ assert_equal '/usuarios', users_root_path
+ assert_equal 'users/home#index', @response.body
+ end
+ end
+
def test_articles_with_id
with_test_routes do
get '/articles/rails/1'
@@ -1365,6 +1438,114 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_non_greedy_regexp
+ with_test_routes do
+ get '/api/1.0/users'
+ assert_equal 'api/users#index', @response.body
+ assert_equal '/api/1.0/users', api_users_path(:version => '1.0')
+
+ get '/api/1.0/users.json'
+ assert_equal 'api/users#index', @response.body
+ assert_equal true, @request.format.json?
+ assert_equal '/api/1.0/users.json', api_users_path(:version => '1.0', :format => :json)
+
+ get '/api/1.0/users/first.last'
+ assert_equal 'api/users#show', @response.body
+ assert_equal 'first.last', @request.params[:id]
+ assert_equal '/api/1.0/users/first.last', api_user_path(:version => '1.0', :id => 'first.last')
+
+ get '/api/1.0/users/first.last.xml'
+ assert_equal 'api/users#show', @response.body
+ assert_equal 'first.last', @request.params[:id]
+ assert_equal true, @request.format.xml?
+ assert_equal '/api/1.0/users/first.last.xml', api_user_path(:version => '1.0', :id => 'first.last', :format => :xml)
+ end
+ end
+
+ def test_glob_parameter_accepts_regexp
+ with_test_routes do
+ get '/en/path/to/existing/file.html'
+ assert_equal 200, @response.status
+ end
+ end
+
+ def test_resources_controller_name_is_not_pluralized
+ with_test_routes do
+ get '/content'
+ assert_equal 'content#index', @response.body
+ end
+ end
+
+ def test_url_generator_for_optional_prefix_dynamic_segment
+ with_test_routes do
+ get '/bob/followers'
+ assert_equal 'followers#index', @response.body
+ assert_equal 'http://www.example.com/bob/followers',
+ url_for(:controller => "followers", :action => "index", :username => "bob")
+
+ get '/followers'
+ assert_equal 'followers#index', @response.body
+ assert_equal 'http://www.example.com/followers',
+ url_for(:controller => "followers", :action => "index", :username => nil)
+ end
+ end
+
+ def test_url_generator_for_optional_suffix_static_and_dynamic_segment
+ with_test_routes do
+ get '/groups/user/bob'
+ assert_equal 'groups#index', @response.body
+ assert_equal 'http://www.example.com/groups/user/bob',
+ url_for(:controller => "groups", :action => "index", :username => "bob")
+
+ get '/groups'
+ assert_equal 'groups#index', @response.body
+ assert_equal 'http://www.example.com/groups',
+ url_for(:controller => "groups", :action => "index", :username => nil)
+ end
+ end
+
+ def test_url_generator_for_optional_prefix_static_and_dynamic_segment
+ with_test_routes do
+ get 'user/bob/photos'
+ assert_equal 'photos#index', @response.body
+ assert_equal 'http://www.example.com/user/bob/photos',
+ url_for(:controller => "photos", :action => "index", :username => "bob")
+
+ get 'photos'
+ assert_equal 'photos#index', @response.body
+ assert_equal 'http://www.example.com/photos',
+ url_for(:controller => "photos", :action => "index", :username => nil)
+ end
+ end
+
+ def test_url_recognition_for_optional_static_segments
+ with_test_routes do
+ get '/groups/discussions/messages'
+ assert_equal 'messages#index', @response.body
+
+ get '/groups/discussions/messages/1'
+ assert_equal 'messages#show', @response.body
+
+ get '/groups/messages'
+ assert_equal 'messages#index', @response.body
+
+ get '/groups/messages/1'
+ assert_equal 'messages#show', @response.body
+
+ get '/discussions/messages'
+ assert_equal 'messages#index', @response.body
+
+ get '/discussions/messages/1'
+ assert_equal 'messages#show', @response.body
+
+ get '/messages'
+ assert_equal 'messages#index', @response.body
+
+ get '/messages/1'
+ assert_equal 'messages#show', @response.body
+ end
+ end
+
private
def with_test_routes
yield
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index b4380f7818..fd63f5ad5e 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -83,7 +83,7 @@ class CookieStoreTest < ActionController::IntegrationTest
get '/get_session_id'
assert_response :success
- assert_equal "id: #{session_id}", response.body
+ assert_equal "id: #{session_id}", response.body, "should be able to read session id without accessing the session hash"
end
end
@@ -96,6 +96,31 @@ class CookieStoreTest < ActionController::IntegrationTest
end
end
+ # {:foo=>#<SessionAutoloadTest::Foo bar:"baz">, :session_id=>"ce8b0752a6ab7c7af3cdb8a80e6b9e46"}
+ SignedSerializedCookie = "BAh7BzoIZm9vbzodU2Vzc2lvbkF1dG9sb2FkVGVzdDo6Rm9vBjoJQGJhciIIYmF6Og9zZXNzaW9uX2lkIiVjZThiMDc1MmE2YWI3YzdhZjNjZGI4YTgwZTZiOWU0Ng==--2bf3af1ae8bd4e52b9ac2099258ace0c380e601c"
+
+ def test_deserializes_unloaded_classes_on_get_id
+ with_test_route_set do
+ with_autoload_path "session_autoload_test" do
+ cookies[SessionKey] = SignedSerializedCookie
+ get '/get_session_id'
+ assert_response :success
+ assert_equal 'id: ce8b0752a6ab7c7af3cdb8a80e6b9e46', response.body, "should auto-load unloaded class"
+ end
+ end
+ end
+
+ def test_deserializes_unloaded_classes_on_get_value
+ with_test_route_set do
+ with_autoload_path "session_autoload_test" do
+ cookies[SessionKey] = SignedSerializedCookie
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: #<SessionAutoloadTest::Foo bar:"baz">', response.body, "should auto-load unloaded class"
+ end
+ end
+ end
+
def test_close_raises_when_data_overflows
with_test_route_set do
assert_raise(ActionDispatch::Cookies::CookieOverflow) {
@@ -141,6 +166,15 @@ class CookieStoreTest < ActionController::IntegrationTest
end
end
+ def test_getting_from_nonexistent_session
+ with_test_route_set do
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: nil', response.body
+ assert_nil headers['Set-Cookie'], "should only create session on write, not read"
+ end
+ end
+
def test_persistent_session_id
with_test_route_set do
cookies[SessionKey] = SignedBar
@@ -196,21 +230,21 @@ class CookieStoreTest < ActionController::IntegrationTest
def test_session_store_without_domain
with_test_route_set do
get '/set_session_value'
- assert_no_match /domain\=/, headers['Set-Cookie']
+ assert_no_match(/domain\=/, headers['Set-Cookie'])
end
end
def test_session_store_with_nil_domain
with_test_route_set(:domain => nil) do
get '/set_session_value'
- assert_no_match /domain\=/, headers['Set-Cookie']
+ assert_no_match(/domain\=/, headers['Set-Cookie'])
end
end
def test_session_store_with_all_domains
with_test_route_set(:domain => :all) do
get '/set_session_value'
- assert_match /domain=\.example\.com/, headers['Set-Cookie']
+ assert_match(/domain=\.example\.com/, headers['Set-Cookie'])
end
end
@@ -238,4 +272,5 @@ class CookieStoreTest < ActionController::IntegrationTest
yield
end
end
+
end
diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb
index 8858a398e0..9bd6f9b8c4 100644
--- a/actionpack/test/dispatch/session/mem_cache_store_test.rb
+++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -11,13 +11,17 @@ class MemCacheStoreTest < ActionController::IntegrationTest
session[:foo] = "bar"
head :ok
end
+
+ def set_serialized_session_value
+ session[:foo] = SessionAutoloadTest::Foo.new
+ head :ok
+ end
def get_session_value
render :text => "foo: #{session[:foo].inspect}"
end
def get_session_id
- session[:foo]
render :text => "#{request.session_options[:id]}"
end
@@ -56,6 +60,34 @@ class MemCacheStoreTest < ActionController::IntegrationTest
end
end
+ def test_getting_session_value_after_session_reset
+ with_test_route_set do
+ get '/set_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+ session_cookie = cookies.send(:hash_for)['_session_id']
+
+ get '/call_reset_session'
+ assert_response :success
+ assert_not_equal [], headers['Set-Cookie']
+
+ cookies << session_cookie # replace our new session_id with our old, pre-reset session_id
+
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from memcached"
+ end
+ end
+
+ def test_getting_from_nonexistent_session
+ with_test_route_set do
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: nil', response.body
+ assert_nil cookies['_session_id'], "should only create session on write, not read"
+ end
+ end
+
def test_setting_session_value_after_session_reset
with_test_route_set do
get '/set_session_value'
@@ -86,7 +118,38 @@ class MemCacheStoreTest < ActionController::IntegrationTest
get '/get_session_id'
assert_response :success
- assert_equal session_id, response.body
+ assert_equal session_id, response.body, "should be able to read session id without accessing the session hash"
+ end
+ end
+
+ def test_deserializes_unloaded_class
+ with_test_route_set do
+ with_autoload_path "session_autoload_test" do
+ get '/set_serialized_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+ end
+ with_autoload_path "session_autoload_test" do
+ get '/get_session_id'
+ assert_response :success
+ end
+ with_autoload_path "session_autoload_test" do
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: #<SessionAutoloadTest::Foo bar:"baz">', response.body, "should auto-load unloaded class"
+ end
+ end
+ end
+
+ def test_doesnt_write_session_cookie_if_session_id_is_already_exists
+ with_test_route_set do
+ get '/set_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+
+ get '/get_session_value'
+ assert_response :success
+ assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists"
end
end
diff --git a/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb b/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb
new file mode 100644
index 0000000000..4ee7a24561
--- /dev/null
+++ b/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb
@@ -0,0 +1,10 @@
+module SessionAutoloadTest
+ class Foo
+ def initialize(bar='baz')
+ @bar = bar
+ end
+ def inspect
+ "#<#{self.class} bar:#{@bar.inspect}>"
+ end
+ end
+end
diff --git a/actionpack/test/template/active_model_helper_test.rb b/actionpack/test/template/active_model_helper_test.rb
index b1705072c2..6ab244d178 100644
--- a/actionpack/test/template/active_model_helper_test.rb
+++ b/actionpack/test/template/active_model_helper_test.rb
@@ -39,6 +39,13 @@ class ActiveModelHelperTest < ActionView::TestCase
)
end
+ def test_hidden_field_does_not_render_errors
+ assert_dom_equal(
+ %(<input id="post_author_name" name="post[author_name]" type="hidden" value="" />),
+ hidden_field("post", "author_name")
+ )
+ end
+
def test_field_error_proc
old_proc = ActionView::Base.field_error_proc
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 633641514e..6d5e4893c4 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -44,7 +44,7 @@ class AssetTagHelperTest < ActionView::TestCase
@controller.request = @request
- ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
+ ActionView::Helpers::AssetTagHelper::register_javascript_expansion :defaults => ['prototype', 'effects', 'dragdrop', 'controls', 'rails']
end
def url_for(*args)
@@ -256,19 +256,6 @@ class AssetTagHelperTest < ActionView::TestCase
assert javascript_include_tag("prototype").html_safe?
end
- def test_register_javascript_include_default
- ENV["RAILS_ASSET_ID"] = ""
- ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'bank'
- assert_dom_equal %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/rails.js" type="text/javascript"></script>\n<script src="/javascripts/bank.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>), javascript_include_tag(:defaults)
- end
-
- def test_register_javascript_include_default_mixed_defaults
- ENV["RAILS_ASSET_ID"] = ""
- ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'bank'
- ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'robber', '/elsewhere/cools.js'
- assert_dom_equal %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/rails.js" type="text/javascript"></script>\n<script src="/javascripts/bank.js" type="text/javascript"></script>\n<script src="/javascripts/robber.js" type="text/javascript"></script>\n<script src="/elsewhere/cools.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>), javascript_include_tag(:defaults)
- end
-
def test_custom_javascript_expansions
ENV["RAILS_ASSET_ID"] = ""
ActionView::Helpers::AssetTagHelper::register_javascript_expansion :robbery => ["bank", "robber"]
@@ -286,6 +273,11 @@ class AssetTagHelperTest < ActionView::TestCase
assert_raise(ArgumentError) { javascript_include_tag('first', :monkey, 'last') }
end
+ def test_reset_javascript_expansions
+ ActionView::Helpers::AssetTagHelper.javascript_expansions.clear
+ assert_raise(ArgumentError) { javascript_include_tag(:defaults) }
+ end
+
def test_stylesheet_path
ENV["RAILS_ASSET_ID"] = ""
StylePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
@@ -923,7 +915,7 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
@request = Struct.new(:protocol).new("gopher://")
@controller.request = @request
- ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
+ ActionView::Helpers::AssetTagHelper.javascript_expansions.clear
end
def url_for(options)
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 8de1e782c0..6ba407e230 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -188,6 +188,11 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, text_field("post", "title", :maxlength => 35, :size => nil)
end
+ def test_text_field_with_nil_value
+ expected = '<input id="post_title" name="post[title]" size="30" type="text" />'
+ assert_dom_equal expected, text_field("post", "title", :value => nil)
+ end
+
def test_text_field_doesnt_change_param_values
object_name = 'post[]'
expected = '<input id="post_123_title" name="post[123][title]" size="30" type="text" value="Hello World" />'
@@ -208,6 +213,11 @@ class FormHelperTest < ActionView::TestCase
hidden_field("post", "title")
end
+ def test_hidden_field_with_nil_value
+ expected = '<input id="post_title" name="post[title]" type="hidden" />'
+ assert_dom_equal expected, hidden_field("post", "title", :value => nil)
+ end
+
def test_text_field_with_options
assert_dom_equal '<input id="post_title" name="post[title]" type="hidden" value="Something Else" />',
hidden_field("post", "title", :value => "Something Else")
@@ -300,6 +310,11 @@ class FormHelperTest < ActionView::TestCase
)
end
+ def test_radio_button_with_negative_integer_value
+ assert_dom_equal('<input id="post_secret_-1" name="post[secret]" type="radio" value="-1" />',
+ radio_button("post", "secret", "-1"))
+ end
+
def test_radio_button_respects_passed_in_id
assert_dom_equal('<input checked="checked" id="foo" name="post[secret]" type="radio" value="1" />',
radio_button("post", "secret", "1", :id=>"foo")
diff --git a/actionpack/test/template/log_subscriber_test.rb b/actionpack/test/template/log_subscriber_test.rb
index 5076dfa70f..eb1e548672 100644
--- a/actionpack/test/template/log_subscriber_test.rb
+++ b/actionpack/test/template/log_subscriber_test.rb
@@ -1,22 +1,22 @@
require "abstract_unit"
-require "rails/log_subscriber/test_helper"
-require "action_view/railties/log_subscriber"
+require "active_support/log_subscriber/test_helper"
+require "action_view/log_subscriber"
require "controller/fake_models"
class AVLogSubscriberTest < ActiveSupport::TestCase
- include Rails::LogSubscriber::TestHelper
+ include ActiveSupport::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::LogSubscriber.add(:action_view, ActionView::Railties::LogSubscriber.new)
+ ActionView::LogSubscriber.attach_to :action_view
end
def teardown
super
- Rails::LogSubscriber.log_subscribers.clear
+ ActiveSupport::LogSubscriber.log_subscribers.clear
ActionController::Base.logger = @old_logger
end
diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb
index c365aec841..a0c46f8a59 100644
--- a/actionpack/test/template/test_case_test.rb
+++ b/actionpack/test/template/test_case_test.rb
@@ -37,8 +37,12 @@ module ActionView
include SharedTests
test_case = self
- test "memoizes the _view" do
- assert_same _view, _view
+ test "memoizes the view" do
+ assert_same view, view
+ end
+
+ test "exposes view as _view for backwards compatibility" do
+ assert_same _view, view
end
test "works without testing a helper module" do
@@ -61,13 +65,13 @@ module ActionView
end
test "delegates notice to request.flash" do
- _view.request.flash.expects(:notice).with("this message")
- _view.notice("this message")
+ view.request.flash.expects(:notice).with("this message")
+ view.notice("this message")
end
test "delegates alert to request.flash" do
- _view.request.flash.expects(:alert).with("this message")
- _view.alert("this message")
+ view.request.flash.expects(:alert).with("this message")
+ view.alert("this message")
end
end
@@ -136,7 +140,7 @@ module ActionView
helper HelperThatInvokesProtectAgainstForgery
test "protect_from_forgery? in any helpers returns false" do
- assert !_view.help_me
+ assert !view.help_me
end
end
@@ -200,6 +204,15 @@ module ActionView
assert_match /Hello: EloyHello: Manfred/, render(:file => 'test/list')
end
+ test "is able to render partials from templates and also use instance variables after view has been referenced" do
+ @controller.controller_path = "test"
+
+ view
+
+ @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')]
+ assert_match /Hello: EloyHello: Manfred/, render(:file => 'test/list')
+ end
+
end
class AssertionsTest < ActionView::TestCase
@@ -220,10 +233,24 @@ module ActionView
end
class RenderTemplateTest < ActionView::TestCase
- test "render template" do
+ test "supports specifying partials" do
controller.controller_path = "test"
render(:template => "test/calling_partial_with_layout")
- assert_template "partial_for_use_in_layout"
+ assert_template :partial => "_partial_for_use_in_layout"
+ end
+
+ test "supports specifying locals (passing)" do
+ controller.controller_path = "test"
+ render(:template => "test/calling_partial_with_layout")
+ assert_template :partial => "_partial_for_use_in_layout", :locals => { :name => "David" }
+ end
+
+ test "supports specifying locals (failing)" do
+ controller.controller_path = "test"
+ render(:template => "test/calling_partial_with_layout")
+ assert_raise ActiveSupport::TestCase::Assertion, /Somebody else.*David/m do
+ assert_template :partial => "_partial_for_use_in_layout", :locals => { :name => "Somebody Else" }
+ end
end
end
end
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 299d6dd5bd..72d4897630 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -429,6 +429,10 @@ class UrlHelperControllerTest < ActionController::TestCase
map.connect ":controller/:action/:id"
# match "/:controller(/:action(/:id))"
+
+ match 'url_helper_controller_test/url_helper/normalize_recall_params',
+ :to => UrlHelperController.action(:normalize_recall),
+ :as => :normalize_recall_params
end
def show_url_for
@@ -447,6 +451,14 @@ class UrlHelperControllerTest < ActionController::TestCase
render :inline => '<%= url_for(nil) %>'
end
+ def normalize_recall_params
+ render :inline => '<%= normalize_recall_params_path %>'
+ end
+
+ def recall_params_not_changed
+ render :inline => '<%= url_for(:action => :show_url_for) %>'
+ end
+
def rescue_action(e) raise e end
end
@@ -488,6 +500,16 @@ class UrlHelperControllerTest < ActionController::TestCase
get :show_named_route, :kind => 'url'
assert_equal 'http://testtwo.host/url_helper_controller_test/url_helper/show_named_route', @response.body
end
+
+ def test_recall_params_should_be_normalized_when_using_block_route
+ get :normalize_recall_params
+ assert_equal '/url_helper_controller_test/url_helper/normalize_recall_params', @response.body
+ end
+
+ def test_recall_params_should_not_be_changed_when_using_normal_route
+ get :recall_params_not_changed
+ assert_equal '/url_helper_controller_test/url_helper/show_url_for', @response.body
+ end
end
class TasksController < ActionController::Base