mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Merge branch 'master' of github.com:rails/rails
This commit is contained in:
@@ -866,7 +866,6 @@ EOF
|
||||
regex = Regexp.escape('Subject: Foo =?UTF-8?Q?=C3=A1=C3=AB=C3=B4=?= =?UTF-8?Q?_=C3=AE=C3=BC=?=')
|
||||
assert_match(/#{regex}/, mail.encoded)
|
||||
string = "Foo áëô îü"
|
||||
string.force_encoding('UTF-8') if string.respond_to?(:force_encoding)
|
||||
assert_match(string, mail.subject)
|
||||
end
|
||||
|
||||
@@ -875,7 +874,6 @@ EOF
|
||||
regex = Regexp.escape('Subject: Foo =?UTF-8?Q?=C3=A1=C3=AB=C3=B4=?= =?UTF-8?Q?_=C3=AE=C3=BC=?=')
|
||||
assert_match(/#{regex}/, mail.encoded)
|
||||
string = "Foo áëô îü"
|
||||
string.force_encoding('UTF-8') if string.respond_to?(:force_encoding)
|
||||
assert_match(string, mail.subject)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
|
||||
|
||||
* Renamed the field error CSS class from fieldWithErrors to field_with_errors for consistency. [Jeremy Kemper]
|
||||
|
||||
* Add support for shorthand routes like /projects/status(.:format) #4423 [Diego Carrion]
|
||||
|
||||
* Changed translate helper so that it doesn’t mark every translation as safe HTML. Only keys with a "_html" suffix and keys named "html" are considered to be safe HTML. All other translations are left untouched. [Craig Davey]
|
||||
|
||||
@@ -12,7 +12,6 @@ require 'active_support/i18n'
|
||||
module AbstractController
|
||||
extend ActiveSupport::Autoload
|
||||
|
||||
autoload :Assigns
|
||||
autoload :Base
|
||||
autoload :Callbacks
|
||||
autoload :Collector
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
module AbstractController
|
||||
module Assigns
|
||||
# This method should return a hash with assigns.
|
||||
# You can overwrite this configuration per controller.
|
||||
# :api: public
|
||||
def view_assigns
|
||||
hash = {}
|
||||
variables = instance_variable_names
|
||||
variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
|
||||
variables.each { |name| hash[name] = instance_variable_get(name) }
|
||||
hash
|
||||
end
|
||||
|
||||
# This method assigns the hash specified in _assigns_hash to the given object.
|
||||
# :api: private
|
||||
# TODO Ideally, this should be done on AV::Base.new initialization.
|
||||
def _evaluate_assigns(object)
|
||||
view_assigns.each { |k,v| object.instance_variable_set(k, v) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'active_support/ordered_options'
|
||||
require 'active_support/configurable'
|
||||
|
||||
module AbstractController
|
||||
class Error < StandardError; end
|
||||
@@ -8,6 +8,8 @@ module AbstractController
|
||||
attr_internal :response_body
|
||||
attr_internal :action_name
|
||||
|
||||
include ActiveSupport::Configurable
|
||||
|
||||
class << self
|
||||
attr_reader :abstract
|
||||
alias_method :abstract?, :abstract
|
||||
@@ -29,14 +31,6 @@ module AbstractController
|
||||
@descendants ||= []
|
||||
end
|
||||
|
||||
def config
|
||||
@config ||= ActiveSupport::InheritableOptions.new(superclass < Base ? superclass.config : {})
|
||||
end
|
||||
|
||||
def configure
|
||||
yield config
|
||||
end
|
||||
|
||||
# A list of all internal methods for a controller. This finds the first
|
||||
# abstract superclass of a controller, and gets a list of all public
|
||||
# instance methods on that abstract class. Public instance methods of
|
||||
@@ -99,10 +93,6 @@ module AbstractController
|
||||
|
||||
abstract!
|
||||
|
||||
def config
|
||||
@config ||= ActiveSupport::InheritableOptions.new(self.class.config)
|
||||
end
|
||||
|
||||
# Calls the action going through the entire action dispatch stack.
|
||||
#
|
||||
# The actual method that is called is determined by calling
|
||||
@@ -133,6 +123,7 @@ module AbstractController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns true if the name can be considered an action. This can
|
||||
# be overridden in subclasses to modify the semantics of what
|
||||
# can be considered an action.
|
||||
|
||||
@@ -8,7 +8,6 @@ module AbstractController
|
||||
|
||||
included do
|
||||
class_attribute :_helpers
|
||||
delegate :_helpers, :to => :'self.class'
|
||||
self._helpers = Module.new
|
||||
end
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ module AbstractController
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
cattr_accessor :logger
|
||||
config_accessor :logger
|
||||
extend ActiveSupport::Benchmarkable
|
||||
end
|
||||
end
|
||||
|
||||
@@ -65,8 +65,11 @@ module ActionController
|
||||
@subclasses ||= []
|
||||
end
|
||||
|
||||
# TODO Move this to the appropriate module
|
||||
config_accessor :assets_dir, :asset_path, :javascripts_dir, :stylesheets_dir
|
||||
|
||||
ActiveSupport.run_load_hooks(:action_controller, self)
|
||||
end
|
||||
end
|
||||
|
||||
require "action_controller/deprecated/base"
|
||||
require "action_controller/deprecated/base"
|
||||
@@ -63,12 +63,10 @@ module ActionController #:nodoc:
|
||||
included do
|
||||
extend ConfigMethods
|
||||
|
||||
delegate :perform_caching, :perform_caching=, :to => :config
|
||||
singleton_class.delegate :perform_caching, :perform_caching=, :to => :config
|
||||
self.perform_caching = true
|
||||
config_accessor :perform_caching
|
||||
self.perform_caching = true if perform_caching.nil?
|
||||
end
|
||||
|
||||
|
||||
def caching_allowed?
|
||||
request.get? && response.status == 200
|
||||
end
|
||||
|
||||
@@ -44,8 +44,8 @@ module ActionController #:nodoc:
|
||||
# For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>Rails.root + "/public"</tt>). Changing
|
||||
# this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
|
||||
# web server to look in the new location for cached files.
|
||||
singleton_class.delegate :page_cache_directory, :page_cache_directory=, :to => :config
|
||||
self.page_cache_directory = ''
|
||||
config_accessor :page_cache_directory
|
||||
self.page_cache_directory ||= ''
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
@@ -53,8 +53,8 @@ module ActionController #:nodoc:
|
||||
# order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
|
||||
# If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
|
||||
# extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
|
||||
singleton_class.delegate :page_cache_extension, :page_cache_extension=, :to => :config
|
||||
self.page_cache_extension = '.html'
|
||||
config_accessor :page_cache_extension
|
||||
self.page_cache_extension ||= '.html'
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
@@ -1,33 +1,16 @@
|
||||
module ActionController
|
||||
class Base
|
||||
class << self
|
||||
def deprecated_config_accessor(option, message = nil)
|
||||
deprecated_config_reader(option, message)
|
||||
deprecated_config_writer(option, message)
|
||||
# Deprecated methods. Wrap them in a module so they can be overwritten by plugins
|
||||
# (like the verify method.)
|
||||
module DeprecatedBehavior #:nodoc:
|
||||
def relative_url_root
|
||||
ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root is ineffective. " <<
|
||||
"Please stop using it.", caller
|
||||
end
|
||||
|
||||
def deprecated_config_reader(option, message = nil)
|
||||
message ||= "Reading #{option} directly from ActionController::Base is deprecated. " \
|
||||
"Please read it from config.#{option}"
|
||||
|
||||
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||
def #{option}
|
||||
ActiveSupport::Deprecation.warn #{message.inspect}, caller
|
||||
config.#{option}
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
def deprecated_config_writer(option, message = nil)
|
||||
message ||= "Setting #{option} directly on ActionController::Base is deprecated. " \
|
||||
"Please set it on config.action_controller.#{option}"
|
||||
|
||||
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||
def #{option}=(val)
|
||||
ActiveSupport::Deprecation.warn #{message.inspect}, caller
|
||||
config.#{option} = val
|
||||
end
|
||||
RUBY
|
||||
def relative_url_root=
|
||||
ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root= is ineffective. " <<
|
||||
"Please stop using it.", caller
|
||||
end
|
||||
|
||||
def consider_all_requests_local
|
||||
@@ -125,9 +108,7 @@ module ActionController
|
||||
def use_accept_header=(val)
|
||||
use_accept_header
|
||||
end
|
||||
end
|
||||
|
||||
module DeprecatedBehavior
|
||||
# This method has been moved to ActionDispatch::Request.filter_parameters
|
||||
def filter_parameter_logging(*args, &block)
|
||||
ActiveSupport::Deprecation.warn("Setting filter_parameter_logging in ActionController is deprecated and has no longer effect, please set 'config.filter_parameters' in config/application.rb instead", caller)
|
||||
@@ -146,17 +127,6 @@ module ActionController
|
||||
|
||||
extend DeprecatedBehavior
|
||||
|
||||
deprecated_config_writer :session_options
|
||||
deprecated_config_writer :session_store
|
||||
|
||||
deprecated_config_accessor :assets_dir
|
||||
deprecated_config_accessor :asset_path
|
||||
deprecated_config_accessor :helpers_path
|
||||
deprecated_config_accessor :javascripts_dir
|
||||
deprecated_config_accessor :page_cache_directory
|
||||
deprecated_config_accessor :relative_url_root, "relative_url_root is ineffective. Please stop using it"
|
||||
deprecated_config_accessor :stylesheets_dir
|
||||
|
||||
delegate :consider_all_requests_local, :consider_all_requests_local=,
|
||||
:allow_concurrency, :allow_concurrency=, :to => :"self.class"
|
||||
end
|
||||
|
||||
@@ -21,8 +21,8 @@ module ActionController
|
||||
delegate :default_charset=, :to => "ActionDispatch::Response"
|
||||
end
|
||||
|
||||
# cattr_reader :protected_instance_variables
|
||||
cattr_accessor :protected_instance_variables
|
||||
# TODO: Update protected instance variables list
|
||||
config_accessor :protected_instance_variables
|
||||
self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render
|
||||
@variables_added @request_origin @url
|
||||
@parent_controller @action_name
|
||||
|
||||
@@ -52,8 +52,8 @@ module ActionController
|
||||
include AbstractController::Helpers
|
||||
|
||||
included do
|
||||
class_attribute :helpers_path
|
||||
self.helpers_path = []
|
||||
config_accessor :helpers_path
|
||||
self.helpers_path ||= []
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
@@ -79,12 +79,12 @@ module ActionController
|
||||
|
||||
add :js do |js, options|
|
||||
self.content_type ||= Mime::JS
|
||||
self.response_body = js.respond_to?(:to_js) ? js.to_js : js
|
||||
self.response_body = js.respond_to?(:to_js) ? js.to_js(options) : js
|
||||
end
|
||||
|
||||
add :xml do |xml, options|
|
||||
self.content_type ||= Mime::XML
|
||||
self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml
|
||||
self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
|
||||
end
|
||||
|
||||
add :update do |proc, options|
|
||||
|
||||
@@ -4,6 +4,45 @@ module ActionController #:nodoc:
|
||||
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
|
||||
end
|
||||
|
||||
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
|
||||
# web application, not a forged link from another site, is done by embedding a token based on a random
|
||||
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
|
||||
# by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
|
||||
# requests are checked, so this will not protect your XML API (presumably you'll have a different
|
||||
# authentication scheme there anyway). Also, GET requests are not protected as these should be
|
||||
# idempotent anyway.
|
||||
#
|
||||
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
|
||||
# ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
|
||||
# error message in production by editing public/422.html. A call to this method in ApplicationController is
|
||||
# generated by default in post-Rails 2.0 applications.
|
||||
#
|
||||
# The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
|
||||
# manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
|
||||
# include a hidden field named like that and set its value to what is returned by
|
||||
# <tt>form_authenticity_token</tt>.
|
||||
#
|
||||
# Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
|
||||
# 1.x, add this to config/environments/test.rb:
|
||||
#
|
||||
# # Disable request forgery protection in test environment
|
||||
# config.action_controller.allow_forgery_protection = false
|
||||
#
|
||||
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
|
||||
#
|
||||
# Here are some resources:
|
||||
# * http://isc.sans.org/diary.html?storyid=1750
|
||||
# * http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
||||
#
|
||||
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
|
||||
# There are a few guidelines you should follow:
|
||||
#
|
||||
# * Keep your GET requests safe and idempotent. More reading material:
|
||||
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
|
||||
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
|
||||
# * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
|
||||
# for "Expires: at end of session"
|
||||
#
|
||||
module RequestForgeryProtection
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
@@ -12,54 +51,17 @@ module ActionController #:nodoc:
|
||||
included do
|
||||
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
|
||||
# sets it to <tt>:authenticity_token</tt> by default.
|
||||
config.request_forgery_protection_token ||= :authenticity_token
|
||||
config_accessor :request_forgery_protection_token
|
||||
self.request_forgery_protection_token ||= :authenticity_token
|
||||
|
||||
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
|
||||
config.allow_forgery_protection ||= true
|
||||
config_accessor :allow_forgery_protection
|
||||
self.allow_forgery_protection = true if allow_forgery_protection.nil?
|
||||
|
||||
helper_method :form_authenticity_token
|
||||
helper_method :protect_against_forgery?
|
||||
end
|
||||
|
||||
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
|
||||
# web application, not a forged link from another site, is done by embedding a token based on a random
|
||||
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
|
||||
# by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
|
||||
# requests are checked, so this will not protect your XML API (presumably you'll have a different
|
||||
# authentication scheme there anyway). Also, GET requests are not protected as these should be
|
||||
# idempotent anyway.
|
||||
#
|
||||
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
|
||||
# ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
|
||||
# error message in production by editing public/422.html. A call to this method in ApplicationController is
|
||||
# generated by default in post-Rails 2.0 applications.
|
||||
#
|
||||
# The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
|
||||
# manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
|
||||
# include a hidden field named like that and set its value to what is returned by
|
||||
# <tt>form_authenticity_token</tt>.
|
||||
#
|
||||
# Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
|
||||
# 1.x, add this to config/environments/test.rb:
|
||||
#
|
||||
# # Disable request forgery protection in test environment
|
||||
# config.action_controller.allow_forgery_protection = false
|
||||
#
|
||||
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
|
||||
#
|
||||
# Here are some resources:
|
||||
# * http://isc.sans.org/diary.html?storyid=1750
|
||||
# * http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
||||
#
|
||||
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
|
||||
# There are a few guidelines you should follow:
|
||||
#
|
||||
# * Keep your GET requests safe and idempotent. More reading material:
|
||||
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
|
||||
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
|
||||
# * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
|
||||
# for "Expires: at end of session"
|
||||
#
|
||||
module ClassMethods
|
||||
# Turn on request forgery protection. Bear in mind that only non-GET, HTML/JavaScript requests are checked.
|
||||
#
|
||||
@@ -79,22 +81,6 @@ module ActionController #:nodoc:
|
||||
self.request_forgery_protection_token ||= :authenticity_token
|
||||
before_filter :verify_authenticity_token, options
|
||||
end
|
||||
|
||||
def request_forgery_protection_token
|
||||
config.request_forgery_protection_token
|
||||
end
|
||||
|
||||
def request_forgery_protection_token=(val)
|
||||
config.request_forgery_protection_token = val
|
||||
end
|
||||
|
||||
def allow_forgery_protection
|
||||
config.allow_forgery_protection
|
||||
end
|
||||
|
||||
def allow_forgery_protection=(val)
|
||||
config.allow_forgery_protection = val
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
@@ -104,22 +90,6 @@ module ActionController #:nodoc:
|
||||
before_filter :verify_authenticity_token, options
|
||||
end
|
||||
|
||||
def request_forgery_protection_token
|
||||
config.request_forgery_protection_token
|
||||
end
|
||||
|
||||
def request_forgery_protection_token=(val)
|
||||
config.request_forgery_protection_token = val
|
||||
end
|
||||
|
||||
def allow_forgery_protection
|
||||
config.allow_forgery_protection
|
||||
end
|
||||
|
||||
def allow_forgery_protection=(val)
|
||||
config.allow_forgery_protection = val
|
||||
end
|
||||
|
||||
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
|
||||
def verify_authenticity_token
|
||||
verified_request? || raise(ActionController::InvalidAuthenticityToken)
|
||||
@@ -146,7 +116,7 @@ module ActionController #:nodoc:
|
||||
end
|
||||
|
||||
def protect_against_forgery?
|
||||
config.allow_forgery_protection
|
||||
allow_forgery_protection
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,64 +13,51 @@ module ActionController
|
||||
class Railtie < Rails::Railtie
|
||||
config.action_controller = ActiveSupport::OrderedOptions.new
|
||||
|
||||
ad = config.action_dispatch
|
||||
config.action_controller.singleton_class.send(:define_method, :session) do
|
||||
ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
|
||||
"renamed to config.action_dispatch.session.", caller
|
||||
ad.session
|
||||
end
|
||||
config.action_controller.singleton_class.tap do |d|
|
||||
d.send(:define_method, :session) do
|
||||
ActiveSupport::Deprecation.warn "config.action_controller.session has been deprecated. " <<
|
||||
"Please use Rails.application.config.session_store instead.", caller
|
||||
end
|
||||
|
||||
config.action_controller.singleton_class.send(:define_method, :session=) do |val|
|
||||
ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
|
||||
"renamed to config.action_dispatch.session.", caller
|
||||
ad.session = val
|
||||
end
|
||||
d.send(:define_method, :session=) do |val|
|
||||
ActiveSupport::Deprecation.warn "config.action_controller.session= has been deprecated. " <<
|
||||
"Please use config.session_store(name, options) instead.", caller
|
||||
end
|
||||
|
||||
config.action_controller.singleton_class.send(:define_method, :session_store) do
|
||||
ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
|
||||
"renamed to config.action_dispatch.session_store.", caller
|
||||
ad.session_store
|
||||
end
|
||||
d.send(:define_method, :session_store) do
|
||||
ActiveSupport::Deprecation.warn "config.action_controller.session_store has been deprecated. " <<
|
||||
"Please use Rails.application.config.session_store instead.", caller
|
||||
end
|
||||
|
||||
config.action_controller.singleton_class.send(:define_method, :session_store=) do |val|
|
||||
ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
|
||||
"renamed to config.action_dispatch.session_store.", caller
|
||||
ad.session_store = val
|
||||
d.send(:define_method, :session_store=) do |val|
|
||||
ActiveSupport::Deprecation.warn "config.action_controller.session_store= has been deprecated. " <<
|
||||
"Please use config.session_store(name, options) instead.", caller
|
||||
end
|
||||
end
|
||||
|
||||
log_subscriber :action_controller, ActionController::Railties::LogSubscriber.new
|
||||
|
||||
initializer "action_controller.logger" do
|
||||
ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
|
||||
end
|
||||
|
||||
initializer "action_controller.page_cache_directory" do
|
||||
ActiveSupport.on_load(:action_controller) do
|
||||
self.page_cache_directory = Rails.public_path
|
||||
end
|
||||
end
|
||||
|
||||
initializer "action_controller.set_configs" do |app|
|
||||
paths = app.config.paths
|
||||
ac = app.config.action_controller
|
||||
|
||||
ac.assets_dir = paths.public.to_a.first
|
||||
ac.javascripts_dir = paths.public.javascripts.to_a.first
|
||||
ac.stylesheets_dir = paths.public.stylesheets.to_a.first
|
||||
ac.assets_dir ||= paths.public.to_a.first
|
||||
ac.javascripts_dir ||= paths.public.javascripts.to_a.first
|
||||
ac.stylesheets_dir ||= paths.public.stylesheets.to_a.first
|
||||
ac.page_cache_directory ||= paths.public.to_a.first
|
||||
ac.helpers_path ||= paths.app.helpers.to_a
|
||||
|
||||
ActiveSupport.on_load(:action_controller) do
|
||||
self.config.merge!(ac)
|
||||
end
|
||||
end
|
||||
|
||||
initializer "action_controller.initialize_framework_caches" do
|
||||
ActiveSupport.on_load(:action_controller) { self.cache_store ||= RAILS_CACHE }
|
||||
initializer "action_controller.logger" do
|
||||
ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
|
||||
end
|
||||
|
||||
initializer "action_controller.set_helpers_path" do |app|
|
||||
ActiveSupport.on_load(:action_controller) do
|
||||
self.helpers_path = app.config.paths.app.helpers.to_a
|
||||
end
|
||||
initializer "action_controller.initialize_framework_caches" do
|
||||
ActiveSupport.on_load(:action_controller) { self.cache_store ||= RAILS_CACHE }
|
||||
end
|
||||
|
||||
initializer "action_controller.url_helpers" do |app|
|
||||
|
||||
@@ -36,6 +36,7 @@ module ActionController
|
||||
end
|
||||
|
||||
def teardown_subscriptions
|
||||
ActiveSupport::Notifications.unsubscribe("action_view.render_template")
|
||||
ActiveSupport::Notifications.unsubscribe("action_view.render_template!")
|
||||
end
|
||||
|
||||
@@ -282,82 +283,161 @@ module ActionController
|
||||
#
|
||||
# assert_redirected_to page_url(:title => 'foo')
|
||||
class TestCase < ActiveSupport::TestCase
|
||||
include ActionDispatch::TestProcess
|
||||
include ActionController::TemplateAssertions
|
||||
module Behavior
|
||||
extend ActiveSupport::Concern
|
||||
include ActionDispatch::TestProcess
|
||||
|
||||
attr_reader :response, :request
|
||||
attr_reader :response, :request
|
||||
|
||||
# Executes a request simulating GET HTTP method and set/volley the response
|
||||
def get(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "GET")
|
||||
end
|
||||
module ClassMethods
|
||||
|
||||
# Executes a request simulating POST HTTP method and set/volley the response
|
||||
def post(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "POST")
|
||||
end
|
||||
# Sets the controller class name. Useful if the name can't be inferred from test class.
|
||||
# Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
|
||||
def tests(controller_class)
|
||||
self.controller_class = controller_class
|
||||
end
|
||||
|
||||
def controller_class=(new_class)
|
||||
prepare_controller_class(new_class) if new_class
|
||||
write_inheritable_attribute(:controller_class, new_class)
|
||||
end
|
||||
|
||||
# Executes a request simulating PUT HTTP method and set/volley the response
|
||||
def put(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "PUT")
|
||||
end
|
||||
def controller_class
|
||||
if current_controller_class = read_inheritable_attribute(:controller_class)
|
||||
current_controller_class
|
||||
else
|
||||
self.controller_class = determine_default_controller_class(name)
|
||||
end
|
||||
end
|
||||
|
||||
# Executes a request simulating DELETE HTTP method and set/volley the response
|
||||
def delete(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "DELETE")
|
||||
end
|
||||
def determine_default_controller_class(name)
|
||||
name.sub(/Test$/, '').constantize
|
||||
rescue NameError
|
||||
nil
|
||||
end
|
||||
|
||||
# Executes a request simulating HEAD HTTP method and set/volley the response
|
||||
def head(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "HEAD")
|
||||
end
|
||||
def prepare_controller_class(new_class)
|
||||
new_class.send :include, ActionController::TestCase::RaiseActionExceptions
|
||||
end
|
||||
|
||||
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
|
||||
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
|
||||
returning __send__(request_method, action, parameters, session, flash) do
|
||||
@request.env.delete 'HTTP_X_REQUESTED_WITH'
|
||||
@request.env.delete 'HTTP_ACCEPT'
|
||||
end
|
||||
end
|
||||
alias xhr :xml_http_request
|
||||
|
||||
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
|
||||
# Sanity check for required instance variables so we can give an
|
||||
# understandable error message.
|
||||
%w(@routes @controller @request @response).each do |iv_name|
|
||||
if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
|
||||
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
|
||||
# Executes a request simulating GET HTTP method and set/volley the response
|
||||
def get(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "GET")
|
||||
end
|
||||
|
||||
# Executes a request simulating POST HTTP method and set/volley the response
|
||||
def post(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "POST")
|
||||
end
|
||||
|
||||
# Executes a request simulating PUT HTTP method and set/volley the response
|
||||
def put(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "PUT")
|
||||
end
|
||||
|
||||
# Executes a request simulating DELETE HTTP method and set/volley the response
|
||||
def delete(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "DELETE")
|
||||
end
|
||||
|
||||
# Executes a request simulating HEAD HTTP method and set/volley the response
|
||||
def head(action, parameters = nil, session = nil, flash = nil)
|
||||
process(action, parameters, session, flash, "HEAD")
|
||||
end
|
||||
|
||||
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
|
||||
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
|
||||
returning __send__(request_method, action, parameters, session, flash) do
|
||||
@request.env.delete 'HTTP_X_REQUESTED_WITH'
|
||||
@request.env.delete 'HTTP_ACCEPT'
|
||||
end
|
||||
end
|
||||
alias xhr :xml_http_request
|
||||
|
||||
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
|
||||
# Sanity check for required instance variables so we can give an
|
||||
# understandable error message.
|
||||
%w(@routes @controller @request @response).each do |iv_name|
|
||||
if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
|
||||
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
|
||||
end
|
||||
end
|
||||
|
||||
@request.recycle!
|
||||
@response.recycle!
|
||||
@controller.response_body = nil
|
||||
@controller.formats = nil
|
||||
@controller.params = nil
|
||||
|
||||
@html_document = nil
|
||||
@request.env['REQUEST_METHOD'] = http_method
|
||||
|
||||
parameters ||= {}
|
||||
@request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
|
||||
|
||||
@request.session = ActionController::TestSession.new(session) unless session.nil?
|
||||
@request.session["flash"] = @request.flash.update(flash || {})
|
||||
@request.session["flash"].sweep
|
||||
|
||||
@controller.request = @request
|
||||
@controller.params.merge!(parameters)
|
||||
build_request_uri(action, parameters)
|
||||
Base.class_eval { include Testing }
|
||||
@controller.process_with_new_base_test(@request, @response)
|
||||
@request.session.delete('flash') if @request.session['flash'].blank?
|
||||
@response
|
||||
end
|
||||
|
||||
def setup_controller_request_and_response
|
||||
@request = TestRequest.new
|
||||
@response = TestResponse.new
|
||||
|
||||
if klass = self.class.controller_class
|
||||
@controller ||= klass.new rescue nil
|
||||
end
|
||||
|
||||
@request.env.delete('PATH_INFO')
|
||||
|
||||
if @controller
|
||||
@controller.request = @request
|
||||
@controller.params = {}
|
||||
end
|
||||
end
|
||||
|
||||
@request.recycle!
|
||||
@response.recycle!
|
||||
@controller.response_body = nil
|
||||
@controller.formats = nil
|
||||
@controller.params = nil
|
||||
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
|
||||
def rescue_action_in_public!
|
||||
@request.remote_addr = '208.77.188.166' # example.com
|
||||
end
|
||||
|
||||
@html_document = nil
|
||||
@request.env['REQUEST_METHOD'] = http_method
|
||||
included do
|
||||
include ActionController::TemplateAssertions
|
||||
include ActionDispatch::Assertions
|
||||
setup :setup_controller_request_and_response
|
||||
end
|
||||
|
||||
parameters ||= {}
|
||||
@request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
|
||||
private
|
||||
|
||||
@request.session = ActionController::TestSession.new(session) unless session.nil?
|
||||
@request.session["flash"] = @request.flash.update(flash || {})
|
||||
@request.session["flash"].sweep
|
||||
def build_request_uri(action, parameters)
|
||||
unless @request.env["PATH_INFO"]
|
||||
options = @controller.__send__(:url_options).merge(parameters)
|
||||
options.update(
|
||||
:only_path => true,
|
||||
:action => action,
|
||||
:relative_url_root => nil,
|
||||
:_path_segments => @request.symbolized_path_parameters)
|
||||
|
||||
@controller.request = @request
|
||||
@controller.params.merge!(parameters)
|
||||
build_request_uri(action, parameters)
|
||||
Base.class_eval { include Testing }
|
||||
@controller.process_with_new_base_test(@request, @response)
|
||||
@request.session.delete('flash') if @request.session['flash'].blank?
|
||||
@response
|
||||
url, query_string = @routes.url_for(options).split("?", 2)
|
||||
|
||||
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
|
||||
@request.env["PATH_INFO"] = url
|
||||
@request.env["QUERY_STRING"] = query_string || ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include ActionDispatch::Assertions
|
||||
|
||||
# When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
|
||||
# (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
|
||||
# rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
|
||||
@@ -384,78 +464,6 @@ module ActionController
|
||||
end
|
||||
end
|
||||
|
||||
setup :setup_controller_request_and_response
|
||||
|
||||
@@controller_class = nil
|
||||
|
||||
class << self
|
||||
# Sets the controller class name. Useful if the name can't be inferred from test class.
|
||||
# Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
|
||||
def tests(controller_class)
|
||||
self.controller_class = controller_class
|
||||
end
|
||||
|
||||
def controller_class=(new_class)
|
||||
prepare_controller_class(new_class) if new_class
|
||||
write_inheritable_attribute(:controller_class, new_class)
|
||||
end
|
||||
|
||||
def controller_class
|
||||
if current_controller_class = read_inheritable_attribute(:controller_class)
|
||||
current_controller_class
|
||||
else
|
||||
self.controller_class = determine_default_controller_class(name)
|
||||
end
|
||||
end
|
||||
|
||||
def determine_default_controller_class(name)
|
||||
name.sub(/Test$/, '').constantize
|
||||
rescue NameError
|
||||
nil
|
||||
end
|
||||
|
||||
def prepare_controller_class(new_class)
|
||||
new_class.send :include, RaiseActionExceptions
|
||||
end
|
||||
end
|
||||
|
||||
def setup_controller_request_and_response
|
||||
@request = TestRequest.new
|
||||
@response = TestResponse.new
|
||||
|
||||
if klass = self.class.controller_class
|
||||
@controller ||= klass.new rescue nil
|
||||
end
|
||||
|
||||
@request.env.delete('PATH_INFO')
|
||||
|
||||
if @controller
|
||||
@controller.request = @request
|
||||
@controller.params = {}
|
||||
end
|
||||
end
|
||||
|
||||
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
|
||||
def rescue_action_in_public!
|
||||
@request.remote_addr = '208.77.188.166' # example.com
|
||||
end
|
||||
|
||||
private
|
||||
def build_request_uri(action, parameters)
|
||||
unless @request.env["PATH_INFO"]
|
||||
options = @controller.__send__(:url_options).merge(parameters)
|
||||
options.update(
|
||||
:only_path => true,
|
||||
:action => action,
|
||||
:relative_url_root => nil,
|
||||
:_path_segments => @request.symbolized_path_parameters)
|
||||
|
||||
url, query_string = @routes.url_for(options).split("?", 2)
|
||||
|
||||
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
|
||||
@request.env["PATH_INFO"] = url
|
||||
@request.env["QUERY_STRING"] = query_string || ""
|
||||
end
|
||||
end
|
||||
end
|
||||
include Behavior
|
||||
end
|
||||
end
|
||||
|
||||
@@ -128,7 +128,7 @@ module ActionDispatch
|
||||
when String
|
||||
options
|
||||
when nil, Hash
|
||||
_router.url_for(url_options.merge(options || {}))
|
||||
_router.url_for(url_options.merge((options || {}).symbolize_keys))
|
||||
else
|
||||
polymorphic_url(options)
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ require 'active_support/core_ext/object/blank'
|
||||
module ActionView
|
||||
ActiveSupport.on_load(:action_view) do
|
||||
class ActionView::Base
|
||||
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
|
||||
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
|
||||
cattr_accessor :field_error_proc
|
||||
end
|
||||
end
|
||||
|
||||
@@ -102,7 +102,7 @@ module ActionView
|
||||
escape = true
|
||||
options
|
||||
when Hash
|
||||
options = { :only_path => options[:host].nil? }.update(options.to_hash.symbolize_keys)
|
||||
options = { :only_path => options[:host].nil? }.update(options.symbolize_keys)
|
||||
escape = options.key?(:escape) ? options.delete(:escape) : false
|
||||
super
|
||||
when :back
|
||||
|
||||
@@ -31,8 +31,8 @@ module ActionView
|
||||
include ActionController::PolymorphicRoutes
|
||||
include ActionController::RecordIdentifier
|
||||
|
||||
include AbstractController::Helpers
|
||||
include ActionView::Helpers
|
||||
include ActionController::Helpers
|
||||
|
||||
class_inheritable_accessor :helper_class
|
||||
attr_accessor :controller, :output_buffer, :rendered
|
||||
|
||||
@@ -143,6 +143,12 @@ class BasicController
|
||||
end
|
||||
end
|
||||
|
||||
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@routes = SharedTestRoutes
|
||||
end
|
||||
end
|
||||
|
||||
class ActionController::IntegrationTest < ActiveSupport::TestCase
|
||||
def self.build_app(routes = nil)
|
||||
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
|
||||
@@ -275,4 +281,4 @@ module ActionController
|
||||
class Base
|
||||
include SharedTestRoutes.url_helpers
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# encoding: utf-8
|
||||
#--
|
||||
# Copyright (c) 2006 Assaf Arkin (http://labnotes.org)
|
||||
# Under MIT and/or CC By license.
|
||||
@@ -347,7 +348,6 @@ class AssertSelectTest < ActionController::TestCase
|
||||
assert_select str, :text => "\343\203\201\343\202\261\343\203\203\343\203\210"
|
||||
assert_select str, "\343\203\201\343\202\261\343\203\203\343\203\210"
|
||||
if str.respond_to?(:force_encoding)
|
||||
str.force_encoding(Encoding::UTF_8)
|
||||
assert_select str, /\343\203\201..\343\203\210/u
|
||||
assert_raise(Assertion) { assert_select str, /\343\203\201.\343\203\210/u }
|
||||
else
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require 'abstract_unit'
|
||||
require 'rbconfig'
|
||||
|
||||
# The view_paths array must be set on Base and not LayoutTest so that LayoutTest's inherited
|
||||
# method has access to the view_paths array when looking for a layout to automatically assign.
|
||||
@@ -209,7 +210,7 @@ class LayoutStatusIsRenderedTest < ActionController::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
unless RUBY_PLATFORM =~ /mswin|mingw/
|
||||
unless Config::CONFIG['host_os'] =~ /mswin|mingw/
|
||||
class LayoutSymlinkedTest < LayoutTest
|
||||
layout "symlinked/symlinked_layout"
|
||||
end
|
||||
|
||||
@@ -3,6 +3,14 @@ require 'controller/fake_models'
|
||||
require 'pathname'
|
||||
|
||||
class RenderJsonTest < ActionController::TestCase
|
||||
class JsonRenderable
|
||||
def as_json(options={})
|
||||
hash = { :a => :b, :c => :d, :e => :f }
|
||||
hash.except!(*options[:except]) if options[:except]
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
class TestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
@@ -37,6 +45,10 @@ class RenderJsonTest < ActionController::TestCase
|
||||
def render_json_with_render_to_string
|
||||
render :json => {:hello => render_to_string(:partial => 'partial')}
|
||||
end
|
||||
|
||||
def render_json_with_extra_options
|
||||
render :json => JsonRenderable.new, :except => [:c, :e]
|
||||
end
|
||||
end
|
||||
|
||||
tests TestController
|
||||
@@ -91,4 +103,10 @@ class RenderJsonTest < ActionController::TestCase
|
||||
assert_equal '{"hello":"partial html"}', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_forwards_extra_options
|
||||
get :render_json_with_extra_options
|
||||
assert_equal '{"a":"b"}', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,13 @@ require 'controller/fake_models'
|
||||
require 'pathname'
|
||||
|
||||
class RenderXmlTest < ActionController::TestCase
|
||||
class XmlRenderable
|
||||
def to_xml(options)
|
||||
options[:root] ||= "i-am-xml"
|
||||
"<#{options[:root]}/>"
|
||||
end
|
||||
end
|
||||
|
||||
class TestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
@@ -20,13 +27,7 @@ class RenderXmlTest < ActionController::TestCase
|
||||
end
|
||||
|
||||
def render_with_to_xml
|
||||
to_xmlable = Class.new do
|
||||
def to_xml
|
||||
"<i-am-xml/>"
|
||||
end
|
||||
end.new
|
||||
|
||||
render :xml => to_xmlable
|
||||
render :xml => XmlRenderable.new
|
||||
end
|
||||
|
||||
def formatted_xml_erb
|
||||
@@ -35,6 +36,10 @@ class RenderXmlTest < ActionController::TestCase
|
||||
def render_xml_with_custom_content_type
|
||||
render :xml => "<blah/>", :content_type => "application/atomsvc+xml"
|
||||
end
|
||||
|
||||
def render_xml_with_custom_options
|
||||
render :xml => XmlRenderable.new, :root => "i-am-THE-xml"
|
||||
end
|
||||
end
|
||||
|
||||
tests TestController
|
||||
@@ -58,6 +63,11 @@ class RenderXmlTest < ActionController::TestCase
|
||||
assert_equal "<i-am-xml/>", @response.body
|
||||
end
|
||||
|
||||
def test_rendering_xml_should_call_to_xml_with_extra_options
|
||||
get :render_xml_with_custom_options
|
||||
assert_equal "<i-am-THE-xml/>", @response.body
|
||||
end
|
||||
|
||||
def test_rendering_with_object_location_should_set_header_with_url_for
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
|
||||
@@ -25,7 +25,7 @@ class SendFileController < ActionController::Base
|
||||
end
|
||||
|
||||
def multibyte_text_data
|
||||
send_data("Кирилица\n祝您好運", options)
|
||||
send_data("Кирилица\n祝您好運.", options)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -128,7 +128,7 @@ class SendFileTest < ActionController::TestCase
|
||||
|
||||
assert_equal 'image/png', @controller.content_type
|
||||
end
|
||||
|
||||
|
||||
|
||||
def test_send_file_headers_with_bad_symbol
|
||||
options = {
|
||||
|
||||
@@ -257,10 +257,24 @@ module AbstractController
|
||||
assert_equal second_class.default_url_options[:host], second_host
|
||||
end
|
||||
|
||||
def test_with_stringified_keys
|
||||
assert_equal("/c", W.new.url_for('controller' => 'c', 'only_path' => true))
|
||||
assert_equal("/c/a", W.new.url_for('controller' => 'c', 'action' => 'a', 'only_path' => true))
|
||||
end
|
||||
|
||||
def test_with_hash_with_indifferent_access
|
||||
W.default_url_options[:controller] = 'd'
|
||||
W.default_url_options[:only_path] = false
|
||||
assert_equal("/c", W.new.url_for(HashWithIndifferentAccess.new('controller' => 'c', 'only_path' => true)))
|
||||
|
||||
W.default_url_options[:action] = 'b'
|
||||
assert_equal("/c/a", W.new.url_for(HashWithIndifferentAccess.new('controller' => 'c', 'action' => 'a', 'only_path' => true)))
|
||||
end
|
||||
|
||||
private
|
||||
def extract_params(url)
|
||||
url.split('?', 2).last.split('&').sort
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -237,8 +237,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
|
||||
|
||||
AltRoutes = ActionDispatch::Routing::RouteSet.new(AltRequest)
|
||||
AltRoutes.draw do
|
||||
get "/" => XHeader.new, :constraints => {:x_header => /HEADER/}
|
||||
get "/" => AltApp.new
|
||||
get "/" => TestRoutingMapper::TestAltApp::XHeader.new, :constraints => {:x_header => /HEADER/}
|
||||
get "/" => TestRoutingMapper::TestAltApp::AltApp.new
|
||||
end
|
||||
|
||||
def app
|
||||
@@ -1000,6 +1000,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
def test_assert_recognizes_account_overview
|
||||
with_test_routes do
|
||||
assert_recognizes({:controller => "account", :action => "overview"}, "/account/overview")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def with_test_routes
|
||||
yield
|
||||
|
||||
@@ -27,14 +27,14 @@ class ActiveModelHelperTest < ActionView::TestCase
|
||||
|
||||
def test_text_area_with_errors
|
||||
assert_dom_equal(
|
||||
%(<div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div>),
|
||||
%(<div class="field_with_errors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div>),
|
||||
text_area("post", "body")
|
||||
)
|
||||
end
|
||||
|
||||
def test_text_field_with_errors
|
||||
assert_dom_equal(
|
||||
%(<div class="fieldWithErrors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /></div>),
|
||||
%(<div class="field_with_errors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /></div>),
|
||||
text_field("post", "author_name")
|
||||
)
|
||||
end
|
||||
@@ -42,11 +42,11 @@ class ActiveModelHelperTest < ActionView::TestCase
|
||||
def test_field_error_proc
|
||||
old_proc = ActionView::Base.field_error_proc
|
||||
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
|
||||
%(<div class=\"fieldWithErrors\">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>).html_safe
|
||||
%(<div class=\"field_with_errors\">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>).html_safe
|
||||
end
|
||||
|
||||
assert_dom_equal(
|
||||
%(<div class="fieldWithErrors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /> <span class="error">can't be empty</span></div>),
|
||||
%(<div class="field_with_errors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /> <span class="error">can't be empty</span></div>),
|
||||
text_field("post", "author_name")
|
||||
)
|
||||
ensure
|
||||
|
||||
@@ -3,9 +3,6 @@ require 'abstract_unit'
|
||||
class FormTagHelperTest < ActionView::TestCase
|
||||
tests ActionView::Helpers::FormTagHelper
|
||||
|
||||
# include ActiveSupport::Configurable
|
||||
# DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG
|
||||
|
||||
def setup
|
||||
super
|
||||
@controller = BasicController.new
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# encoding: us-ascii
|
||||
require 'abstract_unit'
|
||||
require 'testing_sandbox'
|
||||
begin
|
||||
|
||||
@@ -17,6 +17,7 @@ en:
|
||||
too_short: "is too short (minimum is {{count}} characters)"
|
||||
wrong_length: "is the wrong length (should be {{count}} characters)"
|
||||
not_a_number: "is not a number"
|
||||
not_an_integer: "must be an integer"
|
||||
greater_than: "must be greater than {{count}}"
|
||||
greater_than_or_equal_to: "must be greater than or equal to {{count}}"
|
||||
equal_to: "must be equal to {{count}}"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require 'active_support/core_ext/array/wrap'
|
||||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
require 'active_support/core_ext/hash/conversions'
|
||||
require 'active_support/core_ext/hash/slice'
|
||||
|
||||
module ActiveModel
|
||||
module Serializers
|
||||
@@ -12,8 +13,10 @@ module ActiveModel
|
||||
class Attribute #:nodoc:
|
||||
attr_reader :name, :value, :type
|
||||
|
||||
def initialize(name, serializable)
|
||||
def initialize(name, serializable, raw_value=nil)
|
||||
@name, @serializable = name, serializable
|
||||
@raw_value = raw_value || @serializable.send(name)
|
||||
|
||||
@type = compute_type
|
||||
@value = compute_value
|
||||
end
|
||||
@@ -51,20 +54,17 @@ module ActiveModel
|
||||
|
||||
protected
|
||||
def compute_type
|
||||
value = @serializable.send(name)
|
||||
type = Hash::XML_TYPE_NAMES[value.class.name]
|
||||
type ||= :string if value.respond_to?(:to_str)
|
||||
type = Hash::XML_TYPE_NAMES[@raw_value.class.name]
|
||||
type ||= :string if @raw_value.respond_to?(:to_str)
|
||||
type ||= :yaml
|
||||
type
|
||||
end
|
||||
|
||||
def compute_value
|
||||
value = @serializable.send(name)
|
||||
|
||||
if formatter = Hash::XML_FORMATTING[type.to_s]
|
||||
value ? formatter.call(value) : nil
|
||||
@raw_value ? formatter.call(@raw_value) : nil
|
||||
else
|
||||
value
|
||||
@raw_value
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -72,7 +72,7 @@ module ActiveModel
|
||||
class MethodAttribute < Attribute #:nodoc:
|
||||
protected
|
||||
def compute_type
|
||||
Hash::XML_TYPE_NAMES[@serializable.send(name).class.name] || :string
|
||||
Hash::XML_TYPE_NAMES[@raw_value.class.name] || :string
|
||||
end
|
||||
end
|
||||
|
||||
@@ -92,25 +92,24 @@ module ActiveModel
|
||||
# then because <tt>:except</tt> is set to a default value, the second
|
||||
# level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
|
||||
# <tt>:only</tt> is set, always delete <tt>:except</tt>.
|
||||
def serializable_attribute_names
|
||||
attribute_names = @serializable.attributes.keys.sort
|
||||
|
||||
def serializable_attributes_hash
|
||||
attributes = @serializable.attributes
|
||||
if options[:only].any?
|
||||
attribute_names &= options[:only]
|
||||
attributes.slice(*options[:only])
|
||||
elsif options[:except].any?
|
||||
attribute_names -= options[:except]
|
||||
attributes.except(*options[:except])
|
||||
else
|
||||
attributes
|
||||
end
|
||||
|
||||
attribute_names
|
||||
end
|
||||
|
||||
def serializable_attributes
|
||||
serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
|
||||
serializable_attributes_hash.map { |name, value| self.class::Attribute.new(name, @serializable, value) }
|
||||
end
|
||||
|
||||
def serializable_method_attributes
|
||||
Array.wrap(options[:methods]).inject([]) do |methods, name|
|
||||
methods << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
|
||||
methods << self.class::MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
|
||||
methods
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,11 +25,18 @@ module ActiveModel
|
||||
|
||||
return if options[:allow_nil] && raw_value.nil?
|
||||
|
||||
unless value = parse_raw_value(raw_value, options)
|
||||
unless value = parse_raw_value_as_a_number(raw_value)
|
||||
record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
|
||||
return
|
||||
end
|
||||
|
||||
if options[:only_integer]
|
||||
unless value = parse_raw_value_as_an_integer(raw_value)
|
||||
record.errors.add(attr_name, :not_an_integer, :value => raw_value, :default => options[:message])
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
options.slice(*CHECKS.keys).each do |option, option_value|
|
||||
case option
|
||||
when :odd, :even
|
||||
@@ -44,23 +51,23 @@ module ActiveModel
|
||||
record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def parse_raw_value(raw_value, options)
|
||||
if options[:only_integer]
|
||||
raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
|
||||
else
|
||||
begin
|
||||
Kernel.Float(raw_value)
|
||||
rescue ArgumentError, TypeError
|
||||
nil
|
||||
end
|
||||
def parse_raw_value_as_a_number(raw_value)
|
||||
begin
|
||||
Kernel.Float(raw_value)
|
||||
rescue ArgumentError, TypeError
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def parse_raw_value_as_an_integer(raw_value)
|
||||
raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
@@ -217,15 +217,15 @@ class I18nValidationTest < ActiveModel::TestCase
|
||||
|
||||
def test_validates_numericality_of_only_integer_generates_message
|
||||
Person.validates_numericality_of :title, :only_integer => true
|
||||
@person.title = 'a'
|
||||
@person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil})
|
||||
@person.title = '0.0'
|
||||
@person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => nil})
|
||||
@person.valid?
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message
|
||||
Person.validates_numericality_of :title, :only_integer => true, :message => 'custom'
|
||||
@person.title = 'a'
|
||||
@person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'})
|
||||
@person.title = '0.0'
|
||||
@person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => 'custom'})
|
||||
@person.valid?
|
||||
end
|
||||
|
||||
@@ -441,20 +441,20 @@ class I18nValidationTest < ActiveModel::TestCase
|
||||
# validates_numericality_of with :only_integer w/o mocha
|
||||
|
||||
def test_validates_numericality_of_only_integer_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_a_number => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}}
|
||||
I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_an_integer => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :errors => {:messages => {:not_an_integer => 'global message'}}
|
||||
|
||||
Person.validates_numericality_of :title, :only_integer => true
|
||||
@person.title = 'a'
|
||||
@person.title = '1.0'
|
||||
@person.valid?
|
||||
assert_equal ['custom message'], @person.errors[:title]
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_only_integer_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}}
|
||||
I18n.backend.store_translations 'en', :errors => {:messages => {:not_an_integer => 'global message'}}
|
||||
|
||||
Person.validates_numericality_of :title, :only_integer => true
|
||||
@person.title = 'a'
|
||||
@person.title = '1.0'
|
||||
@person.valid?
|
||||
assert_equal ['global message'], @person.errors[:title]
|
||||
end
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
|
||||
|
||||
* PostgreSQL: drop support for old postgres driver. Use pg 0.9.0 or later. [Jeremy Kemper]
|
||||
|
||||
* Observers can prevent records from saving by returning false, just like before_save and friends. #4087 [Mislav Marohnić]
|
||||
|
||||
|
||||
|
||||
@@ -1844,8 +1844,7 @@ module ActiveRecord #:nodoc:
|
||||
# user.is_admin? # => true
|
||||
def attributes=(new_attributes, guard_protected_attributes = true)
|
||||
return if new_attributes.nil?
|
||||
attributes = new_attributes.dup
|
||||
attributes.stringify_keys!
|
||||
attributes = new_attributes.stringify_keys
|
||||
|
||||
multi_parameter_attributes = []
|
||||
attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
|
||||
|
||||
@@ -13,12 +13,12 @@ module ActiveRecord
|
||||
when String, ActiveSupport::Multibyte::Chars
|
||||
value = value.to_s
|
||||
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
||||
"#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
|
||||
"'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
|
||||
elsif column && [:integer, :float].include?(column.type)
|
||||
value = column.type == :integer ? value.to_i : value.to_f
|
||||
value.to_s
|
||||
else
|
||||
"#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
|
||||
"'#{quote_string(value)}'" # ' (for ruby-mode)
|
||||
end
|
||||
when NilClass then "NULL"
|
||||
when TrueClass then (column && column.type == :integer ? '1' : quoted_true)
|
||||
@@ -30,7 +30,7 @@ module ActiveRecord
|
||||
if value.acts_like?(:date) || value.acts_like?(:time)
|
||||
"'#{quoted_date(value)}'"
|
||||
else
|
||||
"#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
|
||||
"'#{quote_string(value.to_yaml)}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -67,10 +67,6 @@ module ActiveRecord
|
||||
value
|
||||
end.to_s(:db)
|
||||
end
|
||||
|
||||
def quoted_string_prefix
|
||||
''
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,26 +2,12 @@ require 'active_record/connection_adapters/abstract_adapter'
|
||||
require 'active_support/core_ext/kernel/requires'
|
||||
require 'active_support/core_ext/object/blank'
|
||||
|
||||
begin
|
||||
require_library_or_gem 'pg'
|
||||
rescue LoadError => e
|
||||
begin
|
||||
require_library_or_gem 'postgres'
|
||||
class PGresult
|
||||
alias_method :nfields, :num_fields unless self.method_defined?(:nfields)
|
||||
alias_method :ntuples, :num_tuples unless self.method_defined?(:ntuples)
|
||||
alias_method :ftype, :type unless self.method_defined?(:ftype)
|
||||
alias_method :cmd_tuples, :cmdtuples unless self.method_defined?(:cmd_tuples)
|
||||
end
|
||||
rescue LoadError
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveRecord
|
||||
class Base
|
||||
# Establishes a connection to the database that's used by all Active Record objects
|
||||
def self.postgresql_connection(config) # :nodoc:
|
||||
require 'pg'
|
||||
|
||||
config = config.symbolize_keys
|
||||
host = config[:host]
|
||||
port = config[:port] || 5432
|
||||
@@ -277,20 +263,12 @@ module ActiveRecord
|
||||
true
|
||||
end
|
||||
|
||||
# Does PostgreSQL support standard conforming strings?
|
||||
def supports_standard_conforming_strings?
|
||||
# Temporarily set the client message level above error to prevent unintentional
|
||||
# error messages in the logs when working on a PostgreSQL database server that
|
||||
# does not support standard conforming strings.
|
||||
client_min_messages_old = client_min_messages
|
||||
self.client_min_messages = 'panic'
|
||||
|
||||
# postgres-pr does not raise an exception when client_min_messages is set higher
|
||||
# than error and "SHOW standard_conforming_strings" fails, but returns an empty
|
||||
# PGresult instead.
|
||||
has_support = query('SHOW standard_conforming_strings')[0][0] rescue false
|
||||
self.client_min_messages = client_min_messages_old
|
||||
has_support
|
||||
# Enable standard-conforming strings if available.
|
||||
def set_standard_conforming_strings
|
||||
old, self.client_min_messages = client_min_messages, 'panic'
|
||||
execute('SET standard_conforming_strings = on') rescue nil
|
||||
ensure
|
||||
self.client_min_messages = old
|
||||
end
|
||||
|
||||
def supports_insert_with_returning?
|
||||
@@ -314,85 +292,23 @@ module ActiveRecord
|
||||
# QUOTING ==================================================
|
||||
|
||||
# Escapes binary strings for bytea input to the database.
|
||||
def escape_bytea(original_value)
|
||||
if @connection.respond_to?(:escape_bytea)
|
||||
self.class.instance_eval do
|
||||
define_method(:escape_bytea) do |value|
|
||||
@connection.escape_bytea(value) if value
|
||||
end
|
||||
end
|
||||
elsif PGconn.respond_to?(:escape_bytea)
|
||||
self.class.instance_eval do
|
||||
define_method(:escape_bytea) do |value|
|
||||
PGconn.escape_bytea(value) if value
|
||||
end
|
||||
end
|
||||
else
|
||||
self.class.instance_eval do
|
||||
define_method(:escape_bytea) do |value|
|
||||
if value
|
||||
result = ''
|
||||
value.each_byte { |c| result << sprintf('\\\\%03o', c) }
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
escape_bytea(original_value)
|
||||
def escape_bytea(value)
|
||||
@connection.escape_bytea(value) if value
|
||||
end
|
||||
|
||||
# Unescapes bytea output from a database to the binary string it represents.
|
||||
# NOTE: This is NOT an inverse of escape_bytea! This is only to be used
|
||||
# on escaped binary output from database drive.
|
||||
def unescape_bytea(original_value)
|
||||
# In each case, check if the value actually is escaped PostgreSQL bytea output
|
||||
# or an unescaped Active Record attribute that was just written.
|
||||
if PGconn.respond_to?(:unescape_bytea)
|
||||
self.class.instance_eval do
|
||||
define_method(:unescape_bytea) do |value|
|
||||
if value =~ /\\\d{3}/
|
||||
PGconn.unescape_bytea(value)
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
self.class.instance_eval do
|
||||
define_method(:unescape_bytea) do |value|
|
||||
if value =~ /\\\d{3}/
|
||||
result = ''
|
||||
i, max = 0, value.size
|
||||
while i < max
|
||||
char = value[i]
|
||||
if char == ?\\
|
||||
if value[i+1] == ?\\
|
||||
char = ?\\
|
||||
i += 1
|
||||
else
|
||||
char = value[i+1..i+3].oct
|
||||
i += 3
|
||||
end
|
||||
end
|
||||
result << char
|
||||
i += 1
|
||||
end
|
||||
result
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
unescape_bytea(original_value)
|
||||
def unescape_bytea(value)
|
||||
@connection.unescape_bytea(value) if value
|
||||
end
|
||||
|
||||
# Quotes PostgreSQL-specific data types for SQL input.
|
||||
def quote(value, column = nil) #:nodoc:
|
||||
if value.kind_of?(String) && column && column.type == :binary
|
||||
"#{quoted_string_prefix}'#{escape_bytea(value)}'"
|
||||
"'#{escape_bytea(value)}'"
|
||||
elsif value.kind_of?(String) && column && column.sql_type == 'xml'
|
||||
"xml E'#{quote_string(value)}'"
|
||||
"xml '#{quote_string(value)}'"
|
||||
elsif value.kind_of?(Numeric) && column && column.sql_type == 'money'
|
||||
# Not truly string input, so doesn't require (or allow) escape string syntax.
|
||||
"'#{value.to_s}'"
|
||||
@@ -408,28 +324,9 @@ module ActiveRecord
|
||||
end
|
||||
end
|
||||
|
||||
# Quotes strings for use in SQL input in the postgres driver for better performance.
|
||||
def quote_string(original_value) #:nodoc:
|
||||
if @connection.respond_to?(:escape)
|
||||
self.class.instance_eval do
|
||||
define_method(:quote_string) do |s|
|
||||
@connection.escape(s)
|
||||
end
|
||||
end
|
||||
elsif PGconn.respond_to?(:escape)
|
||||
self.class.instance_eval do
|
||||
define_method(:quote_string) do |s|
|
||||
PGconn.escape(s)
|
||||
end
|
||||
end
|
||||
else
|
||||
# There are some incorrectly compiled postgres drivers out there
|
||||
# that don't define PGconn.escape.
|
||||
self.class.instance_eval do
|
||||
remove_method(:quote_string)
|
||||
end
|
||||
end
|
||||
quote_string(original_value)
|
||||
# Quotes strings for use in SQL input.
|
||||
def quote_string(s) #:nodoc:
|
||||
@connection.escape(s)
|
||||
end
|
||||
|
||||
# Checks the following cases:
|
||||
@@ -1005,22 +902,11 @@ module ActiveRecord
|
||||
# Ignore async_exec and async_query when using postgres-pr.
|
||||
@async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec)
|
||||
|
||||
# Use escape string syntax if available. We cannot do this lazily when encountering
|
||||
# the first string, because that could then break any transactions in progress.
|
||||
# See: http://www.postgresql.org/docs/current/static/runtime-config-compatible.html
|
||||
# If PostgreSQL doesn't know the standard_conforming_strings parameter then it doesn't
|
||||
# support escape string syntax. Don't override the inherited quoted_string_prefix.
|
||||
if supports_standard_conforming_strings?
|
||||
self.class.instance_eval do
|
||||
define_method(:quoted_string_prefix) { 'E' }
|
||||
end
|
||||
end
|
||||
|
||||
# Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
|
||||
# PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
|
||||
# should know about this but can't detect it there, so deal with it here.
|
||||
PostgreSQLColumn.money_precision =
|
||||
(postgresql_version >= 80300) ? 19 : 10
|
||||
PostgreSQLColumn.money_precision = (postgresql_version >= 80300) ? 19 : 10
|
||||
|
||||
configure_connection
|
||||
end
|
||||
|
||||
@@ -1036,7 +922,10 @@ module ActiveRecord
|
||||
end
|
||||
self.client_min_messages = @config[:min_messages] if @config[:min_messages]
|
||||
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
|
||||
|
||||
|
||||
# Use standard-conforming strings if available so we don't have to do the E'...' dance.
|
||||
set_standard_conforming_strings
|
||||
|
||||
# If using ActiveRecord's time zone support configure the connection to return
|
||||
# TIMESTAMP WITH ZONE types in UTC.
|
||||
execute("SET time zone 'UTC'") if ActiveRecord::Base.default_timezone == :utc
|
||||
|
||||
@@ -3,8 +3,9 @@ require 'yaml'
|
||||
require 'csv'
|
||||
require 'zlib'
|
||||
require 'active_support/dependencies'
|
||||
require 'active_support/core_ext/logger'
|
||||
require 'active_support/core_ext/array/wrap'
|
||||
require 'active_support/core_ext/object/blank'
|
||||
require 'active_support/core_ext/logger'
|
||||
|
||||
if RUBY_VERSION < '1.9'
|
||||
module YAML #:nodoc:
|
||||
@@ -492,6 +493,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
|
||||
|
||||
def self.create_fixtures(fixtures_directory, table_names, class_names = {})
|
||||
table_names = [table_names].flatten.map { |n| n.to_s }
|
||||
table_names.each { |n| class_names[n.tr('/', '_').to_sym] = n.classify if n.include?('/') }
|
||||
connection = block_given? ? yield : ActiveRecord::Base.connection
|
||||
|
||||
table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) }
|
||||
@@ -502,7 +504,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
|
||||
fixtures_map = {}
|
||||
|
||||
fixtures = table_names_to_fetch.map do |table_name|
|
||||
fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
|
||||
fixtures_map[table_name] = Fixtures.new(connection, table_name.tr('/', '_'), class_names[table_name.tr('/', '_').to_sym], File.join(fixtures_directory, table_name))
|
||||
end
|
||||
|
||||
all_loaded_fixtures.update(fixtures_map)
|
||||
@@ -836,8 +838,8 @@ module ActiveRecord
|
||||
|
||||
def fixtures(*table_names)
|
||||
if table_names.first == :all
|
||||
table_names = Dir["#{fixture_path}/*.yml"] + Dir["#{fixture_path}/*.csv"]
|
||||
table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') }
|
||||
table_names = Dir["#{fixture_path}/**/*.{yml,csv}"]
|
||||
table_names.map! { |f| f[(fixture_path.size + 1)..-5] }
|
||||
else
|
||||
table_names = table_names.flatten.map { |n| n.to_s }
|
||||
end
|
||||
@@ -868,9 +870,9 @@ module ActiveRecord
|
||||
end
|
||||
|
||||
def setup_fixture_accessors(table_names = nil)
|
||||
table_names = [table_names] if table_names && !table_names.respond_to?(:each)
|
||||
(table_names || fixture_table_names).each do |table_name|
|
||||
table_name = table_name.to_s.tr('.', '_')
|
||||
table_names = Array.wrap(table_names || fixture_table_names)
|
||||
table_names.each do |table_name|
|
||||
table_name = table_name.to_s.tr('./', '_')
|
||||
|
||||
define_method(table_name) do |*fixtures|
|
||||
force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
|
||||
|
||||
@@ -258,8 +258,8 @@ namespace :db do
|
||||
base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
|
||||
fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir
|
||||
|
||||
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file|
|
||||
Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))
|
||||
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir["#{fixtures_dir}/**/*.{yml,csv}"]).each do |fixture_file|
|
||||
Fixtures.create_fixtures(fixtures_dir, fixture_file[(fixtures_dir.size + 1)..-5])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -182,17 +182,6 @@ module ActiveRecord #:nodoc:
|
||||
options[:except] |= Array.wrap(@serializable.class.inheritance_column)
|
||||
end
|
||||
|
||||
def serializable_attributes
|
||||
serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
|
||||
end
|
||||
|
||||
def serializable_method_attributes
|
||||
Array.wrap(options[:methods]).inject([]) do |method_attributes, name|
|
||||
method_attributes << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
|
||||
method_attributes
|
||||
end
|
||||
end
|
||||
|
||||
def add_associations(association, records, opts)
|
||||
if records.is_a?(Enumerable)
|
||||
tag = reformat_name(association.to_s)
|
||||
|
||||
@@ -566,8 +566,8 @@ class FinderTest < ActiveRecord::TestCase
|
||||
end
|
||||
|
||||
def test_string_sanitation
|
||||
assert_not_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
|
||||
assert_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something; select table'", ActiveRecord::Base.sanitize("something; select table")
|
||||
assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
|
||||
assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
|
||||
end
|
||||
|
||||
def test_count
|
||||
|
||||
@@ -16,6 +16,9 @@ require 'models/treasure'
|
||||
require 'models/matey'
|
||||
require 'models/ship'
|
||||
require 'models/book'
|
||||
require 'models/admin'
|
||||
require 'models/admin/account'
|
||||
require 'models/admin/user'
|
||||
|
||||
class FixturesTest < ActiveRecord::TestCase
|
||||
self.use_instantiated_fixtures = true
|
||||
@@ -507,7 +510,7 @@ class FasterFixturesTest < ActiveRecord::TestCase
|
||||
end
|
||||
|
||||
class FoxyFixturesTest < ActiveRecord::TestCase
|
||||
fixtures :parrots, :parrots_pirates, :pirates, :treasures, :mateys, :ships, :computers, :developers
|
||||
fixtures :parrots, :parrots_pirates, :pirates, :treasures, :mateys, :ships, :computers, :developers, :"admin/accounts", :"admin/users"
|
||||
|
||||
def test_identifies_strings
|
||||
assert_equal(Fixtures.identify("foo"), Fixtures.identify("foo"))
|
||||
@@ -629,6 +632,11 @@ class FoxyFixturesTest < ActiveRecord::TestCase
|
||||
assert_kind_of DeadParrot, parrots(:polly)
|
||||
assert_equal pirates(:blackbeard), parrots(:polly).killer
|
||||
end
|
||||
|
||||
def test_namespaced_models
|
||||
assert admin_accounts(:signals37).users.include?(admin_users(:david))
|
||||
assert_equal 2, admin_accounts(:signals37).users.size
|
||||
end
|
||||
end
|
||||
|
||||
class ActiveSupportSubclassWithFixturesTest < ActiveRecord::TestCase
|
||||
|
||||
2
activerecord/test/fixtures/admin/accounts.yml
vendored
Normal file
2
activerecord/test/fixtures/admin/accounts.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
signals37:
|
||||
name: 37signals
|
||||
7
activerecord/test/fixtures/admin/users.yml
vendored
Normal file
7
activerecord/test/fixtures/admin/users.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
david:
|
||||
name: David
|
||||
account: signals37
|
||||
|
||||
jamis:
|
||||
name: Jamis
|
||||
account: signals37
|
||||
5
activerecord/test/models/admin.rb
Normal file
5
activerecord/test/models/admin.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
module Admin
|
||||
def self.table_name_prefix
|
||||
'admin_'
|
||||
end
|
||||
end
|
||||
3
activerecord/test/models/admin/account.rb
Normal file
3
activerecord/test/models/admin/account.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
class Admin::Account < ActiveRecord::Base
|
||||
has_many :users
|
||||
end
|
||||
3
activerecord/test/models/admin/user.rb
Normal file
3
activerecord/test/models/admin/user.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
class Admin::User < ActiveRecord::Base
|
||||
belongs_to :account
|
||||
end
|
||||
@@ -26,6 +26,15 @@ ActiveRecord::Schema.define do
|
||||
t.integer :credit_limit
|
||||
end
|
||||
|
||||
create_table :admin_accounts, :force => true do |t|
|
||||
t.string :name
|
||||
end
|
||||
|
||||
create_table :admin_users, :force => true do |t|
|
||||
t.string :name
|
||||
t.references :account
|
||||
end
|
||||
|
||||
create_table :audit_logs, :force => true do |t|
|
||||
t.column :message, :string, :null=>false
|
||||
t.column :developer_id, :integer, :null=>false
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
|
||||
|
||||
* JSON: set Base.include_root_in_json = true to include a root value in the JSON: {"post": {"title": ...}}. Mirrors the Active Record option. [Santiago Pastorino]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
|
||||
|
||||
* No changes
|
||||
|
||||
@@ -251,9 +251,6 @@ module ActiveResource
|
||||
# The logger for diagnosing and tracing Active Resource calls.
|
||||
cattr_accessor :logger
|
||||
|
||||
# Controls the top-level behavior of JSON serialization
|
||||
cattr_accessor :include_root_in_json, :instance_writer => false
|
||||
|
||||
class << self
|
||||
# Creates a schema for this resource - setting the attributes that are
|
||||
# known prior to fetching an instance from the remote system.
|
||||
@@ -1179,79 +1176,11 @@ module ActiveResource
|
||||
!new? && self.class.exists?(to_param, :params => prefix_options)
|
||||
end
|
||||
|
||||
# Converts the resource to an XML string representation.
|
||||
#
|
||||
# ==== Options
|
||||
# The +options+ parameter is handed off to the +to_xml+ method on each
|
||||
# attribute, so it has the same options as the +to_xml+ methods in
|
||||
# Active Support.
|
||||
#
|
||||
# * <tt>:indent</tt> - Set the indent level for the XML output (default is +2+).
|
||||
# * <tt>:dasherize</tt> - Boolean option to determine whether or not element names should
|
||||
# replace underscores with dashes (default is <tt>false</tt>).
|
||||
# * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
|
||||
# that generates the XML declaration (default is <tt>false</tt>).
|
||||
#
|
||||
# ==== Examples
|
||||
# my_group = SubsidiaryGroup.find(:first)
|
||||
# my_group.to_xml
|
||||
# # => <?xml version="1.0" encoding="UTF-8"?>
|
||||
# # <subsidiary_group> [...] </subsidiary_group>
|
||||
#
|
||||
# my_group.to_xml(:dasherize => true)
|
||||
# # => <?xml version="1.0" encoding="UTF-8"?>
|
||||
# # <subsidiary-group> [...] </subsidiary-group>
|
||||
#
|
||||
# my_group.to_xml(:skip_instruct => true)
|
||||
# # => <subsidiary_group> [...] </subsidiary_group>
|
||||
def to_xml(options={})
|
||||
attributes.to_xml({:root => self.class.element_name}.merge(options))
|
||||
end
|
||||
|
||||
# Coerces to a hash for JSON encoding.
|
||||
#
|
||||
# ==== Options
|
||||
# The +options+ are passed to the +to_json+ method on each
|
||||
# attribute, so the same options as the +to_json+ methods in
|
||||
# Active Support.
|
||||
#
|
||||
# * <tt>:only</tt> - Only include the specified attribute or list of
|
||||
# attributes in the serialized output. Attribute names must be specified
|
||||
# as strings.
|
||||
# * <tt>:except</tt> - Do not include the specified attribute or list of
|
||||
# attributes in the serialized output. Attribute names must be specified
|
||||
# as strings.
|
||||
#
|
||||
# ==== Examples
|
||||
# person = Person.new(:first_name => "Jim", :last_name => "Smith")
|
||||
# person.to_json
|
||||
# # => {"first_name": "Jim", "last_name": "Smith"}
|
||||
#
|
||||
# person.to_json(:only => ["first_name"])
|
||||
# # => {"first_name": "Jim"}
|
||||
#
|
||||
# person.to_json(:except => ["first_name"])
|
||||
# # => {"last_name": "Smith"}
|
||||
def as_json(options = nil)
|
||||
attributes.as_json(options)
|
||||
end
|
||||
|
||||
# Returns the serialized string representation of the resource in the configured
|
||||
# serialization format specified in ActiveResource::Base.format. The options
|
||||
# applicable depend on the configured encoding format.
|
||||
def encode(options={})
|
||||
case self.class.format
|
||||
when ActiveResource::Formats::XmlFormat
|
||||
self.class.format.encode(attributes, {:root => self.class.element_name}.merge(options))
|
||||
when ActiveResource::Formats::JsonFormat
|
||||
if ActiveResource::Base.include_root_in_json
|
||||
self.class.format.encode({self.class.element_name => attributes}, options)
|
||||
else
|
||||
self.class.format.encode(attributes, options)
|
||||
end
|
||||
else
|
||||
self.class.format.encode(attributes, options)
|
||||
end
|
||||
send("to_#{self.class.format.extension}", options)
|
||||
end
|
||||
|
||||
# A method to \reload the attributes of this object from the remote web service.
|
||||
@@ -1475,5 +1404,7 @@ module ActiveResource
|
||||
class Base
|
||||
extend ActiveModel::Naming
|
||||
include CustomMethods, Observing, Validations
|
||||
include ActiveModel::Serializers::JSON
|
||||
include ActiveModel::Serializers::Xml
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1015,8 +1015,7 @@ class BaseTest < Test::Unit::TestCase
|
||||
assert xml.include?('<id type="integer">1</id>')
|
||||
end
|
||||
|
||||
|
||||
def test_to_json_including_root
|
||||
def test_to_json
|
||||
Person.include_root_in_json = true
|
||||
Person.format = :json
|
||||
joe = Person.find(6)
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
|
||||
|
||||
* JSON: encode objects that don't have a native JSON representation using to_hash, if available, instead of instance_values (the old fallback) or to_s (other encoders' default). Encode BigDecimal and Regexp encode as strings to conform with other encoders. Try to transcode non-UTF-8 strings. [Jeremy Kemper]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
|
||||
|
||||
* HashWithIndifferentAccess: remove inherited symbolize_keys! since its keys are always strings. [Santiago Pastorino]
|
||||
|
||||
* Improve transliteration quality. #4374 [Norman Clarke]
|
||||
|
||||
* Speed up and add Ruby 1.9 support for ActiveSupport::Multibyte::Chars#tidy_bytes. #4350 [Norman Clarke]
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
require "active_support/concern"
|
||||
require 'active_support/concern'
|
||||
require 'active_support/ordered_options'
|
||||
require 'active_support/core_ext/kernel/singleton_class'
|
||||
require 'active_support/core_ext/module/delegation'
|
||||
|
||||
module ActiveSupport
|
||||
module Configurable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
def get_config
|
||||
module_parts = name.split("::")
|
||||
modules = [Object]
|
||||
module_parts.each {|name| modules.push modules.last.const_get(name) }
|
||||
modules.reverse_each do |mod|
|
||||
return mod.const_get(:DEFAULT_CONFIG) if const_defined?(:DEFAULT_CONFIG)
|
||||
end
|
||||
{}
|
||||
end
|
||||
|
||||
def config
|
||||
self.config = get_config unless @config
|
||||
@config
|
||||
@config ||= ActiveSupport::InheritableOptions.new(superclass.respond_to?(:config) ? superclass.config : {})
|
||||
end
|
||||
|
||||
def config=(hash)
|
||||
@config = ActiveSupport::OrderedOptions.new
|
||||
hash.each do |key, value|
|
||||
@config[key] = value
|
||||
def configure
|
||||
yield config
|
||||
end
|
||||
|
||||
def config_accessor(*names)
|
||||
names.each do |name|
|
||||
code, line = <<-RUBY, __LINE__ + 1
|
||||
def #{name}; config.#{name}; end
|
||||
def #{name}=(value); config.#{name} = value; end
|
||||
RUBY
|
||||
|
||||
singleton_class.class_eval code, __FILE__, line
|
||||
class_eval code, __FILE__, line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def config
|
||||
self.class.config
|
||||
@config ||= ActiveSupport::InheritableOptions.new(self.class.config)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,4 @@
|
||||
require 'rbconfig'
|
||||
module Kernel
|
||||
# Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.
|
||||
#
|
||||
@@ -37,7 +38,7 @@ module Kernel
|
||||
# puts 'But this will'
|
||||
def silence_stream(stream)
|
||||
old_stream = stream.dup
|
||||
stream.reopen(RUBY_PLATFORM =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
|
||||
stream.reopen(Config::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
|
||||
stream.sync = true
|
||||
yield
|
||||
ensure
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# encoding: utf-8
|
||||
|
||||
if RUBY_VERSION >= '1.9'
|
||||
require 'uri'
|
||||
|
||||
str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
|
||||
str.force_encoding(Encoding::UTF_8) if str.respond_to?(:force_encoding)
|
||||
|
||||
parser = URI::Parser.new
|
||||
unless str == parser.unescape(parser.escape(str))
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'active_support/core_ext/hash/keys'
|
||||
|
||||
# This class has dubious semantics and we only have it so that
|
||||
# people can write params[:key] instead of params['key']
|
||||
# and they get the same value for both keys.
|
||||
@@ -112,7 +114,9 @@ module ActiveSupport
|
||||
end
|
||||
|
||||
def stringify_keys!; self end
|
||||
def symbolize_keys!; self end
|
||||
def stringify_keys; dup end
|
||||
undef :symbolize_keys!
|
||||
def symbolize_keys; to_hash.symbolize_keys end
|
||||
def to_options!; self end
|
||||
|
||||
# Convert to a Hash with String keys.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# encoding: utf-8
|
||||
require 'bigdecimal'
|
||||
require 'active_support/core_ext/array/wrap'
|
||||
require 'active_support/core_ext/hash/except'
|
||||
require 'active_support/core_ext/hash/slice'
|
||||
@@ -102,7 +103,9 @@ module ActiveSupport
|
||||
end
|
||||
|
||||
def escape(string)
|
||||
string = string.dup.force_encoding(::Encoding::BINARY) if string.respond_to?(:force_encoding)
|
||||
if string.respond_to?(:force_encoding)
|
||||
string = string.encode(::Encoding::UTF_8, undef: :replace).force_encoding(::Encoding::BINARY)
|
||||
end
|
||||
json = string.
|
||||
gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
|
||||
gsub(/([\xC0-\xDF][\x80-\xBF]|
|
||||
@@ -110,7 +113,9 @@ module ActiveSupport
|
||||
[\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
|
||||
s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
|
||||
}
|
||||
%("#{json}")
|
||||
json = %("#{json}")
|
||||
json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
|
||||
json
|
||||
end
|
||||
end
|
||||
|
||||
@@ -128,7 +133,13 @@ class Object
|
||||
ActiveSupport::JSON.encode(self, options)
|
||||
end
|
||||
|
||||
def as_json(options = nil) instance_values end #:nodoc:
|
||||
def as_json(options = nil) #:nodoc:
|
||||
if respond_to?(:to_hash)
|
||||
to_hash
|
||||
else
|
||||
instance_values
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# A string that returns itself as its JSON-encoded form.
|
||||
@@ -166,9 +177,12 @@ class Numeric
|
||||
def encode_json(encoder) to_s end #:nodoc:
|
||||
end
|
||||
|
||||
class BigDecimal
|
||||
def as_json(options = nil) to_s end #:nodoc:
|
||||
end
|
||||
|
||||
class Regexp
|
||||
def as_json(options = nil) self end #:nodoc:
|
||||
def encode_json(encoder) inspect end #:nodoc:
|
||||
def as_json(options = nil) to_s end #:nodoc:
|
||||
end
|
||||
|
||||
module Enumerable
|
||||
|
||||
@@ -72,8 +72,8 @@ module ActiveSupport #:nodoc:
|
||||
def self.codepoints_to_pattern(array_of_codepoints) #:nodoc:
|
||||
array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|')
|
||||
end
|
||||
UNICODE_TRAILERS_PAT = /(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+\Z/
|
||||
UNICODE_LEADERS_PAT = /\A(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+/
|
||||
UNICODE_TRAILERS_PAT = /(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+\Z/u
|
||||
UNICODE_LEADERS_PAT = /\A(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+/u
|
||||
|
||||
UTF8_PAT = ActiveSupport::Multibyte::VALID_CHARACTER['UTF-8']
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ module ActiveSupport
|
||||
end
|
||||
|
||||
def unsubscribe(subscriber)
|
||||
@subscribers.delete(subscriber)
|
||||
@listeners_for.clear
|
||||
@subscribers.reject! {|s| s.matches?(subscriber)}
|
||||
end
|
||||
|
||||
def publish(name, *args)
|
||||
@@ -60,7 +60,7 @@ module ActiveSupport
|
||||
end
|
||||
|
||||
def publish(*args)
|
||||
return unless matches?(args.first)
|
||||
return unless subscribed_to?(args.first)
|
||||
push(*args)
|
||||
true
|
||||
end
|
||||
@@ -69,10 +69,20 @@ module ActiveSupport
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
def matches?(name)
|
||||
!@pattern || @pattern =~ name.to_s
|
||||
def subscribed_to?(name)
|
||||
!@pattern || @pattern =~ name.to_s
|
||||
end
|
||||
|
||||
def matches?(subscriber_or_name)
|
||||
case subscriber_or_name
|
||||
when String
|
||||
@pattern && @pattern =~ subscriber_or_name
|
||||
when self
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def push(*args)
|
||||
@block.call(*args)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
require 'rbconfig'
|
||||
module ActiveSupport
|
||||
module Testing
|
||||
class RemoteError < StandardError
|
||||
@@ -33,7 +34,7 @@ module ActiveSupport
|
||||
|
||||
module Isolation
|
||||
def self.forking_env?
|
||||
!ENV["NO_FORK"] && RUBY_PLATFORM !~ /mswin|mingw|java/
|
||||
!ENV["NO_FORK"] && ((Config::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
|
||||
end
|
||||
|
||||
def self.included(base)
|
||||
|
||||
42
activesupport/test/configurable_test.rb
Normal file
42
activesupport/test/configurable_test.rb
Normal file
@@ -0,0 +1,42 @@
|
||||
require 'abstract_unit'
|
||||
require 'active_support/configurable'
|
||||
|
||||
class ConfigurableActiveSupport < ActiveSupport::TestCase
|
||||
class Parent
|
||||
include ActiveSupport::Configurable
|
||||
config_accessor :foo
|
||||
end
|
||||
|
||||
class Child < Parent
|
||||
end
|
||||
|
||||
setup do
|
||||
Parent.config.clear
|
||||
Parent.config.foo = :bar
|
||||
|
||||
Child.config.clear
|
||||
end
|
||||
|
||||
test "adds a configuration hash" do
|
||||
assert_equal({ :foo => :bar }, Parent.config)
|
||||
end
|
||||
|
||||
test "configuration hash is inheritable" do
|
||||
assert_equal :bar, Child.config.foo
|
||||
assert_equal :bar, Parent.config.foo
|
||||
|
||||
Child.config.foo = :baz
|
||||
assert_equal :baz, Child.config.foo
|
||||
assert_equal :bar, Parent.config.foo
|
||||
end
|
||||
|
||||
test "configuration hash is available on instance" do
|
||||
instance = Parent.new
|
||||
assert_equal :bar, instance.config.foo
|
||||
assert_equal :bar, Parent.config.foo
|
||||
|
||||
instance.config.foo = :baz
|
||||
assert_equal :baz, instance.config.foo
|
||||
assert_equal :bar, Parent.config.foo
|
||||
end
|
||||
end
|
||||
@@ -60,6 +60,43 @@ class HashExtTest < Test::Unit::TestCase
|
||||
assert_equal @strings, @mixed.dup.stringify_keys!
|
||||
end
|
||||
|
||||
def test_symbolize_keys_for_hash_with_indifferent_access
|
||||
assert_instance_of Hash, @symbols.with_indifferent_access.symbolize_keys
|
||||
assert_equal @symbols, @symbols.with_indifferent_access.symbolize_keys
|
||||
assert_equal @symbols, @strings.with_indifferent_access.symbolize_keys
|
||||
assert_equal @symbols, @mixed.with_indifferent_access.symbolize_keys
|
||||
end
|
||||
|
||||
def test_symbolize_keys_bang_for_hash_with_indifferent_access
|
||||
assert_raise(NoMethodError) { @symbols.with_indifferent_access.dup.symbolize_keys! }
|
||||
assert_raise(NoMethodError) { @strings.with_indifferent_access.dup.symbolize_keys! }
|
||||
assert_raise(NoMethodError) { @mixed.with_indifferent_access.dup.symbolize_keys! }
|
||||
end
|
||||
|
||||
def test_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access
|
||||
assert_equal @illegal_symbols, @illegal_symbols.with_indifferent_access.symbolize_keys
|
||||
assert_raise(NoMethodError) { @illegal_symbols.with_indifferent_access.dup.symbolize_keys! }
|
||||
end
|
||||
|
||||
def test_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access
|
||||
assert_equal @fixnums, @fixnums.with_indifferent_access.symbolize_keys
|
||||
assert_raise(NoMethodError) { @fixnums.with_indifferent_access.dup.symbolize_keys! }
|
||||
end
|
||||
|
||||
def test_stringify_keys_for_hash_with_indifferent_access
|
||||
assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.stringify_keys
|
||||
assert_equal @strings, @symbols.with_indifferent_access.stringify_keys
|
||||
assert_equal @strings, @strings.with_indifferent_access.stringify_keys
|
||||
assert_equal @strings, @mixed.with_indifferent_access.stringify_keys
|
||||
end
|
||||
|
||||
def test_stringify_keys_bang_for_hash_with_indifferent_access
|
||||
assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.dup.stringify_keys!
|
||||
assert_equal @strings, @symbols.with_indifferent_access.dup.stringify_keys!
|
||||
assert_equal @strings, @strings.with_indifferent_access.dup.stringify_keys!
|
||||
assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys!
|
||||
end
|
||||
|
||||
def test_indifferent_assorted
|
||||
@strings = @strings.with_indifferent_access
|
||||
@symbols = @symbols.with_indifferent_access
|
||||
@@ -213,11 +250,11 @@ class HashExtTest < Test::Unit::TestCase
|
||||
def test_stringify_and_symbolize_keys_on_indifferent_preserves_hash
|
||||
h = HashWithIndifferentAccess.new
|
||||
h[:first] = 1
|
||||
h.stringify_keys!
|
||||
h = h.stringify_keys
|
||||
assert_equal 1, h['first']
|
||||
h = HashWithIndifferentAccess.new
|
||||
h['first'] = 1
|
||||
h.symbolize_keys!
|
||||
h = h.symbolize_keys
|
||||
assert_equal 1, h[:first]
|
||||
end
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# encoding: utf-8
|
||||
require 'abstract_unit'
|
||||
require 'uri'
|
||||
require 'active_support/core_ext/uri'
|
||||
@@ -5,7 +6,6 @@ require 'active_support/core_ext/uri'
|
||||
class URIExtTest < Test::Unit::TestCase
|
||||
def test_uri_decode_handle_multibyte
|
||||
str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
|
||||
str.force_encoding(Encoding::UTF_8) if str.respond_to?(:force_encoding)
|
||||
|
||||
if URI.const_defined?(:Parser)
|
||||
parser = URI::Parser.new
|
||||
|
||||
@@ -9,6 +9,12 @@ class TestJSONEncoding < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
class Hashlike
|
||||
def to_hash
|
||||
{ :a => 1 }
|
||||
end
|
||||
end
|
||||
|
||||
class Custom
|
||||
def as_json(options)
|
||||
'custom'
|
||||
@@ -19,7 +25,8 @@ class TestJSONEncoding < Test::Unit::TestCase
|
||||
FalseTests = [[ false, %(false) ]]
|
||||
NilTests = [[ nil, %(null) ]]
|
||||
NumericTests = [[ 1, %(1) ],
|
||||
[ 2.5, %(2.5) ]]
|
||||
[ 2.5, %(2.5) ],
|
||||
[ BigDecimal('2.5'), %("#{BigDecimal('2.5').to_s}") ]]
|
||||
|
||||
StringTests = [[ 'this is the <string>', %("this is the \\u003Cstring\\u003E")],
|
||||
[ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
|
||||
@@ -35,11 +42,12 @@ class TestJSONEncoding < Test::Unit::TestCase
|
||||
[ :"a b", %("a b") ]]
|
||||
|
||||
ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]]
|
||||
HashlikeTests = [[ Hashlike.new, %({\"a\":1}) ]]
|
||||
CustomTests = [[ Custom.new, '"custom"' ]]
|
||||
|
||||
VariableTests = [[ ActiveSupport::JSON::Variable.new('foo'), 'foo'],
|
||||
[ ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")']]
|
||||
RegexpTests = [[ /^a/, '/^a/' ], [/^\w{1,2}[a-z]+/ix, '/^\\w{1,2}[a-z]+/ix']]
|
||||
RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']]
|
||||
|
||||
DateTests = [[ Date.new(2005,2,1), %("2005/02/01") ]]
|
||||
TimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]]
|
||||
@@ -91,6 +99,15 @@ class TestJSONEncoding < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
if '1.9'.respond_to?(:force_encoding)
|
||||
def test_non_utf8_string_transcodes
|
||||
s = '二'.encode('Shift_JIS')
|
||||
result = ActiveSupport::JSON.encode(s)
|
||||
assert_equal '"\\u4e8c"', result
|
||||
assert_equal Encoding::UTF_8, result.encoding
|
||||
end
|
||||
end
|
||||
|
||||
def test_exception_raised_when_encoding_circular_reference
|
||||
a = [1]
|
||||
a << a
|
||||
|
||||
@@ -105,7 +105,7 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase
|
||||
@whitespace = "\n\t#{[32, 8195].pack('U*')}"
|
||||
else
|
||||
# Ruby 1.9 only supports basic whitespace
|
||||
@whitespace = "\n\t ".force_encoding(Encoding::UTF_8)
|
||||
@whitespace = "\n\t "
|
||||
end
|
||||
|
||||
@byte_order_mark = [65279].pack('U')
|
||||
|
||||
@@ -6,7 +6,9 @@ module Notifications
|
||||
ActiveSupport::Notifications.notifier = nil
|
||||
@notifier = ActiveSupport::Notifications.notifier
|
||||
@events = []
|
||||
@named_events = []
|
||||
@subscription = @notifier.subscribe { |*args| @events << event(*args) }
|
||||
@named_subscription = @notifier.subscribe("named.subscription") { |*args| @named_events << event(*args) }
|
||||
end
|
||||
|
||||
private
|
||||
@@ -30,6 +32,26 @@ module Notifications
|
||||
assert_equal [[:foo]], @events
|
||||
end
|
||||
|
||||
def test_unsubscribing_by_name_removes_a_subscription
|
||||
@notifier.publish "named.subscription", :foo
|
||||
@notifier.wait
|
||||
assert_equal [["named.subscription", :foo]], @named_events
|
||||
@notifier.unsubscribe("named.subscription")
|
||||
@notifier.publish "named.subscription", :foo
|
||||
@notifier.wait
|
||||
assert_equal [["named.subscription", :foo]], @named_events
|
||||
end
|
||||
|
||||
def test_unsubscribing_by_name_leaves_the_other_subscriptions
|
||||
@notifier.publish "named.subscription", :foo
|
||||
@notifier.wait
|
||||
assert_equal [["named.subscription", :foo]], @events
|
||||
@notifier.unsubscribe("named.subscription")
|
||||
@notifier.publish "named.subscription", :foo
|
||||
@notifier.wait
|
||||
assert_equal [["named.subscription", :foo], ["named.subscription", :foo]], @events
|
||||
end
|
||||
|
||||
private
|
||||
def event(*args)
|
||||
args
|
||||
|
||||
@@ -6,6 +6,7 @@ require 'rake/gempackagetask'
|
||||
require 'date'
|
||||
require 'rbconfig'
|
||||
|
||||
|
||||
task :default => :test
|
||||
task :test => 'test:isolated'
|
||||
|
||||
|
||||
@@ -112,15 +112,15 @@ module Rails
|
||||
|
||||
def load_tasks
|
||||
initialize_tasks
|
||||
super
|
||||
railties.all { |r| r.load_tasks }
|
||||
super
|
||||
self
|
||||
end
|
||||
|
||||
def load_generators
|
||||
initialize_generators
|
||||
super
|
||||
railties.all { |r| r.load_generators }
|
||||
super
|
||||
self
|
||||
end
|
||||
|
||||
|
||||
@@ -128,13 +128,13 @@ module Rails
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def session_options
|
||||
return @session_options unless @session_store == :cookie_store
|
||||
@session_options.merge(:secret => @secret_token)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_middleware_stack
|
||||
ActionDispatch::MiddlewareStack.new.tap do |middleware|
|
||||
middleware.use('::ActionDispatch::Static', lambda { paths.public.to_a.first }, :if => lambda { serve_static_assets })
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require 'erb'
|
||||
require 'yaml'
|
||||
require 'optparse'
|
||||
require 'rbconfig'
|
||||
|
||||
module Rails
|
||||
class DBConsole
|
||||
@@ -41,7 +42,7 @@ module Rails
|
||||
|
||||
def find_cmd(*commands)
|
||||
dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
|
||||
commands += commands.map{|cmd| "#{cmd}.exe"} if RUBY_PLATFORM =~ /win32/
|
||||
commands += commands.map{|cmd| "#{cmd}.exe"} if Config::CONFIG['host_os'] =~ /mswin|mingw/
|
||||
|
||||
full_path_command = nil
|
||||
found = commands.detect do |cmd|
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require 'optparse'
|
||||
require 'rbconfig'
|
||||
|
||||
options = { :environment => (ENV['RAILS_ENV'] || "development").dup }
|
||||
code_or_file = nil
|
||||
@@ -18,7 +19,7 @@ ARGV.clone.options do |opts|
|
||||
opts.on("-h", "--help",
|
||||
"Show this help message.") { $stderr.puts opts; exit }
|
||||
|
||||
if RUBY_PLATFORM !~ /mswin|mingw/
|
||||
if Config::CONFIG['host_os'] !~ /mswin|mingw/
|
||||
opts.separator ""
|
||||
opts.separator "You can also use runner as a shebang line for your scripts like this:"
|
||||
opts.separator "-------------------------------------------------------------"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require 'rails/railtie'
|
||||
require 'active_support/core_ext/module/delegation'
|
||||
require 'pathname'
|
||||
require 'rbconfig'
|
||||
|
||||
module Rails
|
||||
# Rails::Engine allows you to wrap a specific Rails application and share it accross
|
||||
@@ -119,7 +120,7 @@ module Rails
|
||||
root = File.exist?("#{root_path}/#{flag}") ? root_path : default
|
||||
raise "Could not find root path for #{self}" unless root
|
||||
|
||||
RUBY_PLATFORM =~ /mswin|mingw/ ?
|
||||
Config::CONFIG['host_os'] =~ /mswin|mingw/ ?
|
||||
Pathname.new(root).expand_path : Pathname.new(root).realpath
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'open-uri'
|
||||
require 'active_support/deprecation'
|
||||
require 'rbconfig'
|
||||
|
||||
module Rails
|
||||
module Generators
|
||||
@@ -240,7 +241,7 @@ module Rails
|
||||
def rake(command, options={})
|
||||
log :rake, command
|
||||
env = options[:env] || 'development'
|
||||
sudo = options[:sudo] && RUBY_PLATFORM !~ /mswin|mingw/ ? 'sudo ' : ''
|
||||
sudo = options[:sudo] && Config::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
|
||||
in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", :verbose => false) }
|
||||
end
|
||||
|
||||
@@ -307,7 +308,7 @@ module Rails
|
||||
# Add an extension to the given name based on the platform.
|
||||
#
|
||||
def extify(name)
|
||||
if RUBY_PLATFORM =~ /mswin|mingw/
|
||||
if Config::CONFIG['host_os'] =~ /mswin|mingw/
|
||||
"#{name}.bat"
|
||||
else
|
||||
name
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<p class="notice"><%%= notice %></p>
|
||||
<p id="notice"><%%= notice %></p>
|
||||
|
||||
<% for attribute in attributes -%>
|
||||
<p>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require 'digest/md5'
|
||||
require 'active_support/secure_random'
|
||||
require 'rails/version' unless defined?(Rails::VERSION)
|
||||
require 'rbconfig'
|
||||
|
||||
module Rails::Generators
|
||||
# We need to store the RAILS_DEV_PATH in a constant, otherwise the path
|
||||
@@ -265,7 +266,7 @@ module Rails::Generators
|
||||
"/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
|
||||
"/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
|
||||
"/opt/lampp/var/mysql/mysql.sock" # xampp for linux
|
||||
].find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /mswin|mingw/
|
||||
].find { |f| File.exist?(f) } unless Config::CONFIG['host_os'] =~ /mswin|mingw/
|
||||
end
|
||||
|
||||
def empty_directory_with_gitkeep(destination, config = {})
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||
|
||||
require File.expand_path('../config/application', __FILE__)
|
||||
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
Rails::Application.load_tasks
|
||||
|
||||
@@ -20,15 +20,11 @@ div.field, div.actions {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.notice {
|
||||
#notice {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.alert {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.fieldWithErrors {
|
||||
.field_with_errors {
|
||||
padding: 2px;
|
||||
background-color: red;
|
||||
display: table;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'rake/rdoctask'
|
||||
|
||||
namespace :doc do
|
||||
def gem_path(gem_name)
|
||||
path = $LOAD_PATH.grep(/#{gem_name}[\w.-]*\/lib$/).first
|
||||
|
||||
@@ -35,7 +35,9 @@ class ActionController::TestCase
|
||||
end
|
||||
|
||||
class ActionDispatch::IntegrationTest
|
||||
include Rails.application.routes.url_helpers
|
||||
setup do
|
||||
@routes = Rails.application.routes
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'rake/testtask'
|
||||
|
||||
TEST_CHANGES_SINCE = Time.now - 600
|
||||
|
||||
# Look up tests for recently modified sources.
|
||||
@@ -30,7 +32,7 @@ end
|
||||
module Kernel
|
||||
def silence_stderr
|
||||
old_stderr = STDERR.dup
|
||||
STDERR.reopen(RUBY_PLATFORM =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
|
||||
STDERR.reopen(Config::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
|
||||
STDERR.sync = true
|
||||
yield
|
||||
ensure
|
||||
|
||||
@@ -109,7 +109,7 @@ module ApplicationTests
|
||||
end
|
||||
end
|
||||
|
||||
test "Frameworks are not preloaded by default" do
|
||||
test "frameworks are not preloaded by default" do
|
||||
require "#{app_path}/config/environment"
|
||||
|
||||
assert ActionController.autoload?(:RecordIdentifier)
|
||||
@@ -193,71 +193,10 @@ module ApplicationTests
|
||||
assert_equal File.join(app_path, "somewhere"), Rails.public_path
|
||||
end
|
||||
|
||||
def make_basic_app
|
||||
require "rails"
|
||||
require "action_controller/railtie"
|
||||
|
||||
app = Class.new(Rails::Application)
|
||||
|
||||
yield app if block_given?
|
||||
|
||||
app.config.session_store :disabled
|
||||
app.initialize!
|
||||
|
||||
app.routes.draw do
|
||||
match "/" => "omg#index"
|
||||
end
|
||||
|
||||
require 'rack/test'
|
||||
extend Rack::Test::Methods
|
||||
end
|
||||
|
||||
test "config.action_dispatch.x_sendfile_header defaults to ''" do
|
||||
make_basic_app
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
def index
|
||||
send_file __FILE__
|
||||
end
|
||||
end
|
||||
|
||||
get "/"
|
||||
assert_equal File.read(__FILE__), last_response.body
|
||||
end
|
||||
|
||||
test "config.action_dispatch.x_sendfile_header can be set" do
|
||||
make_basic_app do |app|
|
||||
app.config.action_dispatch.x_sendfile_header = "X-Sendfile"
|
||||
end
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
def index
|
||||
send_file __FILE__
|
||||
end
|
||||
end
|
||||
|
||||
get "/"
|
||||
assert_equal File.expand_path(__FILE__), last_response.headers["X-Sendfile"]
|
||||
end
|
||||
|
||||
test "config.action_dispatch.x_sendfile_header is sent to Rack::Sendfile" do
|
||||
make_basic_app do |app|
|
||||
app.config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File'
|
||||
end
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
def index
|
||||
send_file __FILE__
|
||||
end
|
||||
end
|
||||
|
||||
get "/"
|
||||
assert_equal File.expand_path(__FILE__), last_response.headers["X-Lighttpd-Send-File"]
|
||||
end
|
||||
|
||||
test "config.secret_token is sent in env" do
|
||||
make_basic_app do |app|
|
||||
app.config.secret_token = 'ThisIsASECRET123'
|
||||
app.config.session_store :disabled
|
||||
end
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
@@ -287,9 +226,9 @@ module ApplicationTests
|
||||
end
|
||||
|
||||
test "config.action_controller.perform_caching = true" do
|
||||
make_basic_app do |app|
|
||||
app.config.action_controller.perform_caching = true
|
||||
end
|
||||
make_basic_app do |app|
|
||||
app.config.action_controller.perform_caching = true
|
||||
end
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
@@count = 0
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
require 'isolation/abstract_unit'
|
||||
|
||||
class MiddlewareStackDefaultsTest < Test::Unit::TestCase
|
||||
include ActiveSupport::Testing::Isolation
|
||||
|
||||
def setup
|
||||
boot_rails
|
||||
require "rails"
|
||||
require "action_controller/railtie"
|
||||
|
||||
Object.const_set(:MyApplication, Class.new(Rails::Application))
|
||||
MyApplication.class_eval do
|
||||
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
config.session_store :cookie_store, :key => "_myapp_session"
|
||||
end
|
||||
end
|
||||
|
||||
def remote_ip(env = {})
|
||||
remote_ip = nil
|
||||
env = Rack::MockRequest.env_for("/").merge(env).merge('action_dispatch.show_exceptions' => false)
|
||||
|
||||
endpoint = Proc.new do |e|
|
||||
remote_ip = ActionDispatch::Request.new(e).remote_ip
|
||||
[200, {}, ["Hello"]]
|
||||
end
|
||||
|
||||
out = MyApplication.middleware.build(endpoint).call(env)
|
||||
remote_ip
|
||||
end
|
||||
|
||||
test "remote_ip works" do
|
||||
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1")
|
||||
end
|
||||
|
||||
test "checks IP spoofing by default" do
|
||||
assert_raises(ActionDispatch::RemoteIp::IpSpoofAttackError) do
|
||||
remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2")
|
||||
end
|
||||
end
|
||||
|
||||
test "can disable IP spoofing check" do
|
||||
MyApplication.config.action_dispatch.ip_spoofing_check = false
|
||||
|
||||
assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do
|
||||
assert_equal "1.1.1.2", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2")
|
||||
end
|
||||
end
|
||||
|
||||
test "the user can set trusted proxies" do
|
||||
MyApplication.config.action_dispatch.trusted_proxies = /^4\.2\.42\.42$/
|
||||
|
||||
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "4.2.42.42,1.1.1.1")
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,10 @@ module ApplicationTests
|
||||
FileUtils.rm_rf "#{app_path}/config/environments"
|
||||
end
|
||||
|
||||
def app
|
||||
@app ||= Rails.application
|
||||
end
|
||||
|
||||
test "default middleware stack" do
|
||||
boot!
|
||||
|
||||
@@ -83,7 +87,83 @@ module ApplicationTests
|
||||
assert middleware.include?("ActionDispatch::Cascade")
|
||||
end
|
||||
|
||||
# x_sendfile_header middleware
|
||||
test "config.action_dispatch.x_sendfile_header defaults to ''" do
|
||||
make_basic_app
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
def index
|
||||
send_file __FILE__
|
||||
end
|
||||
end
|
||||
|
||||
get "/"
|
||||
assert_equal File.read(__FILE__), last_response.body
|
||||
end
|
||||
|
||||
test "config.action_dispatch.x_sendfile_header can be set" do
|
||||
make_basic_app do |app|
|
||||
app.config.action_dispatch.x_sendfile_header = "X-Sendfile"
|
||||
end
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
def index
|
||||
send_file __FILE__
|
||||
end
|
||||
end
|
||||
|
||||
get "/"
|
||||
assert_equal File.expand_path(__FILE__), last_response.headers["X-Sendfile"]
|
||||
end
|
||||
|
||||
test "config.action_dispatch.x_sendfile_header is sent to Rack::Sendfile" do
|
||||
make_basic_app do |app|
|
||||
app.config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File'
|
||||
end
|
||||
|
||||
class ::OmgController < ActionController::Base
|
||||
def index
|
||||
send_file __FILE__
|
||||
end
|
||||
end
|
||||
|
||||
get "/"
|
||||
assert_equal File.expand_path(__FILE__), last_response.headers["X-Lighttpd-Send-File"]
|
||||
end
|
||||
|
||||
# remote_ip tests
|
||||
test "remote_ip works" do
|
||||
make_basic_app
|
||||
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1")
|
||||
end
|
||||
|
||||
test "checks IP spoofing by default" do
|
||||
make_basic_app
|
||||
assert_raises(ActionDispatch::RemoteIp::IpSpoofAttackError) do
|
||||
remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2")
|
||||
end
|
||||
end
|
||||
|
||||
test "can disable IP spoofing check" do
|
||||
make_basic_app do |app|
|
||||
app.config.action_dispatch.ip_spoofing_check = false
|
||||
end
|
||||
|
||||
assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do
|
||||
assert_equal "1.1.1.2", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2")
|
||||
end
|
||||
end
|
||||
|
||||
test "the user can set trusted proxies" do
|
||||
make_basic_app do |app|
|
||||
app.config.action_dispatch.trusted_proxies = /^4\.2\.42\.42$/
|
||||
end
|
||||
|
||||
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "4.2.42.42,1.1.1.1")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def boot!
|
||||
require "#{app_path}/config/environment"
|
||||
end
|
||||
@@ -91,5 +171,18 @@ module ApplicationTests
|
||||
def middleware
|
||||
AppTemplate::Application.middleware.active.map(&:klass).map(&:name)
|
||||
end
|
||||
|
||||
def remote_ip(env = {})
|
||||
remote_ip = nil
|
||||
env = Rack::MockRequest.env_for("/").merge(env).merge('action_dispatch.show_exceptions' => false)
|
||||
|
||||
endpoint = Proc.new do |e|
|
||||
remote_ip = ActionDispatch::Request.new(e).remote_ip
|
||||
[200, {}, ["Hello"]]
|
||||
end
|
||||
|
||||
Rails.application.middleware.build(endpoint).call(env)
|
||||
remote_ip
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
23
railties/test/application/rake_test.rb
Normal file
23
railties/test/application/rake_test.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
require "isolation/abstract_unit"
|
||||
|
||||
module ApplicationTests
|
||||
class RakeTest < Test::Unit::TestCase
|
||||
include ActiveSupport::Testing::Isolation
|
||||
|
||||
def setup
|
||||
build_app
|
||||
boot_rails
|
||||
FileUtils.rm_rf("#{app_path}/config/environments")
|
||||
end
|
||||
|
||||
def test_gems_tasks_are_loaded_first_than_application_ones
|
||||
app_file "lib/tasks/app.rake", <<-RUBY
|
||||
$task_loaded = Rake::Task.task_defined?("db:create:all")
|
||||
RUBY
|
||||
|
||||
require "#{app_path}/config/environment"
|
||||
::Rails.application.load_tasks
|
||||
assert $task_loaded
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -103,6 +103,25 @@ module TestHelpers
|
||||
add_to_config 'config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"; config.session_store :cookie_store, :key => "_myapp_session"'
|
||||
end
|
||||
|
||||
def make_basic_app
|
||||
require "rails"
|
||||
require "action_controller/railtie"
|
||||
|
||||
app = Class.new(Rails::Application)
|
||||
app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
|
||||
app.config.session_store :cookie_store, :key => "_myapp_session"
|
||||
|
||||
yield app if block_given?
|
||||
app.initialize!
|
||||
|
||||
app.routes.draw do
|
||||
match "/" => "omg#index"
|
||||
end
|
||||
|
||||
require 'rack/test'
|
||||
extend ::Rack::Test::Methods
|
||||
end
|
||||
|
||||
class Bukkit
|
||||
attr_reader :path
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ Gem.source_index
|
||||
require 'benchmark'
|
||||
|
||||
module RequireProfiler
|
||||
private
|
||||
def require(file, *args) RequireProfiler.profile(file) { super } end
|
||||
def load(file, *args) RequireProfiler.profile(file) { super } end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user