Merge commit 'rails/master'

Conflicts:

	activerecord/lib/active_record/base.rb
	activerecord/lib/active_record/migration.rb
	activerecord/test/cases/helper.rb
This commit is contained in:
Emilio Tagua
2009-05-18 11:18:46 -03:00
175 changed files with 2001 additions and 984 deletions

View File

@@ -1,6 +1,5 @@
require 'rake'
require 'rake/rdoctask'
require 'rake/contrib/sshpublisher'
env = %(PKG_BUILD="#{ENV['PKG_BUILD']}") if ENV['PKG_BUILD']
@@ -13,12 +12,14 @@ end
desc 'Run all tests by default'
task :default => :test
%w(test rdoc pgem package release).each do |task_name|
%w(test isolated_test rdoc pgem package release).each do |task_name|
desc "Run #{task_name} task for all projects"
task task_name do
errors = []
PROJECTS.each do |project|
system %(cd #{project} && #{env} #{$0} #{task_name})
system(%(cd #{project} && #{env} #{$0} #{task_name})) || errors << project
end
fail("Errors in #{errors.join(', ')}") unless errors.empty?
end
end
@@ -74,6 +75,7 @@ end
desc "Publish API docs for Rails as a whole and for each component"
task :pdoc => :rdoc do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/api", "doc/rdoc").upload
PROJECTS.each do |project|
system %(cd #{project} && #{env} #{$0} pdoc)

View File

@@ -28,6 +28,12 @@ Rake::TestTask.new { |t|
t.warning = false
}
task :isolated_test do
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir.glob("test/*_test.rb").all? do |file|
system(ruby, '-Ilib:test', file)
end or raise "Failures"
end
# Generate the RDoc documentation
Rake::RDocTask.new { |rdoc|

View File

@@ -12,6 +12,7 @@ end
require 'tmail'
require 'active_support/core_ext/kernel/reporting'
silence_warnings do
TMail::Encoder.const_set("MAX_LINE_LEN", 200)
end

View File

@@ -1,5 +1,7 @@
*Edge*
* Instead of checking Rails.env.test? in Failsafe middleware, check env["rails.raise_exceptions"] [Bryan Helmkamp]
* Fixed that TestResponse.cookies was returning cookies unescaped #1867 [Doug McInnes]

View File

@@ -22,7 +22,7 @@ task :default => [ :test ]
# Run the unit tests
desc "Run all unit tests"
task :test => [:test_action_pack, :test_active_record_integration, :test_new_base]
task :test => [:test_action_pack, :test_active_record_integration]
Rake::TestTask.new(:test_action_pack) do |t|
t.libs << "test"
@@ -34,6 +34,12 @@ Rake::TestTask.new(:test_action_pack) do |t|
t.verbose = true
#t.warning = true
end
task :isolated_test do
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir.glob("test/{controller,dispatch,template}/**/*_test.rb").all? do |file|
system(ruby, '-Ilib:test', file)
end or raise "Failures"
end
desc 'ActiveRecord Integration Tests'
Rake::TestTask.new(:test_active_record_integration) do |t|

View File

@@ -0,0 +1,34 @@
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
require 'action_controller'
require 'action_controller/new_base' if ENV['NEW']
require 'benchmark'
class BaseController < ActionController::Base
def index
render :text => ''
end
end
n = (ENV['N'] || 10000).to_i
input = StringIO.new('')
def call_index(controller, input, n)
n.times do
controller.action(:index).call({ 'rack.input' => input })
end
puts controller.name
status, headers, body = controller.action(:index).call({ 'rack.input' => input })
puts status
puts headers.to_yaml
puts '---'
body.each do |part|
puts part
end
puts '---'
end
elapsed = Benchmark.realtime { call_index BaseController, input, n }
puts "%dms elapsed, %d requests/sec" % [1000 * elapsed, n / elapsed]

View File

@@ -21,16 +21,9 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
begin
require 'active_support'
rescue LoadError
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
if File.directory?(activesupport_path)
$:.unshift activesupport_path
require 'active_support'
end
end
require 'active_support/core/all'
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift activesupport_path if File.directory?(activesupport_path)
require 'active_support'
require File.join(File.dirname(__FILE__), "action_pack")

View File

@@ -1,3 +1,6 @@
require "active_support/core_ext/module/attr_internal"
require "active_support/core_ext/module/delegation"
module AbstractController
autoload :Base, "action_controller/abstract/base"
autoload :Callbacks, "action_controller/abstract/callbacks"

View File

@@ -1,4 +1,16 @@
require 'active_support/core_ext/module/attr_internal'
module AbstractController
class Error < StandardError; end
class DoubleRenderError < Error
DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
def initialize(message = nil)
super(message || DEFAULT_MESSAGE)
end
end
class Base
attr_internal :response_body
@@ -13,6 +25,15 @@ module AbstractController
end
alias_method :abstract?, :abstract
def inherited(klass)
::AbstractController::Base.subclasses << klass.to_s
super
end
def subclasses
@subclasses ||= []
end
def internal_methods
controller = self
@@ -48,12 +69,13 @@ module AbstractController
end
def process(action_name)
unless respond_to_action?(action_name)
@_action_name = action_name = action_name.to_s
unless action_name = method_for_action(action_name)
raise ActionNotFound, "The action '#{action_name}' could not be found"
end
@_action_name = action_name
process_action
process_action(action_name)
self
end
@@ -63,23 +85,31 @@ module AbstractController
self.class.action_methods
end
def action_method?(action)
action_methods.include?(action)
end
# It is possible for respond_to?(action_name) to be false and
# respond_to?(:action_missing) to be false if respond_to_action?
# is overridden in a subclass. For instance, ActionController::Base
# overrides it to include the case where a template matching the
# action_name is found.
def process_action
if respond_to?(action_name) then send(action_name)
elsif respond_to?(:action_missing, true) then action_missing(action_name)
end
def process_action(method_name)
send(method_name)
end
def _handle_action_missing
action_missing(@_action_name)
end
# Override this to change the conditions that will raise an
# ActionNotFound error. If you accept a difference case,
# you must handle it by also overriding process_action and
# handling the case.
def respond_to_action?(action_name)
action_methods.include?(action_name) || respond_to?(:action_missing, true)
def method_for_action(action_name)
if action_method?(action_name) then action_name
elsif respond_to?(:action_missing, true) then "_handle_action_missing"
end
end
end
end

View File

@@ -5,11 +5,11 @@ module AbstractController
depends_on ActiveSupport::NewCallbacks
included do
define_callbacks :process_action
define_callbacks :process_action, "response_body"
end
def process_action
_run_process_action_callbacks(action_name) do
def process_action(method_name)
_run_process_action_callbacks(method_name) do
super
end
end

View File

@@ -51,7 +51,7 @@ module AbstractController
end
def _render_template(template, options)
_action_view._render_template_with_layout(template, options[:_layout], options)
_action_view._render_template_from_controller(template, options[:_layout], options, options[:_partial])
end
private

View File

@@ -1,9 +1,44 @@
require 'active_support/core_ext/class/attribute_accessors'
module AbstractController
module Logger
extend ActiveSupport::DependencyModule
class DelayedLog
def initialize(&blk)
@blk = blk
end
def to_s
@blk.call
end
alias to_str to_s
end
included do
cattr_accessor :logger
end
def process(action)
ret = super
if logger
log = DelayedLog.new do
"\n\nProcessing #{self.class.name}\##{action_name} " \
"to #{request.formats} " \
"(for #{request_origin}) [#{request.method.to_s.upcase}]"
end
logger.info(log)
end
ret
end
def request_origin
# this *needs* to be cached!
# otherwise you'd get different results if calling it more than once
@request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}"
end
end
end
end

View File

@@ -1,15 +1,6 @@
require "action_controller/abstract/logger"
module AbstractController
class AbstractControllerError < StandardError; end
class DoubleRenderError < AbstractControllerError
DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
def initialize(message = nil)
super(message || DEFAULT_MESSAGE)
end
end
module Renderer
extend ActiveSupport::DependencyModule
@@ -27,12 +18,12 @@ module AbstractController
@_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self)
end
def render(options = {})
def render(*args)
if response_body
raise AbstractController::DoubleRenderError, "OMG"
end
self.response_body = render_to_body(options)
self.response_body = render_to_body(*args)
end
# Raw rendering of a template to a Rack-compatible body.
@@ -43,10 +34,16 @@ module AbstractController
# :api: plugin
def render_to_body(options = {})
name = options[:_template_name] || action_name
options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix])
_render_template(options[:_template], options)
# TODO: Refactor so we can just use the normal template logic for this
if options[:_partial_object]
_action_view._render_partial_from_controller(options)
else
options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats},
options[:_prefix], options[:_partial])
_render_template(options[:_template], options)
end
end
# Raw rendering of a template to a string.
@@ -60,7 +57,7 @@ module AbstractController
end
def _render_template(template, options)
_action_view._render_template_with_layout(template)
_action_view._render_template_from_controller(template, nil, options, options[:_partial])
end
def view_paths() _view_paths end

View File

@@ -1,5 +1,7 @@
require 'action_controller/deprecated'
require 'set'
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/module/attr_internal'
module ActionController #:nodoc:
class ActionControllerError < StandardError #:nodoc:
@@ -366,9 +368,8 @@ module ActionController #:nodoc:
attr_reader :template
def action(name, env)
# HACK: For global rescue to have access to the original request and response
request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env)
response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new
request = ActionDispatch::Request.new(env)
response = ActionDispatch::Response.new
self.action_name = name && name.to_s
process(request, response).to_a
end

View File

@@ -1,4 +1,4 @@
require 'benchmark'
require 'active_support/core_ext/benchmark'
module ActionController #:nodoc:
# The benchmarking module times the performance of actions and reports to the logger. If the Active Record

View File

@@ -160,7 +160,7 @@ module ActionController #:nodoc:
def convert_only_and_except_options_to_sets_of_strings(opts)
[:only, :except].each do |key|
if values = opts[key]
opts[key] = Array(values).map(&:to_s).to_set
opts[key] = Array(values).map {|val| val.to_s }.to_set
end
end
end
@@ -571,12 +571,7 @@ module ActionController #:nodoc:
# Returns an array of Filter objects for this controller.
def filter_chain
if chain = read_inheritable_attribute('filter_chain')
return chain
else
write_inheritable_attribute('filter_chain', FilterChain.new)
return filter_chain
end
read_inheritable_attribute('filter_chain') || write_inheritable_attribute('filter_chain', FilterChain.new)
end
# Returns all the before filters for this class and all its ancestors.

View File

@@ -1,3 +1,5 @@
require 'active_support/base64'
module ActionController
module HttpAuthentication
# Makes it dead easy to do HTTP Basic authentication.
@@ -276,7 +278,7 @@ module ActionController
t = time.to_i
hashed = [t, secret_key]
digest = ::Digest::MD5.hexdigest(hashed.join(":"))
Base64.encode64("#{t}:#{digest}").gsub("\n", '')
ActiveSupport::Base64.encode64("#{t}:#{digest}").gsub("\n", '')
end
# Might want a shorter timeout depending on whether the request
@@ -285,7 +287,7 @@ module ActionController
# allow a user to use new nonce without prompting user again for their
# username and password.
def validate_nonce(request, value, seconds_to_timeout=5*60)
t = Base64.decode64(value).split(":").first.to_i
t = ActiveSupport::Base64.decode64(value).split(":").first.to_i
nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end

View File

@@ -1,3 +1,7 @@
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/class/delegating_attributes'
require 'active_support/core_ext/class/inheritable_attributes'
module ActionController #:nodoc:
module Layout #:nodoc:
def self.included(base)

View File

@@ -70,7 +70,9 @@ module ActionController
def redirect_to_full_url(url, status)
raise DoubleRenderError if performed?
logger.info("Redirected to #{url}") if logger && logger.info?
response.redirect(url, interpret_status(status))
response.status = interpret_status(status)
response.location = url.gsub(/[\r\n]/, '')
response.body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>"
@performed_redirect = true
end

View File

@@ -1,46 +1,11 @@
require 'active_support/core_ext/module/delegation'
module ActionController
# Dispatches requests to the appropriate controller and takes care of
# reloading the app after each request when Dependencies.load? is true.
class Dispatcher
class << self
def define_dispatcher_callbacks(cache_classes)
unless cache_classes
# Development mode callbacks
before_dispatch :reload_application
after_dispatch :cleanup_application
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
end
if defined?(ActiveRecord)
to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
end
after_dispatch :flush_logger if Base.logger && Base.logger.respond_to?(:flush)
to_prepare do
I18n.reload!
end
end
# Add a preparation callback. Preparation callbacks are run before every
# request in development mode, and before the first request in production
# mode.
#
# An optional identifier may be supplied for the callback. If provided,
# to_prepare may be called again with the same identifier to replace the
# existing callback. Passing an identifier is a suggested practice if the
# code adding a preparation block may be reloaded.
def to_prepare(identifier = nil, &block)
@prepare_dispatch_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new
callback = ActiveSupport::Callbacks::Callback.new(:prepare_dispatch, block, :identifier => identifier)
@prepare_dispatch_callbacks.replace_or_append!(callback)
end
def run_prepare_callbacks
new.send :run_callbacks, :prepare_dispatch
end
end
cattr_accessor :prepare_each_request
self.prepare_each_request = false
cattr_accessor :router
self.router = Routing::Routes
@@ -51,37 +16,50 @@ module ActionController
middleware.instance_eval(File.read(middlewares), middlewares, 1)
end
include ActiveSupport::Callbacks
define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch
class << self
def define_dispatcher_callbacks(cache_classes)
unless cache_classes
# Run prepare callbacks before every request in development mode
self.prepare_each_request = true
def initialize
@app = @@middleware.build(@@router)
freeze
end
# Development mode callbacks
ActionDispatch::Callbacks.before_dispatch do |app|
ActionController::Dispatcher.router.reload
end
def call(env)
run_callbacks :before_dispatch
@app.call(env)
ensure
run_callbacks :after_dispatch, :enumerator => :reverse_each
end
ActionDispatch::Callbacks.after_dispatch do
# Cleanup the application before processing the current request.
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
ActiveSupport::Dependencies.clear
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
end
def reload_application
# Run prepare callbacks before every request in development mode
run_callbacks :prepare_dispatch
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
end
@@router.reload
end
if defined?(ActiveRecord)
to_prepare(:activerecord_instantiate_observers) do
ActiveRecord::Base.instantiate_observers
end
end
def cleanup_application
# Cleanup the application before processing the current request.
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
ActiveSupport::Dependencies.clear
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
end
if Base.logger && Base.logger.respond_to?(:flush)
after_dispatch do
Base.logger.flush
end
end
def flush_logger
Base.logger.flush
to_prepare do
I18n.reload!
end
end
delegate :to_prepare, :prepare_dispatch, :before_dispatch, :after_dispatch,
:to => ActionDispatch::Callbacks
def new
@@middleware.build(@@router)
end
end
end
end

View File

@@ -2,10 +2,11 @@ use "Rack::Lock", :if => lambda {
!ActionController::Base.allow_concurrency
}
use "ActionDispatch::Failsafe"
use "ActionDispatch::ShowExceptions", lambda { ActionController::Base.consider_all_requests_local }
use "ActionDispatch::Callbacks", lambda { ActionController::Dispatcher.prepare_each_request }
use "ActionDispatch::Rescue", lambda {
controller = (::ApplicationController rescue ActionController::Base)
# TODO: Replace with controller.action(:_rescue_action)
controller.method(:rescue_action)
}

View File

@@ -5,7 +5,9 @@ module ActionController
autoload :Http, "action_controller/new_base/http"
autoload :Layouts, "action_controller/new_base/layouts"
autoload :Rails2Compatibility, "action_controller/new_base/compatibility"
autoload :Redirector, "action_controller/new_base/redirector"
autoload :Renderer, "action_controller/new_base/renderer"
autoload :Rescue, "action_controller/new_base/rescuable"
autoload :Testing, "action_controller/new_base/testing"
autoload :UrlFor, "action_controller/new_base/url_for"

View File

@@ -8,17 +8,44 @@ module ActionController
include ActionController::HideActions
include ActionController::UrlFor
include ActionController::Redirector
include ActionController::Renderer
include ActionController::Layouts
include ActionController::ConditionalGet
# Legacy modules
include SessionManagement
include ActionDispatch::StatusCodes
# Rails 2.x compatibility
include ActionController::Rails2Compatibility
# TODO: Extract into its own module
# This should be moved together with other normalizing behavior
module ImplicitRender
def process_action(method_name)
ret = super
render if response_body.nil?
ret
end
def _implicit_render
render
end
def method_for_action(action_name)
super || begin
if view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
"_implicit_render"
end
end
end
end
include ImplicitRender
include ActionController::Rescue
def self.inherited(klass)
::ActionController::Base.subclasses << klass.to_s
super
@@ -34,29 +61,83 @@ module ActionController
end
end
def render(action = action_name, options = {})
def render_to_body(action = nil, options = {})
if action.is_a?(Hash)
options, action = action, nil
else
options.merge! :action => action
elsif action.is_a?(String) || action.is_a?(Symbol)
key = case action = action.to_s
when %r{^/} then :file
when %r{/} then :template
else :action
end
options.merge! key => action
elsif action
options.merge! :partial => action
end
super(options)
if options.key?(:action) && options[:action].to_s.index("/")
options[:template] = options.delete(:action)
end
# options = {:template => options.to_s} if options.is_a?(String) || options.is_a?(Symbol)
super(options) || " "
end
def render_to_body(options = {})
options = {:template => options} if options.is_a?(String)
super
end
def process_action
ret = super
render if response_body.nil?
ret
end
def respond_to_action?(action_name)
super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
# Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
#
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
# * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
# * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
# * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
# Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
#
# Examples:
# redirect_to :action => "show", :id => 5
# redirect_to post
# redirect_to "http://www.rubyonrails.org"
# redirect_to "/images/screenshot.jpg"
# redirect_to articles_url
# redirect_to :back
#
# The redirection happens as a "302 Moved" header unless otherwise specified.
#
# Examples:
# redirect_to post_url(@post), :status=>:found
# redirect_to :action=>'atom', :status=>:moved_permanently
# redirect_to post_url(@post), :status=>301
# redirect_to :action=>'atom', :status=>302
#
# When using <tt>redirect_to :back</tt>, if there is no referrer,
# RedirectBackError will be raised. You may specify some fallback
# behavior for this case by rescuing RedirectBackError.
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
status = if options.is_a?(Hash) && options.key?(:status)
interpret_status(options.delete(:status))
elsif response_status.key?(:status)
interpret_status(response_status[:status])
else
302
end
url = case options
# The scheme name consist of a letter followed by any combination of
# letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
# characters; and is terminated by a colon (":").
when %r{^\w[\w\d+.-]*:.*}
options
when String
request.protocol + request.host_with_port + options
when :back
raise RedirectBackError unless refer = request.headers["Referer"]
refer
else
url_for(options)
end
super(url, status)
end
end
end

View File

@@ -8,27 +8,51 @@ module ActionController
::ActionController::DoubleRenderError = ::AbstractController::DoubleRenderError
cattr_accessor :session_options
self.send(:class_variable_set, "@@session_options", {})
self.session_options = {}
cattr_accessor :allow_concurrency
self.send(:class_variable_set, "@@allow_concurrency", false)
self.allow_concurrency = false
cattr_accessor :param_parsers
self.send(:class_variable_set, "@@param_parsers", { Mime::MULTIPART_FORM => :multipart_form,
Mime::URL_ENCODED_FORM => :url_encoded_form,
Mime::XML => :xml_simple,
Mime::JSON => :json })
self.param_parsers = { Mime::MULTIPART_FORM => :multipart_form,
Mime::URL_ENCODED_FORM => :url_encoded_form,
Mime::XML => :xml_simple,
Mime::JSON => :json }
cattr_accessor :relative_url_root
self.send(:class_variable_set, "@@relative_url_root", ENV['RAILS_RELATIVE_URL_ROOT'])
self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT']
cattr_accessor :default_charset
self.send(:class_variable_set, "@@default_charset", "utf-8")
self.default_charset = "utf-8"
cattr_reader :protected_instance_variables
self.send(:class_variable_set, "@@protected_instance_variables", %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller
# cattr_reader :protected_instance_variables
cattr_accessor :protected_instance_variables
self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller
@action_name @before_filter_chain_aborted @action_cache_path @_headers @_params
@_flash @_response))
@_flash @_response)
# Indicates whether or not optimise the generated named
# route helper methods
cattr_accessor :optimise_named_routes
self.optimise_named_routes = true
cattr_accessor :resources_path_names
self.resources_path_names = { :new => 'new', :edit => 'edit' }
# Controls the resource action separator
cattr_accessor :resource_action_separator
self.resource_action_separator = "/"
cattr_accessor :use_accept_header
self.use_accept_header = true
cattr_accessor :page_cache_directory
self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
cattr_reader :cache_store
cattr_accessor :consider_all_requests_local
self.consider_all_requests_local = true
end
module ClassMethods
@@ -37,8 +61,18 @@ module ActionController
def rescue_action(env)
raise env["action_dispatch.rescue.exception"]
end
# Defines the storage option for cached fragments
def cache_store=(store_option)
@@cache_store = ActiveSupport::Cache.lookup_store(store_option)
end
end
def initialize(*)
super
@template = _action_view
end
def render_to_body(options)
if options.is_a?(Hash) && options.key?(:template)
options[:template].sub!(/^\//, '')
@@ -48,6 +82,14 @@ module ActionController
super
end
def _handle_method_missing
method_missing(@_action_name.to_sym)
end
def method_for_action(action_name)
super || (respond_to?(:method_missing) && "_handle_method_missing")
end
def _layout_for_name(name)
name &&= name.sub(%r{^/?layouts/}, '')

View File

@@ -12,8 +12,8 @@ module ActionController
private
def respond_to_action?(action_name)
!hidden_actions.include?(action_name) && (super || respond_to?(:method_missing))
def action_method?(action_name)
!hidden_actions.include?(action_name) && super
end
module ClassMethods

View File

@@ -1,3 +1,6 @@
require 'action_controller/abstract'
require 'active_support/core_ext/module/delegation'
module ActionController
class Http < AbstractController::Base
abstract!
@@ -21,11 +24,6 @@ module ActionController
# :api: public
def controller_path() self.class.controller_path end
# :api: private
def self.internal_methods
ActionController::Http.public_instance_methods(true)
end
# :api: private
def self.action_names() action_methods end
@@ -38,26 +36,32 @@ module ActionController
controller.call(env).to_rack
end
delegate :headers, :to => "@_response"
def params
@_params ||= @_request.parameters
end
# :api: private
def call(name, env)
@_request = ActionDispatch::Request.new(env)
@_response = ActionDispatch::Response.new
@_response.request = request
process(name)
@_response.body = response_body
@_response.prepare!
to_rack
end
def self.action(name)
@actions ||= {}
@actions[name] ||= proc do |env|
@actions[name.to_s] ||= proc do |env|
new.call(name, env)
end
end
# :api: private
def to_rack
@_response.body = response_body
@_response.prepare!
@_response.to_a
end
end

View File

@@ -15,7 +15,7 @@ module ActionController
# render :text => ..., :layout => ...
# or
# render :anything_else
if (!options.key?(:text) && !options.key?(:inline)) || options.key?(:layout)
if (!options.key?(:text) && !options.key?(:inline) && !options.key?(:partial)) || options.key?(:layout)
options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout
end

View File

@@ -0,0 +1,19 @@
module ActionController
class RedirectBackError < AbstractController::Error #:nodoc:
DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].'
def initialize(message = nil)
super(message || DEFAULT_MESSAGE)
end
end
module Redirector
def redirect_to(url, status) #:doc:
raise AbstractController::DoubleRenderError if response_body
logger.info("Redirected to #{url}") if logger && logger.info?
response.status = status
response.location = url.gsub(/[\r\n]/, '')
self.response_body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>"
end
end
end

View File

@@ -9,13 +9,9 @@ module ActionController
super
end
def render(options = {})
def render_to_body(options)
_process_options(options)
super(options)
end
def render_to_body(options)
if options.key?(:text)
options[:_template] = ActionView::TextTemplate.new(_text(options))
template = nil
@@ -25,12 +21,18 @@ module ActionController
options[:_template] = template
elsif options.key?(:template)
options[:_template_name] = options[:template]
elsif options.key?(:file)
options[:_template_name] = options[:file]
elsif options.key?(:partial)
_render_partial(options[:partial], options)
else
options[:_template_name] = (options[:action] || action_name).to_s
options[:_prefix] = _prefix
end
ret = super(options)
options[:_template] ||= _action_view._partial
response.content_type ||= options[:_template].mime_type
ret
end
@@ -49,6 +51,21 @@ module ActionController
else text.to_s
end
end
def _render_partial(partial, options)
case partial
when true
options[:_prefix] = _prefix
when String
options[:_prefix] = _prefix unless partial.index('/')
options[:_template_name] = partial
else
options[:_partial_object] = true
return
end
options[:_partial] = options[:object] || true
end
def _process_options(options)
status, content_type = options.values_at(:status, :content_type)

View File

@@ -0,0 +1,53 @@
module ActionController #:nodoc:
# Actions that fail to perform as expected throw exceptions. These
# exceptions can either be rescued for the public view (with a nice
# user-friendly explanation) or for the developers view (with tons of
# debugging information). The developers view is already implemented by
# the Action Controller, but the public view should be tailored to your
# specific application.
#
# The default behavior for public exceptions is to render a static html
# file with the name of the error code thrown. If no such file exists, an
# empty response is sent with the correct status code.
#
# You can override what constitutes a local request by overriding the
# <tt>local_request?</tt> method in your own controller. Custom rescue
# behavior is achieved by overriding the <tt>rescue_action_in_public</tt>
# and <tt>rescue_action_locally</tt> methods.
module Rescue
extend ActiveSupport::DependencyModule
included do
include ActiveSupport::Rescuable
end
module ClassMethods
# This can be removed once we can move action(:_rescue_action) into middlewares.rb
# Currently, it does controller.method(:rescue_action), which is hiding the implementation
# difference between the old and new base.
def rescue_action(env)
action(:_rescue_action).call(env)
end
end
attr_internal :rescued_exception
private
def method_for_action(action_name)
return action_name if self.rescued_exception = request.env.delete("action_dispatch.rescue.exception")
super
end
def _rescue_action
rescue_with_handler(rescued_exception) || raise(rescued_exception)
end
def process_action(*)
super
rescue Exception => exception
self.rescued_exception = exception
_rescue_action
end
end
end

View File

@@ -7,7 +7,7 @@ module ActionController
@_response = response
@_response.request = request
ret = process(request.parameters[:action])
@_response.body = self.response_body
@_response.body = self.response_body || " "
@_response.prepare!
set_test_assigns
ret

View File

@@ -1,3 +1,5 @@
require 'active_support/core_ext/module'
module ActionController
# The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
# Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate

View File

@@ -1,5 +1,9 @@
require 'cgi'
require 'uri'
require 'set'
require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/module/attribute_accessors'
require 'action_controller/routing/optimisations'
require 'action_controller/routing/routing_ext'
require 'action_controller/routing/route'

View File

@@ -1,3 +1,5 @@
require 'active_support/core_ext/hash/except'
module ActionController
module Routing
class RouteBuilder #:nodoc:

View File

@@ -1,3 +1,5 @@
require 'active_support/core_ext/object/misc'
module ActionController
module Routing
class Route #:nodoc:
@@ -65,7 +67,7 @@ module ActionController
# map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
#
def parameter_shell
@parameter_shell ||= returning({}) do |shell|
@parameter_shell ||= {}.tap do |shell|
requirements.each do |key, requirement|
shell[key] = requirement unless requirement.is_a? Regexp
end
@@ -76,7 +78,7 @@ module ActionController
# includes keys that appear inside the path, and keys that have requirements
# placed upon them.
def significant_keys
@significant_keys ||= returning([]) do |sk|
@significant_keys ||= [].tap do |sk|
segments.each { |segment| sk << segment.key if segment.respond_to? :key }
sk.concat requirements.keys
sk.uniq!
@@ -86,7 +88,7 @@ module ActionController
# Return a hash of key/value pairs representing the keys in the route that
# have defaults, or which are specified by non-regexp requirements.
def defaults
@defaults ||= returning({}) do |hash|
@defaults ||= {}.tap do |hash|
segments.each do |segment|
next unless segment.respond_to? :default
hash[segment.key] = segment.default unless segment.default.nil?

View File

@@ -1,4 +1,5 @@
require 'rack/session/abstract/id'
require 'active_support/core_ext/object/conversions'
module ActionController #:nodoc:
class TestRequest < ActionDispatch::TestRequest #:nodoc:
@@ -131,9 +132,6 @@ module ActionController #:nodoc:
@request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
build_request_uri(action, parameters)
@request.env["action_controller.rescue.request"] = @request
@request.env["action_controller.rescue.response"] = @response
Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest
env = @request.env
@@ -161,11 +159,13 @@ module ActionController #:nodoc:
alias xhr :xml_http_request
def assigns(key = nil)
if key.nil?
@controller.template.assigns
else
@controller.template.assigns[key.to_s]
assigns = {}
@controller.instance_variable_names.each do |ivar|
next if ActionController::Base.protected_instance_variables.include?(ivar)
assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
end
key.nil? ? assigns : assigns[key.to_s]
end
def session

View File

@@ -50,6 +50,7 @@ module ActionController
@request.session = ActionController::TestSession.new(session) unless session.nil?
@request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
build_request_uri(action, parameters)
@controller.request = @request
@controller.params.merge!(parameters)
# Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest
@controller.process_with_test(@request, @response)

View File

@@ -73,7 +73,7 @@ module HTML
# Specifies the default Set of tags that the #sanitize helper will allow unscathed.
self.allowed_tags = Set.new(%w(strong em b i p code pre tt samp kbd var sub
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dt dd abbr
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dl dt dd abbr
acronym a img blockquote del ins))
# Specifies the default Set of html attributes that the #sanitize helper will leave

View File

@@ -21,16 +21,9 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
begin
require 'active_support'
rescue LoadError
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
if File.directory?(activesupport_path)
$:.unshift activesupport_path
require 'active_support'
end
end
require 'active_support/core/all'
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift activesupport_path if File.directory?(activesupport_path)
require 'active_support'
begin
gem 'rack', '~> 1.1.pre'
@@ -45,7 +38,7 @@ module ActionDispatch
autoload :Response, 'action_dispatch/http/response'
autoload :StatusCodes, 'action_dispatch/http/status_codes'
autoload :Failsafe, 'action_dispatch/middleware/failsafe'
autoload :Callbacks, 'action_dispatch/middleware/callbacks'
autoload :ParamsParser, 'action_dispatch/middleware/params_parser'
autoload :Rescue, 'action_dispatch/middleware/rescue'
autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions'

View File

@@ -1,4 +1,5 @@
require 'set'
require 'active_support/core_ext/class/attribute_accessors'
module Mime
SET = []

View File

@@ -3,6 +3,7 @@ require 'stringio'
require 'strscan'
require 'active_support/memoizable'
require 'active_support/core_ext/hash/indifferent_access'
module ActionDispatch
class Request < Rack::Request

View File

@@ -1,4 +1,5 @@
require 'digest/md5'
require 'active_support/core_ext/module/delegation'
module ActionDispatch # :nodoc:
# Represents an HTTP response generated by a controller action. One can use
@@ -156,12 +157,6 @@ module ActionDispatch # :nodoc:
end
end
def redirect(url, status)
self.status = status
self.location = url.gsub(/[\r\n]/, '')
self.body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>"
end
def sending_file?
headers["Content-Transfer-Encoding"] == "binary"
end

View File

@@ -1,3 +1,5 @@
require 'active_support/inflector'
module ActionDispatch
module StatusCodes #:nodoc:
STATUS_CODES = Rack::Utils::HTTP_STATUS_CODES.merge({
@@ -16,7 +18,7 @@ module ActionDispatch
# :created or :not_implemented) into its corresponding HTTP status
# code (like 200 or 501).
SYMBOL_TO_STATUS_CODE = STATUS_CODES.inject({}) { |hash, (code, message)|
hash[message.gsub(/ /, "").underscore.to_sym] = code
hash[ActiveSupport::Inflector.underscore(message.gsub(/ /, "")).to_sym] = code
hash
}.freeze
@@ -37,4 +39,4 @@ module ActionDispatch
end
end
end
end
end

View File

@@ -0,0 +1,40 @@
module ActionDispatch
class Callbacks
include ActiveSupport::Callbacks
define_callbacks :prepare, :before, :after
class << self
# DEPRECATED
alias_method :prepare_dispatch, :prepare
alias_method :before_dispatch, :before
alias_method :after_dispatch, :after
end
# Add a preparation callback. Preparation callbacks are run before every
# request in development mode, and before the first request in production
# mode.
#
# An optional identifier may be supplied for the callback. If provided,
# to_prepare may be called again with the same identifier to replace the
# existing callback. Passing an identifier is a suggested practice if the
# code adding a preparation block may be reloaded.
def self.to_prepare(identifier = nil, &block)
@prepare_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new
callback = ActiveSupport::Callbacks::Callback.new(:prepare, block, :identifier => identifier)
@prepare_callbacks.replace_or_append!(callback)
end
def initialize(app, prepare_each_request = false)
@app, @prepare_each_request = app, prepare_each_request
run_callbacks :prepare
end
def call(env)
run_callbacks :before
run_callbacks :prepare if @prepare_each_request
@app.call(env)
ensure
run_callbacks :after, :enumerator => :reverse_each
end
end
end

View File

@@ -1,52 +0,0 @@
module ActionDispatch
class Failsafe
cattr_accessor :error_file_path
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
def initialize(app)
@app = app
end
def call(env)
@app.call(env)
rescue Exception => exception
# Reraise exception in test environment
if defined?(Rails) && Rails.env.test?
raise exception
else
failsafe_response(exception)
end
end
private
def failsafe_response(exception)
log_failsafe_exception(exception)
[500, {'Content-Type' => 'text/html'}, failsafe_response_body]
rescue Exception => failsafe_error # Logger or IO errors
$stderr.puts "Error during failsafe response: #{failsafe_error}"
end
def failsafe_response_body
error_path = "#{self.class.error_file_path}/500.html"
if File.exist?(error_path)
[File.read(error_path)]
else
["<html><body><h1>500 Internal Server Error</h1></body></html>"]
end
end
def log_failsafe_exception(exception)
message = "/!\\ FAILSAFE /!\\ #{Time.now}\n Status: 500 Internal Server Error\n"
message << " #{exception}\n #{exception.backtrace.join("\n ")}" if exception
failsafe_logger.fatal(message)
end
def failsafe_logger
if defined?(Rails) && Rails.logger
Rails.logger
else
Logger.new($stderr)
end
end
end
end

View File

@@ -32,16 +32,14 @@ module ActionDispatch
when Proc
strategy.call(request.raw_post)
when :xml_simple, :xml_node
body = request.raw_post
body.blank? ? {} : Hash.from_xml(body).with_indifferent_access
request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
when :yaml
YAML.load(request.raw_post)
YAML.load(request.body)
when :json
body = request.raw_post
if body.blank?
if request.body.size == 0
{}
else
data = ActiveSupport::JSON.decode(body)
data = ActiveSupport::JSON.decode(request.body)
data = {:_json => data} unless data.is_a?(Hash)
data.with_indifferent_access
end

View File

@@ -4,8 +4,11 @@ module ActionDispatch
LOCALHOST = '127.0.0.1'.freeze
DEFAULT_RESCUE_RESPONSE = :internal_server_error
DEFAULT_RESCUE_RESPONSES = {
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
cattr_accessor :rescue_responses
@@rescue_responses = Hash.new(:internal_server_error)
@@rescue_responses.update({
'ActionController::RoutingError' => :not_found,
'ActionController::UnknownAction' => :not_found,
'ActiveRecord::RecordNotFound' => :not_found,
@@ -15,25 +18,19 @@ module ActionDispatch
'ActionController::MethodNotAllowed' => :method_not_allowed,
'ActionController::NotImplemented' => :not_implemented,
'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
}
})
DEFAULT_RESCUE_TEMPLATE = 'diagnostics'
DEFAULT_RESCUE_TEMPLATES = {
cattr_accessor :rescue_templates
@@rescue_templates = Hash.new('diagnostics')
@@rescue_templates.update({
'ActionView::MissingTemplate' => 'missing_template',
'ActionController::RoutingError' => 'routing_error',
'ActionController::UnknownAction' => 'unknown_action',
'ActionView::TemplateError' => 'template_error'
}
})
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
cattr_accessor :rescue_responses
@@rescue_responses = Hash.new(DEFAULT_RESCUE_RESPONSE)
@@rescue_responses.update DEFAULT_RESCUE_RESPONSES
cattr_accessor :rescue_templates
@@rescue_templates = Hash.new(DEFAULT_RESCUE_TEMPLATE)
@@rescue_templates.update DEFAULT_RESCUE_TEMPLATES
FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'},
['<html><body><h1>500 Internal Server Error</h1></body></html>']]
def initialize(app, consider_all_requests_local = false)
@app = app
@@ -43,34 +40,35 @@ module ActionDispatch
def call(env)
@app.call(env)
rescue Exception => exception
raise exception if env['rack.test']
log_error(exception) if logger
request = Request.new(env)
if @consider_all_requests_local || local_request?(request)
rescue_action_locally(request, exception)
else
rescue_action_in_public(exception)
end
raise exception if env['action_dispatch.show_exceptions'] == false
render_exception(env, exception)
end
private
def render_exception(env, exception)
log_error(exception)
request = Request.new(env)
if @consider_all_requests_local || local_request?(request)
rescue_action_locally(request, exception)
else
rescue_action_in_public(exception)
end
rescue Exception => failsafe_error
$stderr.puts "Error during failsafe response: #{failsafe_error}"
FAILSAFE_RESPONSE
end
# Render detailed diagnostics for unhandled exceptions rescued from
# a controller action.
def rescue_action_locally(request, exception)
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
:template => template,
:request => request,
:exception => exception
)
file = "rescues/#{@@rescue_templates[exception.class.name]}.erb"
body = template.render(:file => file, :layout => 'rescues/layout.erb')
headers = {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}
status = status_code(exception)
[status, headers, body]
render(status_code(exception), body)
end
# Attempts to render a static error page based on the
@@ -86,11 +84,11 @@ module ActionDispatch
path = "#{public_path}/#{status}.html"
if locale_path && File.exist?(locale_path)
render_public_file(status, locale_path)
render(status, File.read(locale_path))
elsif File.exist?(path)
render_public_file(status, path)
render(status, File.read(path))
else
[status, {'Content-Type' => 'text/html', 'Content-Length' => '0'}, []]
render(status, '')
end
end
@@ -99,24 +97,21 @@ module ActionDispatch
request.remote_addr == LOCALHOST && request.remote_ip == LOCALHOST
end
def render_public_file(status, path)
body = File.read(path)
[status, {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}, body]
end
def status_code(exception)
interpret_status(@@rescue_responses[exception.class.name]).to_i
end
def public_path
if defined?(Rails)
Rails.public_path
else
"public"
end
def render(status, body)
[status, {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}, body]
end
def log_error(exception) #:doc:
def public_path
defined?(Rails.public_path) ? Rails.public_path : 'public_path'
end
def log_error(exception)
return unless logger
ActiveSupport::Deprecation.silence do
if ActionView::TemplateError === exception
logger.fatal(exception.to_s)
@@ -136,9 +131,7 @@ module ActionDispatch
end
def logger
if defined?(Rails.logger)
Rails.logger
end
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
end
end
end

View File

@@ -21,16 +21,10 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
begin
require 'active_support'
rescue LoadError
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
if File.directory?(activesupport_path)
$:.unshift activesupport_path
require 'active_support'
end
end
require 'active_support/core/all'
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift activesupport_path if File.directory?(activesupport_path)
require 'active_support'
require 'active_support/core_ext/class/attribute_accessors'
require File.join(File.dirname(__FILE__), "action_pack")

View File

@@ -1,3 +1,6 @@
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
module ActionView #:nodoc:
class ActionViewError < StandardError #:nodoc:
end

View File

@@ -2,6 +2,7 @@ require 'cgi'
require 'action_view/helpers/date_helper'
require 'action_view/helpers/tag_helper'
require 'action_view/helpers/form_tag_helper'
require 'active_support/core_ext/class/inheritable_attributes'
module ActionView
module Helpers
@@ -1039,8 +1040,8 @@ module ActionView
end
end
class Base
cattr_accessor :default_form_builder
self.default_form_builder = ::ActionView::Helpers::FormBuilder
class << Base
attr_accessor :default_form_builder
end
end
Base.default_form_builder = ::ActionView::Helpers::FormBuilder
end

View File

@@ -230,6 +230,8 @@ module ActionView
#
# NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
def options_for_select(container, selected = nil)
return container if String === container
container = container.to_a if Hash === container
selected, disabled = extract_selected_and_disabled(selected)

View File

@@ -248,6 +248,11 @@ module ActionView
# number_to_human_size(483989, :precision => 0) # => 473 KB
# number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
#
# Zeros after the decimal point are always stripped out, regardless of the
# specified precision:
# helper.number_to_human_size(1234567890123, :precision => 5) # => "1.12283 TB"
# helper.number_to_human_size(524288000, :precision=>5) # => "500 MB"
#
# You can still use <tt>number_to_human_size</tt> with the old API that accepts the
# +precision+ as its optional second parameter:
# number_to_human_size(1234567, 2) # => 1.18 MB
@@ -293,7 +298,7 @@ module ActionView
:precision => precision,
:separator => separator,
:delimiter => delimiter
).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
rescue
number

View File

@@ -9,7 +9,7 @@ module ActionView
include ERB::Util
BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked).to_set
BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym))
BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map {|attr| attr.to_sym })
# Returns an empty HTML tag of type +name+ which by default is XHTML
# compliant. Set +open+ to true to create an open tag compatible

View File

@@ -535,7 +535,7 @@ module ActionView
link_attributes = html_options.stringify_keys
text.gsub(AUTO_LINK_RE) do
href = $&
punctuation = ''
punctuation = []
left, right = $`, $'
# detect already linked URLs and URLs in the middle of a tag
if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
@@ -543,17 +543,18 @@ module ActionView
href
else
# don't include trailing punctuation character as part of the URL
if href.sub!(/[^\w\/-]$/, '') and punctuation = $& and opening = BRACKETS[punctuation]
if href.scan(opening).size > href.scan(punctuation).size
href << punctuation
punctuation = ''
while href.sub!(/[^\w\/-]$/, '')
punctuation.push $&
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
href << punctuation.pop
break
end
end
link_text = block_given?? yield(href) : href
href = 'http://' + href unless href.index('http') == 0
content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation
content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation.reverse.join('')
end
end
end

View File

@@ -171,11 +171,21 @@ module ActionView
# <% end %>
module Partials
extend ActiveSupport::Memoizable
extend ActiveSupport::DependencyModule
included do
attr_accessor :_partial
end
def _render_partial_from_controller(*args)
@assigns_added = false
_render_partial(*args)
end
def _render_partial(options = {}) #:nodoc:
options[:locals] ||= {}
case path = partial = options[:partial]
case path = partial = options[:partial]
when *_array_like_objects
return _render_partial_collection(partial, options)
else
@@ -222,16 +232,7 @@ module ActionView
ensure
@_proc_for_layout = nil
end
def _render_partial_with_layout(layout, options)
if layout
prefix = controller && !layout.include?("/") ? controller.controller_path : nil
layout = find_by_parts(layout, {:formats => formats}, prefix, true)
end
content = _render_partial(options)
return _render_content_with_layout(content, layout, options[:locals])
end
def _deprecated_ivar_assign(template)
if respond_to?(:controller)
ivar = :"@#{template.variable_name}"
@@ -287,13 +288,17 @@ module ActionView
locals = (options[:locals] ||= {})
object ||= locals[:object] || locals[template.variable_name]
_set_locals(object, locals, template, options)
_set_locals(object, locals, template, options)
self._partial = template
_render_template(template, locals)
end
end
def _set_locals(object, locals, template, options)
object ||= _deprecated_ivar_assign(template)
locals[:object] = locals[template.variable_name] = object
locals[options[:as]] = object if options[:as]
end
@@ -316,6 +321,9 @@ module ActionView
locals[template.counter_name] = index
index += 1
self._partial = template
_render_template(template, locals)
end.join(spacer)
end

View File

@@ -95,6 +95,11 @@ module ActionView
layout ? _render_content_with_layout(text, layout, options[:locals]) : text
end
def _render_template_from_controller(*args)
@assigns_added = nil
_render_template_with_layout(*args)
end
def _render_template_with_layout(template, layout = nil, options = {}, partial = false)
if controller && logger
logger.info("Rendering #{template.identifier}" +

View File

@@ -33,7 +33,7 @@ module ActionView #:nodoc:
end
def template_handler_extensions
@@template_handlers.keys.map(&:to_s).sort
@@template_handlers.keys.map {|key| key.to_s }.sort
end
def registered_template_handler(extension)

View File

@@ -1,4 +1,5 @@
require 'erb'
require 'active_support/core_ext/class/attribute_accessors'
module ActionView
module TemplateHandlers

View File

@@ -201,11 +201,10 @@ module AbstractController
def fail() self.response_body = "fail" end
private
def respond_to_action?(action_name)
action_name.to_s != "fail"
def method_for_action(action_name)
action_name.to_s != "fail" && action_name
end
end
class TestRespondToAction < ActiveSupport::TestCase

View File

@@ -193,5 +193,24 @@ module AbstractController
end
end
class SetsResponseBody < ControllerWithCallbacks
before_filter :set_body
def index
self.response_body = "Fail"
end
def set_body
self.response_body = "Success"
end
end
class TestHalting < ActiveSupport::TestCase
test "when a callback sets the response body, the action should not be invoked" do
result = SetsResponseBody.process(:index)
assert_equal "Success", result.response_body
end
end
end
end

View File

@@ -4,7 +4,7 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
require 'rubygems'
require 'test/unit'
require 'active_support/core/all'
require 'active_support'
require 'active_support/test_case'
require 'action_controller/abstract'
require 'action_view'
@@ -18,4 +18,4 @@ begin
Debugger.start
rescue LoadError
# Debugging disabled. `gem install ruby-debug` to enable.
end
end

View File

@@ -1,3 +1,6 @@
if ENV["new_base"]
require "abstract_unit2"
else
$:.unshift(File.dirname(__FILE__) + '/../lib')
$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib')
$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers')
@@ -34,7 +37,8 @@ ActionController::Base.session_store = nil
# Register danish language for testing
I18n.backend.store_translations 'da', {}
I18n.backend.store_translations 'pt-BR', {}
ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort
ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
ActionController::Base.view_paths = FIXTURE_LOAD_PATH
end

View File

@@ -5,18 +5,25 @@ $:.unshift(File.dirname(__FILE__) + '/lib')
require 'test/unit'
require 'active_support'
require 'active_support/core/all'
require 'active_support/test_case'
require 'action_controller/abstract'
require 'action_controller/new_base'
require 'fixture_template'
require 'action_controller/testing/process2'
require 'action_view/test_case'
require 'action_controller/testing/integration'
require 'active_support/dependencies'
ActiveSupport::Dependencies.hook!
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
module ActionController
Base.session = {
:key => '_testing_session',
:secret => '8273f16463985e2b3747dc25e30f2528'
}
class ActionControllerError < StandardError #:nodoc:
end
@@ -75,7 +82,7 @@ module ActionController
end
class Base
use ActionController::Testing
include ActionController::Testing
end
Base.view_paths = FIXTURE_LOAD_PATH
@@ -89,45 +96,44 @@ module ActionController
end
def assert_template(options = {}, message = nil)
validate_response!
validate_request!
clean_backtrace do
case options
when NilClass, String
hax = @controller._action_view.instance_variable_get(:@_rendered)
rendered = (hax[:template] || []).map { |t| t.identifier }
msg = build_message(message,
"expecting <?> but rendering with <?>",
options, rendered.join(', '))
assert_block(msg) do
if options.nil?
hax[:template].blank?
else
rendered.any? { |t| t.match(options) }
end
end
when Hash
if expected_partial = options[:partial]
partials = hax[:partials]
if expected_count = options[:count]
found = partials.detect { |p, _| p.identifier.match(expected_partial) }
actual_count = found.nil? ? 0 : found.second
msg = build_message(message,
"expecting ? to be rendered ? time(s) but rendered ? time(s)",
expected_partial, expected_count, actual_count)
assert(actual_count == expected_count.to_i, msg)
else
msg = build_message(message,
"expecting partial <?> but action rendered <?>",
options[:partial], partials.keys)
assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg)
end
hax = @controller._action_view.instance_variable_get(:@_rendered)
case options
when NilClass, String
rendered = (hax[:template] || []).map { |t| t.identifier }
msg = build_message(message,
"expecting <?> but rendering with <?>",
options, rendered.join(', '))
assert_block(msg) do
if options.nil?
hax[:template].blank?
else
assert hax[:partials].empty?,
"Expected no partials to be rendered"
rendered.any? { |t| t.match(options) }
end
end
when Hash
if expected_partial = options[:partial]
partials = hax[:partials]
if expected_count = options[:count]
found = partials.detect { |p, _| p.identifier.match(expected_partial) }
actual_count = found.nil? ? 0 : found.second
msg = build_message(message,
"expecting ? to be rendered ? time(s) but rendered ? time(s)",
expected_partial, expected_count, actual_count)
assert(actual_count == expected_count.to_i, msg)
else
msg = build_message(message,
"expecting partial <?> but action rendered <?>",
options[:partial], partials.keys)
assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg)
end
else
assert hax[:partials].empty?,
"Expected no partials to be rendered"
end
end
end
end
end
end
end

View File

@@ -28,9 +28,9 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
end
def call_reset_session
session[:bar]
session[:foo]
reset_session
session[:bar] = "baz"
session[:foo] = "baz"
head :ok
end
@@ -91,7 +91,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
get '/get_session_value'
assert_response :success
assert_equal 'foo: nil', response.body
assert_equal 'foo: "baz"', response.body
get '/get_session_id'
assert_response :success

View File

@@ -1,4 +1,5 @@
require 'active_record_unit'
require 'fixtures/project'
class Task < ActiveRecord::Base
set_table_name 'projects'

View File

@@ -12,6 +12,9 @@ class ActionPackAssertionsController < ActionController::Base
# a standard template
def hello_xml_world() render :template => "test/hello_xml_world"; end
# a standard partial
def partial() render :partial => 'test/partial'; end
# a redirect to an internal location
def redirect_internal() redirect_to "/nothing"; end
@@ -331,6 +334,26 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
end
end
def test_assert_template_with_partial
get :partial
assert_template :partial => '_partial'
end
def test_assert_template_with_nil
get :nothing
assert_template nil
end
def test_assert_template_with_string
get :hello_world
assert_template 'hello_world'
end
def test_assert_template_with_symbol
get :hello_world
assert_template :hello_world
end
# check if we were rendered by a file-based template?
def test_rendered_action
process :nothing

View File

@@ -1,4 +1,5 @@
require 'abstract_unit'
require 'logger'
class Address
def Address.count(conditions = nil, join = nil)

View File

@@ -1,4 +1,5 @@
require 'abstract_unit'
require 'logger'
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
# Provide some controller to run the tests on.
@@ -116,7 +117,7 @@ class PerformActionTest < ActionController::TestCase
end
def method_missing(method, *args)
@logged << args.first
@logged << args.first.to_s
end
end

View File

@@ -1,4 +1,5 @@
require 'abstract_unit'
require 'logger'
class CaptureController < ActionController::Base
def self.controller_name; "test"; end

View File

@@ -6,20 +6,20 @@ class DispatcherTest < Test::Unit::TestCase
def setup
ENV['REQUEST_METHOD'] = 'GET'
Dispatcher.middleware = ActionDispatch::MiddlewareStack.new do |middleware|
middlewares = File.expand_path(File.join(File.dirname(__FILE__), "../../lib/action_controller/dispatch/middlewares.rb"))
middleware.instance_eval(File.read(middlewares))
end
# Clear callbacks as they are redefined by Dispatcher#define_dispatcher_callbacks
Dispatcher.instance_variable_set("@prepare_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
Dispatcher.instance_variable_set("@before_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
Dispatcher.instance_variable_set("@after_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
ActionDispatch::Callbacks.instance_variable_set("@prepare_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
ActionDispatch::Callbacks.instance_variable_set("@before_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
ActionDispatch::Callbacks.instance_variable_set("@after_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
@old_router, Dispatcher.router = Dispatcher.router, mock()
Dispatcher.router.stubs(:call).returns([200, {}, 'response'])
Dispatcher.router.stubs(:reload)
Dispatcher.stubs(:require_dependency)
end
def teardown
Dispatcher.router = @old_router
@dispatcher = nil
ENV.delete 'REQUEST_METHOD'
end
@@ -29,12 +29,12 @@ class DispatcherTest < Test::Unit::TestCase
end
def test_reloads_routes_before_dispatch_if_in_loading_mode
ActionController::Routing::Routes.expects(:reload).once
Dispatcher.router.expects(:reload).once
dispatch(false)
end
def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode
ActionController::Routing::Routes.expects(:reload).never
Dispatcher.router.expects(:reload).never
ActiveSupport::Dependencies.expects(:clear).never
dispatch
@@ -55,7 +55,7 @@ class DispatcherTest < Test::Unit::TestCase
assert_nil a || b || c
# Run callbacks
Dispatcher.run_prepare_callbacks
dispatch
assert_equal 1, a
assert_equal 2, b
@@ -72,16 +72,22 @@ class DispatcherTest < Test::Unit::TestCase
Dispatcher.to_prepare(:unique_id) { |*args| a = b = 1 }
Dispatcher.to_prepare(:unique_id) { |*args| a = 2 }
Dispatcher.run_prepare_callbacks
dispatch
assert_equal 2, a
assert_equal nil, b
end
private
def dispatch(cache_classes = true)
ActionController::Routing::RouteSet.any_instance.stubs(:call).returns([200, {}, 'response'])
ActionController::Dispatcher.prepare_each_request = false
Dispatcher.define_dispatcher_callbacks(cache_classes)
Dispatcher.new.call({'rack.input' => StringIO.new('')})
Dispatcher.middleware = ActionDispatch::MiddlewareStack.new do |middleware|
middlewares = File.expand_path(File.join(File.dirname(__FILE__), "../../lib/action_controller/dispatch/middlewares.rb"))
middleware.instance_eval(File.read(middlewares))
end
@dispatcher ||= Dispatcher.new
@dispatcher.call({'rack.input' => StringIO.new(''), 'action_dispatch.show_exceptions' => false})
end
def assert_subclasses(howmany, klass, message = klass.subclasses.inspect)

View File

@@ -607,7 +607,6 @@ class FilterTest < Test::Unit::TestCase
def test_dynamic_dispatch
%w(foo bar baz).each do |action|
request = ActionController::TestRequest.new
request.env["action_controller.rescue.request"] = request
request.query_parameters[:choose] = action
response = DynamicDispatchController.action.call(request.env).last
assert_equal action, response.body

View File

@@ -1,4 +1,5 @@
require 'abstract_unit'
require 'active_support/core_ext/kernel/reporting'
ActionController::Base.helpers_dir = File.dirname(__FILE__) + '/../fixtures/helpers'
@@ -103,7 +104,6 @@ class HelperTest < Test::Unit::TestCase
def call_controller(klass, action)
request = ActionController::TestRequest.new
request.env["action_controller.rescue.request"] = request
klass.action(action).call(request.env)
end
@@ -111,7 +111,6 @@ class HelperTest < Test::Unit::TestCase
assert_equal 'hello: Iz guuut!',
call_controller(Fun::GamesController, "render_hello_world").last.body
# request = ActionController::TestRequest.new
# request.env["action_controller.rescue.request"] = request
#
# resp = Fun::GamesController.action(:render_hello_world).call(request.env)
# assert_equal 'hello: Iz guuut!', resp.last.body
@@ -216,7 +215,6 @@ class IsolatedHelpersTest < Test::Unit::TestCase
def call_controller(klass, action)
request = ActionController::TestRequest.new
request.env["action_controller.rescue.request"] = request
klass.action(action).call(request.env)
end

View File

@@ -0,0 +1,37 @@
require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
class TestController < ActionController::Base
protect_from_forgery
def render_vanilla_js_hello
render :js => "alert('hello')"
end
def greeting
# let's just rely on the template
end
def partial
render :partial => 'partial'
end
end
class RenderTest < ActionController::TestCase
def test_render_vanilla_js
get :render_vanilla_js_hello
assert_equal "alert('hello')", @response.body
assert_equal "text/javascript", @response.content_type
end
def test_render_with_default_from_accept_header
xhr :get, :greeting
assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body
end
def test_should_render_js_partial
xhr :get, :partial, :format => 'js'
assert_equal 'partial js', @response.body
end
end

View File

@@ -0,0 +1,80 @@
require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
class TestController < ActionController::Base
protect_from_forgery
def render_json_nil
render :json => nil
end
def render_json_hello_world
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
def render_json_hello_world_with_callback
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert'
end
def render_json_with_custom_content_type
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript'
end
def render_symbol_json
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
def render_json_with_render_to_string
render :json => {:hello => render_to_string(:partial => 'partial')}
end
end
class RenderTest < ActionController::TestCase
tests TestController
def setup
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
# a more accurate simulation of what happens in "real life".
super
@controller.logger = Logger.new(nil)
@request.host = "www.nextangle.com"
end
def test_render_json_nil
get :render_json_nil
assert_equal 'null', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json
get :render_json_hello_world
assert_equal '{"hello":"world"}', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json_with_callback
get :render_json_hello_world_with_callback
assert_equal 'alert({"hello":"world"})', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json_with_custom_content_type
get :render_json_with_custom_content_type
assert_equal '{"hello":"world"}', @response.body
assert_equal 'text/javascript', @response.content_type
end
def test_render_symbol_json
get :render_symbol_json
assert_equal '{"hello":"world"}', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json_with_render_to_string
get :render_json_with_render_to_string
assert_equal '{"hello":"partial html"}', @response.body
assert_equal 'application/json', @response.content_type
end
end

View File

@@ -0,0 +1,222 @@
require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
class TestController < ActionController::Base
protect_from_forgery
module RenderTestHelper
def rjs_helper_method_from_module
page.visual_effect :highlight
end
end
helper RenderTestHelper
helper do
def rjs_helper_method(value)
page.visual_effect :highlight, value
end
end
def enum_rjs_test
render :update do |page|
page.select('.product').each do |value|
page.rjs_helper_method_from_module
page.rjs_helper_method(value)
page.sortable(value, :url => { :action => "order" })
page.draggable(value)
end
end
end
def render_explicit_html_template
end
def render_custom_code_rjs
render :update, :status => 404 do |page|
page.replace :foo, :partial => 'partial'
end
end
def render_implicit_html_template
end
def render_js_with_explicit_template
@project_id = 4
render :template => 'test/delete_with_js'
end
def render_js_with_explicit_action_template
@project_id = 4
render :action => 'delete_with_js'
end
def delete_with_js
@project_id = 4
end
def update_page
render :update do |page|
page.replace_html 'balance', '$37,000,000.00'
page.visual_effect :highlight, 'balance'
end
end
def update_page_with_instance_variables
@money = '$37,000,000.00'
@div_id = 'balance'
render :update do |page|
page.replace_html @div_id, @money
page.visual_effect :highlight, @div_id
end
end
def update_page_with_view_method
render :update do |page|
page.replace_html 'person', pluralize(2, 'person')
end
end
def partial_as_rjs
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
def respond_to_partial_as_rjs
respond_to do |format|
format.js do
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
end
end
def render_alternate_default
# For this test, the method "default_render" is overridden:
@alternate_default_render = lambda do
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
end
private
def determine_layout
case action_name
when "render_js_with_explicit_template",
"render_js_with_explicit_action_template",
"delete_with_js", "update_page", "update_page_with_instance_variables"
"layouts/standard"
when "action_talk_to_layout", "layout_overriding_layout"
"layouts/talk_from_action"
when "render_implicit_html_template_from_xhr_request"
(request.xhr? ? 'layouts/xhr' : 'layouts/standard')
end
end
end
class RenderTest < ActionController::TestCase
tests TestController
def setup
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
# a more accurate simulation of what happens in "real life".
super
@controller.logger = Logger.new(nil)
@request.host = "www.nextangle.com"
end
def test_enum_rjs_test
ActiveSupport::SecureRandom.stubs(:base64).returns("asdf")
get :enum_rjs_test
body = %{
$$(".product").each(function(value, index) {
new Effect.Highlight(element,{});
new Effect.Highlight(value,{});
Sortable.create(value, {onUpdate:function(){new Ajax.Request('/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value) + '&authenticity_token=' + encodeURIComponent('asdf')})}});
new Draggable(value, {});
});
}.gsub(/^ /, '').strip
assert_equal body, @response.body
end
def test_explicitly_rendering_an_html_template_with_implicit_html_template_renders_should_be_possible_from_an_rjs_template
[:js, "js"].each do |format|
assert_nothing_raised do
get :render_explicit_html_template, :format => format
assert_equal %(document.write("Hello world\\n");), @response.body
end
end
end
def test_render_custom_code_rjs
get :render_custom_code_rjs
assert_response 404
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_render_in_an_rjs_template_should_pick_html_templates_when_available
[:js, "js"].each do |format|
assert_nothing_raised do
get :render_implicit_html_template, :format => format
assert_equal %(document.write("Hello world\\n");), @response.body
end
end
end
def test_render_rjs_template_explicitly
get :render_js_with_explicit_template
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_rendering_rjs_action_explicitly
get :render_js_with_explicit_action_template
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_render_rjs_with_default
get :delete_with_js
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_update_page
get :update_page
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers['Content-Type']
assert_equal 2, @response.body.split($/).length
end
def test_update_page_with_instance_variables
get :update_page_with_instance_variables
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"]
assert_match /balance/, @response.body
assert_match /\$37/, @response.body
end
def test_update_page_with_view_method
get :update_page_with_view_method
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"]
assert_match /2 people/, @response.body
end
def test_should_render_html_formatted_partial_with_rjs
xhr :get, :partial_as_rjs
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_should_render_html_formatted_partial_with_rjs_and_js_format
xhr :get, :respond_to_partial_as_rjs
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_should_render_with_alternate_default_render
xhr :get, :render_alternate_default
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
end

View File

@@ -1,4 +1,4 @@
require ENV['new_base'] ? 'abstract_unit2' : 'abstract_unit'
require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
@@ -145,18 +145,21 @@ class TestController < ActionController::Base
render :layout => false
end
# :ported:
def render_file_with_instance_variables
@secret = 'in the sauce'
path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
render :file => path
end
# :ported:
def render_file_as_string_with_instance_variables
@secret = 'in the sauce'
path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb'))
render path
end
# :ported:
def render_file_not_using_full_path
@secret = 'in the sauce'
render :file => 'test/render_file_with_ivar'
@@ -203,41 +206,11 @@ class TestController < ActionController::Base
render :inline => "<%= controller_name %>"
end
def render_json_nil
render :json => nil
end
def render_json_hello_world
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
def render_json_hello_world_with_callback
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert'
end
def render_json_with_custom_content_type
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript'
end
def render_symbol_json
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
def render_json_with_render_to_string
render :json => {:hello => render_to_string(:partial => 'partial')}
end
# :ported:
def render_custom_code
render :text => "hello world", :status => 404
end
def render_custom_code_rjs
render :update, :status => 404 do |page|
page.replace :foo, :partial => 'partial'
end
end
# :ported:
def render_text_with_nil
render :text => nil
@@ -253,10 +226,6 @@ class TestController < ActionController::Base
render :text => "appended"
end
def render_vanilla_js_hello
render :js => "alert('hello')"
end
# This test is testing 3 things:
# render :file in AV :ported:
# render :template in AC :ported:
@@ -271,10 +240,6 @@ class TestController < ActionController::Base
render "test/hello"
end
def render_xml_with_custom_content_type
render :xml => "<blah/>", :content_type => "application/atomsvc+xml"
end
def render_line_offset
render :inline => '<% raise %>', :locals => {:foo => 'bar'}
end
@@ -297,6 +262,7 @@ class TestController < ActionController::Base
render :action => "hello_world"
end
# :ported:
def builder_layout_test
render :action => "hello", :layout => "layouts/builder"
end
@@ -306,6 +272,7 @@ class TestController < ActionController::Base
render :action => "hello_world_container"
end
# :ported:
def partials_list
@test_unchanged = 'hello'
@customers = [ Customer.new("david"), Customer.new("mary") ]
@@ -331,12 +298,6 @@ class TestController < ActionController::Base
:locals => { :local_name => name }
end
def render_implicit_html_template
end
def render_explicit_html_template
end
def render_implicit_html_template_from_xhr_request
end
@@ -470,66 +431,6 @@ class TestController < ActionController::Base
render :template => "test/hello_world_from_rxml.builder"
end
module RenderTestHelper
def rjs_helper_method_from_module
page.visual_effect :highlight
end
end
helper RenderTestHelper
helper do
def rjs_helper_method(value)
page.visual_effect :highlight, value
end
end
def enum_rjs_test
render :update do |page|
page.select('.product').each do |value|
page.rjs_helper_method_from_module
page.rjs_helper_method(value)
page.sortable(value, :url => { :action => "order" })
page.draggable(value)
end
end
end
def delete_with_js
@project_id = 4
end
def render_js_with_explicit_template
@project_id = 4
render :template => 'test/delete_with_js'
end
def render_js_with_explicit_action_template
@project_id = 4
render :action => 'delete_with_js'
end
def update_page
render :update do |page|
page.replace_html 'balance', '$37,000,000.00'
page.visual_effect :highlight, 'balance'
end
end
def update_page_with_instance_variables
@money = '$37,000,000.00'
@div_id = 'balance'
render :update do |page|
page.replace_html @div_id, @money
page.visual_effect :highlight, @div_id
end
end
def update_page_with_view_method
render :update do |page|
page.replace_html 'person', pluralize(2, 'person')
end
end
def action_talk_to_layout
# Action template sets variable that's picked up by layout
end
@@ -573,25 +474,6 @@ class TestController < ActionController::Base
head :forbidden, :x_custom_header => "something"
end
def render_with_location
render :xml => "<hello/>", :location => "http://example.com", :status => 201
end
def render_with_object_location
customer = Customer.new("Some guy", 1)
render :xml => "<customer/>", :location => customer_url(customer), :status => :created
end
def render_with_to_xml
to_xmlable = Class.new do
def to_xml
"<i-am-xml/>"
end
end.new
render :xml => to_xmlable
end
def render_using_layout_around_block
render :action => "using_layout_around_block"
end
@@ -608,22 +490,6 @@ class TestController < ActionController::Base
render :partial => 'partial.html.erb'
end
def partial_as_rjs
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
def respond_to_partial_as_rjs
respond_to do |format|
format.js do
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
end
end
def partial
render :partial => 'partial'
end
@@ -880,82 +746,54 @@ class RenderTest < ActionController::TestCase
assert_equal 'Hello world!', @response.body
end
# :ported:
def test_render_file_with_instance_variables
get :render_file_with_instance_variables
assert_equal "The secret is in the sauce\n", @response.body
end
# :ported:
def test_render_file_as_string_with_instance_variables
get :render_file_as_string_with_instance_variables
assert_equal "The secret is in the sauce\n", @response.body
end
# :ported:
def test_render_file_not_using_full_path
get :render_file_not_using_full_path
assert_equal "The secret is in the sauce\n", @response.body
end
# :ported:
def test_render_file_not_using_full_path_with_dot_in_path
get :render_file_not_using_full_path_with_dot_in_path
assert_equal "The secret is in the sauce\n", @response.body
end
# :ported:
def test_render_file_using_pathname
get :render_file_using_pathname
assert_equal "The secret is in the sauce\n", @response.body
end
# :ported:
def test_render_file_with_locals
get :render_file_with_locals
assert_equal "The secret is in the sauce\n", @response.body
end
# :ported:
def test_render_file_as_string_with_locals
get :render_file_as_string_with_locals
assert_equal "The secret is in the sauce\n", @response.body
end
# :assessed:
def test_render_file_from_template
get :render_file_from_template
assert_equal "The secret is in the sauce\n", @response.body
end
def test_render_json_nil
get :render_json_nil
assert_equal 'null', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json
get :render_json_hello_world
assert_equal '{"hello":"world"}', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json_with_callback
get :render_json_hello_world_with_callback
assert_equal 'alert({"hello":"world"})', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json_with_custom_content_type
get :render_json_with_custom_content_type
assert_equal '{"hello":"world"}', @response.body
assert_equal 'text/javascript', @response.content_type
end
def test_render_symbol_json
get :render_symbol_json
assert_equal '{"hello":"world"}', @response.body
assert_equal 'application/json', @response.content_type
end
def test_render_json_with_render_to_string
get :render_json_with_render_to_string
assert_equal '{"hello":"partial html"}', @response.body
assert_equal 'application/json', @response.content_type
end
# :ported:
def test_render_custom_code
get :render_custom_code
@@ -964,12 +802,6 @@ class RenderTest < ActionController::TestCase
assert_equal 'hello world', @response.body
end
def test_render_custom_code_rjs
get :render_custom_code_rjs
assert_response 404
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
# :ported:
def test_render_text_with_nil
get :render_text_with_nil
@@ -1023,12 +855,6 @@ class RenderTest < ActionController::TestCase
assert_equal "test", @response.body # name is explicitly set to 'test' inside the controller.
end
def test_render_vanilla_js
get :render_vanilla_js_hello
assert_equal "alert('hello')", @response.body
assert_equal "text/javascript", @response.content_type
end
# :ported:
def test_render_xml
get :render_xml_hello
@@ -1036,6 +862,7 @@ class RenderTest < ActionController::TestCase
assert_equal "application/xml", @response.content_type
end
# :ported:
def test_render_xml_as_string_template
get :render_xml_hello_as_string_template
assert_equal "<html>\n <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body
@@ -1048,25 +875,13 @@ class RenderTest < ActionController::TestCase
assert_equal "<p>This is grand!</p>\n", @response.body
end
# :move: test in AV
def test_render_xml_with_partial
get :builder_partial_test
assert_equal "<test>\n <hello/>\n</test>\n", @response.body
end
def test_enum_rjs_test
ActiveSupport::SecureRandom.stubs(:base64).returns("asdf")
get :enum_rjs_test
body = %{
$$(".product").each(function(value, index) {
new Effect.Highlight(element,{});
new Effect.Highlight(value,{});
Sortable.create(value, {onUpdate:function(){new Ajax.Request('/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value) + '&authenticity_token=' + encodeURIComponent('asdf')})}});
new Draggable(value, {});
});
}.gsub(/^ /, '').strip
assert_equal body, @response.body
end
# :ported:
def test_layout_rendering
get :layout_test
assert_equal "<html>Hello world!</html>", @response.body
@@ -1114,29 +929,10 @@ class RenderTest < ActionController::TestCase
assert_equal "Goodbye, Local David", @response.body
end
def test_render_in_an_rjs_template_should_pick_html_templates_when_available
[:js, "js"].each do |format|
assert_nothing_raised do
get :render_implicit_html_template, :format => format
assert_equal %(document.write("Hello world\\n");), @response.body
end
end
end
def test_explicitly_rendering_an_html_template_with_implicit_html_template_renders_should_be_possible_from_an_rjs_template
[:js, "js"].each do |format|
assert_nothing_raised do
get :render_explicit_html_template, :format => format
assert_equal %(document.write("Hello world\\n");), @response.body
end
end
end
def test_should_implicitly_render_html_template_from_xhr_request
pending do
xhr :get, :render_implicit_html_template_from_xhr_request
assert_equal "XHR!\nHello HTML!", @response.body
end
pending
# xhr :get, :render_implicit_html_template_from_xhr_request
# assert_equal "XHR!\nHello HTML!", @response.body
end
def test_should_implicitly_render_js_template_without_layout
@@ -1151,11 +947,6 @@ class RenderTest < ActionController::TestCase
assert_equal 'formatted html erb', @response.body
end
def test_should_render_formatted_xml_erb_template
get :formatted_xml_erb, :format => :xml
assert_equal '<test>passed formatted xml erb</test>', @response.body
end
def test_should_render_formatted_html_erb_template
get :formatted_xml_erb
assert_equal '<test>passed formatted html erb</test>', @response.body
@@ -1167,31 +958,6 @@ class RenderTest < ActionController::TestCase
assert_equal '<test>passed formatted html erb</test>', @response.body
end
def test_should_render_xml_but_keep_custom_content_type
get :render_xml_with_custom_content_type
assert_equal "application/atomsvc+xml", @response.content_type
end
def test_render_with_default_from_accept_header
xhr :get, :greeting
assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body
end
def test_render_rjs_with_default
get :delete_with_js
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_render_rjs_template_explicitly
get :render_js_with_explicit_template
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_rendering_rjs_action_explicitly
get :render_js_with_explicit_action_template
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_layout_test_with_different_layout
get :layout_test_with_different_layout
assert_equal "<html>Hello world!</html>", @response.body
@@ -1299,28 +1065,6 @@ class RenderTest < ActionController::TestCase
assert_equal "The secret is area51\n", @response.body
end
def test_update_page
get :update_page
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers['Content-Type']
assert_equal 2, @response.body.split($/).length
end
def test_update_page_with_instance_variables
get :update_page_with_instance_variables
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"]
assert_match /balance/, @response.body
assert_match /\$37/, @response.body
end
def test_update_page_with_view_method
get :update_page_with_view_method
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"]
assert_match /2 people/, @response.body
end
def test_yield_content_for
assert_not_deprecated { get :yield_content_for }
assert_equal "<title>Putting stuff in the title!</title>\n\nGreat stuff!\n", @response.body
@@ -1391,31 +1135,6 @@ class RenderTest < ActionController::TestCase
assert_response :forbidden
end
def test_rendering_with_location_should_set_header
get :render_with_location
assert_equal "http://example.com", @response.headers["Location"]
end
def test_rendering_xml_should_call_to_xml_if_possible
get :render_with_to_xml
assert_equal "<i-am-xml/>", @response.body
end
def test_rendering_with_object_location_should_set_header_with_url_for
ActionController::Routing::Routes.draw do |map|
map.resources :customers
map.connect ':controller/:action/:id'
end
get :render_with_object_location
assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"]
end
def test_should_use_implicit_content_type
get :implicit_content_type, :format => 'atom'
assert_equal Mime::ATOM, @response.content_type
end
def test_using_layout_around_block
get :render_using_layout_around_block
assert_equal "Before (David)\nInside from block\nAfter", @response.body
@@ -1446,26 +1165,6 @@ class RenderTest < ActionController::TestCase
assert_equal 'partial html', @response.body
end
def test_should_render_html_formatted_partial_with_rjs
xhr :get, :partial_as_rjs
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_should_render_html_formatted_partial_with_rjs_and_js_format
xhr :get, :respond_to_partial_as_rjs
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_should_render_js_partial
xhr :get, :partial, :format => 'js'
assert_equal 'partial js', @response.body
end
def test_should_render_with_alternate_default_render
xhr :get, :render_alternate_default
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_partial_only_with_layout
get :partial_only_with_layout
assert_equal "<html>only partial</html>", @response.body
@@ -1647,7 +1346,7 @@ class EtagRenderTest < ActionController::TestCase
def test_render_against_etag_request_should_304_when_match
@request.if_none_match = etag_for("hello david")
get :render_hello_world_from_variable
assert_equal 304, @response.status
assert_equal 304, @response.status.to_i
assert @response.body.empty?
end

View File

@@ -0,0 +1,81 @@
require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
class TestController < ActionController::Base
protect_from_forgery
def render_with_location
render :xml => "<hello/>", :location => "http://example.com", :status => 201
end
def render_with_object_location
customer = Customer.new("Some guy", 1)
render :xml => "<customer/>", :location => customer_url(customer), :status => :created
end
def render_with_to_xml
to_xmlable = Class.new do
def to_xml
"<i-am-xml/>"
end
end.new
render :xml => to_xmlable
end
def formatted_xml_erb
end
def render_xml_with_custom_content_type
render :xml => "<blah/>", :content_type => "application/atomsvc+xml"
end
end
class RenderTest < ActionController::TestCase
tests TestController
def setup
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
# a more accurate simulation of what happens in "real life".
super
@controller.logger = Logger.new(nil)
@request.host = "www.nextangle.com"
end
def test_rendering_with_location_should_set_header
get :render_with_location
assert_equal "http://example.com", @response.headers["Location"]
end
def test_rendering_xml_should_call_to_xml_if_possible
get :render_with_to_xml
assert_equal "<i-am-xml/>", @response.body
end
def test_rendering_with_object_location_should_set_header_with_url_for
ActionController::Routing::Routes.draw do |map|
map.resources :customers
map.connect ':controller/:action/:id'
end
get :render_with_object_location
assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"]
end
def test_should_render_formatted_xml_erb_template
get :formatted_xml_erb, :format => :xml
assert_equal '<test>passed formatted xml erb</test>', @response.body
end
def test_should_render_xml_but_keep_custom_content_type
get :render_xml_with_custom_content_type
assert_equal "application/atomsvc+xml", @response.content_type
end
def test_should_use_implicit_content_type
get :implicit_content_type, :format => 'atom'
assert_equal Mime::ATOM, @response.content_type
end
end

View File

@@ -1,5 +1,19 @@
require 'abstract_unit'
module ActionDispatch
class ShowExceptions
private
def public_path
"#{FIXTURE_LOAD_PATH}/public"
end
# Silence logger
def logger
nil
end
end
end
class RescueController < ActionController::Base
class NotAuthorized < StandardError
end

View File

@@ -6,6 +6,11 @@ module ActionDispatch
def public_path
"#{FIXTURE_LOAD_PATH}/public"
end
# Silence logger
def logger
nil
end
end
end

View File

@@ -0,0 +1 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")

View File

@@ -92,7 +92,7 @@ module RenderAction
test "raises an exception when requesting a layout and none exist" do
assert_raise(ArgumentError, /no default layout for RenderAction::BasicController in/) do
get "/render_action/basic/hello_world_with_layout"
get "/render_action/basic/hello_world_with_layout", {}, "action_dispatch.show_exceptions" => false
end
end
end
@@ -117,7 +117,9 @@ module RenderAction
describe "rendering a normal template with full path with layout => 'greetings'"
test "raises an exception when requesting a layout that does not exist" do
assert_raise(ActionView::MissingTemplate) { get "/render_action/basic/hello_world_with_custom_layout" }
assert_raise(ActionView::MissingTemplate) do
get "/render_action/basic/hello_world_with_custom_layout", {}, "action_dispatch.show_exceptions" => false
end
end
end
@@ -131,8 +133,10 @@ module RenderActionWithApplicationLayout
# Set the view path to an application view structure with layouts
self.view_paths = self.view_paths = [ActionView::Template::FixturePath.new(
"render_action_with_application_layout/basic/hello_world.html.erb" => "Hello World!",
"render_action_with_application_layout/basic/hello.html.builder" => "xml.p 'Omg'",
"layouts/application.html.erb" => "OHAI <%= yield %> KTHXBAI",
"layouts/greetings.html.erb" => "Greetings <%= yield %> Bai"
"layouts/greetings.html.erb" => "Greetings <%= yield %> Bai",
"layouts/builder.html.builder" => "xml.html do\n xml << yield\nend"
)]
def hello_world
@@ -154,6 +158,10 @@ module RenderActionWithApplicationLayout
def hello_world_with_custom_layout
render :action => "hello_world", :layout => "greetings"
end
def with_builder_and_layout
render :action => "hello", :layout => "builder"
end
end
class TestDefaultLayout < SimpleRouteCase
@@ -199,6 +207,15 @@ module RenderActionWithApplicationLayout
assert_status 200
end
class TestLayout < SimpleRouteCase
testing BasicController
test "builder works with layouts" do
get :with_builder_and_layout
assert_response "<html>\n<p>Omg</p>\n</html>\n"
end
end
end
module RenderActionWithControllerLayout

View File

@@ -0,0 +1,110 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
module RenderFile
class BasicController < ActionController::Base
self.view_paths = "."
def index
render :file => File.join(File.dirname(__FILE__), *%w[.. fixtures test hello_world])
end
def with_instance_variables
@secret = 'in the sauce'
render :file => File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
end
def without_file_key
render File.join(File.dirname(__FILE__), *%w[.. fixtures test hello_world])
end
def without_file_key_with_instance_variable
@secret = 'in the sauce'
render File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
end
def relative_path
@secret = 'in the sauce'
render :file => '../fixtures/test/render_file_with_ivar'
end
def relative_path_with_dot
@secret = 'in the sauce'
render :file => '../fixtures/test/dot.directory/render_file_with_ivar'
end
def pathname
@secret = 'in the sauce'
render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. fixtures test dot.directory render_file_with_ivar.erb])
end
def with_locals
path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb')
render :file => path, :locals => {:secret => 'in the sauce'}
end
def without_file_key_with_locals
path = File.expand_path('../fixtures/test/render_file_with_locals.erb')
render path, :locals => {:secret => 'in the sauce'}
end
end
class TestBasic < SimpleRouteCase
testing RenderFile::BasicController
def setup
@old_pwd = Dir.pwd
Dir.chdir(File.dirname(__FILE__))
end
def teardown
Dir.chdir(@old_pwd)
end
test "rendering simple template" do
get :index
assert_response "Hello world!"
end
test "rendering template with ivar" do
get :with_instance_variables
assert_response "The secret is in the sauce\n"
end
test "rendering path without specifying the :file key" do
get :without_file_key
assert_response "Hello world!"
end
test "rendering path without specifying the :file key with ivar" do
get :without_file_key_with_instance_variable
assert_response "The secret is in the sauce\n"
end
test "rendering a relative path" do
get :relative_path
assert_response "The secret is in the sauce\n"
end
test "rendering a relative path with dot" do
get :relative_path_with_dot
assert_response "The secret is in the sauce\n"
end
test "rendering a Pathname" do
get :pathname
assert_response "The secret is in the sauce\n"
end
test "rendering file with locals" do
get :with_locals
assert_response "The secret is in the sauce\n"
end
test "rendering path without specifying the :file key with locals" do
get :without_file_key_with_locals
assert_response "The secret is in the sauce\n"
end
end
end

View File

@@ -6,7 +6,8 @@ module ControllerLayouts
self.view_paths = [ActionView::Template::FixturePath.new(
"layouts/application.html.erb" => "OMG <%= yield %> KTHXBAI",
"layouts/override.html.erb" => "Override! <%= yield %>",
"basic.html.erb" => "Hello world!"
"basic.html.erb" => "Hello world!",
"controller_layouts/implicit/layout_false.html.erb" => "hai(layout_false.html.erb)"
)]
def index
@@ -17,6 +18,10 @@ module ControllerLayouts
render :template => "basic", :layout => "override"
end
def layout_false
render :layout => false
end
def builder_override
end
@@ -56,4 +61,13 @@ module ControllerLayouts
get "/controller_layouts/implicit/override"
assert_body "Override! Hello world!"
end
class TestLayoutOptions < SimpleRouteCase
testing ControllerLayouts::ImplicitController
test "rendering with :layout => false leaves out the implicit layout" do
get :layout_false
assert_response "hai(layout_false.html.erb)"
end
end
end

View File

@@ -0,0 +1,27 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
module RenderPartial
class BasicController < ActionController::Base
self.view_paths = [ActionView::Template::FixturePath.new(
"render_partial/basic/_basic.html.erb" => "OMG!",
"render_partial/basic/basic.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'basic' %><%= @test_unchanged %>"
)]
def changing
@test_unchanged = 'hello'
render :action => "basic"
end
end
class TestPartial < SimpleRouteCase
testing BasicController
test "rendering a partial in ActionView doesn't pull the ivars again from the controller" do
get :changing
assert_response("goodbyeOMG!goodbye")
end
end
end

View File

@@ -4,14 +4,19 @@ module RenderTemplate
class WithoutLayoutController < ActionController::Base
self.view_paths = [ActionView::Template::FixturePath.new(
"test/basic.html.erb" => "Hello from basic.html.erb",
"shared.html.erb" => "Elastica",
"locals.html.erb" => "The secret is <%= secret %>"
"test/basic.html.erb" => "Hello from basic.html.erb",
"shared.html.erb" => "Elastica",
"locals.html.erb" => "The secret is <%= secret %>",
"xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend"
)]
def index
render :template => "test/basic"
end
def index_without_key
render "test/basic"
end
def in_top_directory
render :template => 'shared'
@@ -21,41 +26,56 @@ module RenderTemplate
render :template => '/shared'
end
def in_top_directory_with_slash_without_key
render '/shared'
end
def with_locals
render :template => "locals", :locals => { :secret => 'area51' }
end
def builder_template
render :template => "xml_template"
end
end
class TestWithoutLayout < SimpleRouteCase
describe "rendering a normal template with full path without layout"
testing RenderTemplate::WithoutLayoutController
get "/render_template/without_layout"
assert_body "Hello from basic.html.erb"
assert_status 200
end
class TestTemplateRenderInTopDirectory < SimpleRouteCase
describe "rendering a template not in a subdirectory"
test "rendering a normal template with full path without layout" do
get :index
assert_response "Hello from basic.html.erb"
end
get "/render_template/without_layout/in_top_directory"
assert_body "Elastica"
assert_status 200
end
class TestTemplateRenderInTopDirectoryWithSlash < SimpleRouteCase
describe "rendering a template not in a subdirectory with a leading slash"
test "rendering a normal template with full path without layout without key" do
get :index_without_key
assert_response "Hello from basic.html.erb"
end
get "/render_template/without_layout/in_top_directory_with_slash"
assert_body "Elastica"
assert_status 200
end
class TestTemplateRenderWithLocals < SimpleRouteCase
describe "rendering a template with local variables"
test "rendering a template not in a subdirectory" do
get :in_top_directory
assert_response "Elastica"
end
get "/render_template/without_layout/with_locals"
assert_body "The secret is area51"
assert_status 200
test "rendering a template not in a subdirectory with a leading slash" do
get :in_top_directory_with_slash
assert_response "Elastica"
end
test "rendering a template not in a subdirectory with a leading slash without key" do
get :in_top_directory_with_slash_without_key
assert_response "Elastica"
end
test "rendering a template with local variables" do
get :with_locals
assert_response "The secret is area51"
end
test "rendering a builder template" do
get :builder_template
assert_response "<html>\n <p>Hello</p>\n</html>\n"
end
end
class WithLayoutController < ::ApplicationController

View File

@@ -48,7 +48,7 @@ module Render
test "raises an exception" do
assert_raises(AbstractController::DoubleRenderError) do
get "/render/double_render"
get "/render/double_render", {}, "action_dispatch.show_exceptions" => false
end
end
end
@@ -58,13 +58,13 @@ module Render
test "raises an exception when a method of Object is called" do
assert_raises(AbstractController::ActionNotFound) do
get "/render/blank_render/clone"
get "/render/blank_render/clone", {}, "action_dispatch.show_exceptions" => false
end
end
test "raises an exception when a private method is called" do
assert_raises(AbstractController::ActionNotFound) do
get "/render/blank_render/secretz"
get "/render/blank_render/secretz", {}, "action_dispatch.show_exceptions" => false
end
end
end

View File

@@ -0,0 +1,11 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
module RenderXml
# This has no layout and it works
class BasicController < ActionController::Base
self.view_paths = [ActionView::Template::FixturePath.new(
"render_xml/basic/with_render_erb" => "Hello world!"
)]
end
end

View File

@@ -46,7 +46,7 @@ class Rack::TestCase < ActiveSupport::TestCase
ActionController::Routing.use_controllers!(controllers)
# Move into a bootloader
AbstractController::Base.subclasses.each do |klass|
ActionController::Base.subclasses.each do |klass|
klass = klass.constantize
next unless klass < AbstractController::Layouts
klass.class_eval do
@@ -59,12 +59,28 @@ class Rack::TestCase < ActiveSupport::TestCase
@app ||= ActionController::Dispatcher.new
end
def self.testing(klass = nil)
if klass
@testing = "/#{klass.name.underscore}".sub!(/_controller$/, '')
else
@testing
end
end
def self.get(url)
setup do |test|
test.get url
end
end
def get(thing, *args)
if thing.is_a?(Symbol)
super("#{self.class.testing}/#{thing}")
else
super
end
end
def assert_body(body)
assert_equal body, Array.wrap(last_response.body).join
end
@@ -85,6 +101,14 @@ class Rack::TestCase < ActiveSupport::TestCase
end
end
def assert_response(body, status = 200, headers = {})
assert_body body
assert_status status
headers.each do |header, value|
assert_header header, value
end
end
def assert_content_type(type)
assert_equal type, last_response.headers["Content-Type"]
end

View File

@@ -80,6 +80,14 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
def test_string_options_for_select
options = "<option value=\"Denmark\">Denmark</option><option value=\"USA\">USA</option><option value=\"Sweden\">Sweden</option>"
assert_dom_equal(
options,
options_for_select(options)
)
end
def test_array_options_for_select
assert_dom_equal(
"<option value=\"&lt;Denmark&gt;\">&lt;Denmark&gt;</option>\n<option value=\"USA\">USA</option>\n<option value=\"Sweden\">Sweden</option>",
@@ -324,6 +332,20 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
def test_select_under_fields_for_with_string_and_given_prompt
@post = Post.new
options = "<option value=\"abe\">abe</option><option value=\"mus\">mus</option><option value=\"hest\">hest</option>"
fields_for :post, @post do |f|
concat f.select(:category, options, :prompt => 'The prompt')
end
assert_dom_equal(
"<select id=\"post_category\" name=\"post[category]\"><option value=\"\">The prompt</option>\n#{options}</select>",
output_buffer
)
end
def test_select_with_blank
@post = Post.new
@post.category = "<mus>"

View File

@@ -118,6 +118,10 @@ class NumberHelperTest < ActionView::TestCase
assert_equal '1.01 KB', number_to_human_size(1.0123.kilobytes, :precision => 2)
assert_equal '1.01 KB', number_to_human_size(1.0100.kilobytes, :precision => 4)
assert_equal '10 KB', number_to_human_size(10.000.kilobytes, :precision => 4)
assert_equal '1 TB', number_to_human_size(1234567890123, :precision => 0)
assert_equal '500 MB', number_to_human_size(524288000, :precision=>0)
assert_equal '40 KB', number_to_human_size(41010, :precision => 0)
assert_equal '40 KB', number_to_human_size(41100, :precision => 0)
end
def test_number_to_human_size_with_custom_delimiter_and_separator

View File

@@ -401,6 +401,13 @@ class TextHelperTest < ActionView::TestCase
auto_link("Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.",
:link => :all, :html => { :class => "menu", :target => "_blank" })
end
def test_auto_link_with_multiple_trailing_punctuations
url = "http://youtube.com"
url_result = generate_result(url)
assert_equal url_result, auto_link(url)
assert_equal "(link: #{url_result}).", auto_link("(link: #{url}).")
end
def test_cycle_class
value = Cycle.new("one", 2, "3")

View File

@@ -11,6 +11,12 @@ Rake::TestTask.new do |t|
t.verbose = true
t.warning = true
end
task :isolated_test do
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir.glob("test/**/*_test.rb").all? do |file|
system(ruby, '-Ilib:test', file)
end or raise "Failures"
end
# Generate the RDoc documentation
Rake::RDocTask.new do |rdoc|

View File

@@ -1,4 +1,5 @@
require 'test_helper'
require 'active_model/state_machine/event'
class EventTest < ActiveModel::TestCase
def setup

View File

@@ -1,4 +1,5 @@
require 'test_helper'
require 'active_model/state_machine/state_transition'
class StateTransitionTest < ActiveModel::TestCase
test 'should set from, to, and opts attr readers' do

View File

@@ -1,5 +1,7 @@
*Edge*
* Implement #many? for NamedScope and AssociationCollection using #size. #1500 [Chris Kampmeier]
* Added :touch option to belongs_to associations that will touch the parent record when the current record is saved or destroyed [DHH]
* Added ActiveRecord::Base#touch to update the updated_at/on attributes (or another specified timestamp) with the current time [DHH]

View File

@@ -32,21 +32,32 @@ desc 'Run mysql, sqlite, and postgresql tests'
task :test => defined?(JRUBY_VERSION) ?
%w(test_jdbcmysql test_jdbcsqlite3 test_jdbcpostgresql) :
%w(test_mysql test_sqlite3 test_postgresql)
task :isolated_test => defined?(JRUBY_VERSION) ?
%w(isolated_test_jdbcmysql isolated_test_jdbcsqlite3 isolated_test_jdbcpostgresql) :
%w(isolated_test_mysql isolated_test_sqlite3 isolated_test_postgresql)
for adapter in %w( mysql postgresql sqlite sqlite3 firebird db2 oracle sybase openbase frontbase jdbcmysql jdbcpostgresql jdbcsqlite3 jdbcderby jdbch2 jdbchsqldb )
%w( mysql postgresql sqlite sqlite3 firebird db2 oracle sybase openbase frontbase jdbcmysql jdbcpostgresql jdbcsqlite3 jdbcderby jdbch2 jdbchsqldb ).each do |adapter|
Rake::TestTask.new("test_#{adapter}") { |t|
if adapter =~ /jdbc/
t.libs << "test" << "test/connections/jdbc_#{adapter}"
else
t.libs << "test" << "test/connections/native_#{adapter}"
end
connection_path = "test/connections/#{adapter =~ /jdbc/ ? 'jdbc' : 'native'}_#{adapter}"
adapter_short = adapter == 'db2' ? adapter : adapter[/^[a-z]+/]
t.libs << "test" << connection_path
t.test_files=Dir.glob( "test/cases/**/*_test{,_#{adapter_short}}.rb" ).sort
t.verbose = true
}
task "isolated_test_#{adapter}" do
connection_path = "test/connections/#{adapter =~ /jdbc/ ? 'jdbc' : 'native'}_#{adapter}"
adapter_short = adapter == 'db2' ? adapter : adapter[/^[a-z]+/]
puts [adapter, adapter_short, connection_path].inspect
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir["test/cases/**/*_test{,_#{adapter_short}}.rb"].all? do |file|
system(ruby, "-Ilib:test:#{connection_path}", file)
end or raise "Failures"
end
namespace adapter do
task :test => "test_#{adapter}"
task :isolated_test => "isolated_test_#{adapter}"
end
end

View File

@@ -0,0 +1,14 @@
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
require 'active_record'
class Person < ActiveRecord::Base
establish_connection :adapter => 'sqlite3', :database => 'foobar.db'
connection.create_table table_name, :force => true do |t|
t.string :name
end
end
bob = Person.create!(:name => 'bob')
puts Person.all.inspect
bob.destroy
puts Person.all.inspect

View File

@@ -24,7 +24,9 @@
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift(activesupport_path) if File.directory?(activesupport_path)
require 'active_support'
require 'active_support/core/all'
# TODO: Figure out what parts of AS are *actually* required and use those
require 'active_support/core_ext'
$:.unshift(File.dirname(__FILE__) + '/../../arel/lib')
require 'arel'
@@ -78,5 +80,4 @@ module ActiveRecord
end
end
require 'active_record/i18n_interpolation_deprecation'
I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'

View File

@@ -1,3 +1,5 @@
require 'active_support/core_ext/module/delegation'
module ActiveRecord
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
def initialize(reflection)
@@ -1674,7 +1676,7 @@ module ActiveRecord
def tables_in_string(string)
return [] if string.blank?
string.scan(/([\.a-zA-Z_]+).?\./).flatten
string.scan(/([a-zA-Z_][\.\w]+).?\./).flatten
end
def tables_in_hash(hash)

View File

@@ -302,6 +302,15 @@ module ActiveRecord
end
end
# Returns true if the collection has more than 1 record. Equivalent to collection.size > 1.
def many?
if block_given?
method_missing(:many?) { |*block_args| yield(*block_args) }
else
size > 1
end
end
def uniq(collection = self)
seen = Set.new
collection.inject([]) do |kept, record|

Some files were not shown because too many files have changed in this diff Show More