Update to Rails 2.3.9 and itextomml 1.3.27
This commit is contained in:
parent
113e0af736
commit
ef30cc22df
|
@ -229,9 +229,9 @@ END_THM
|
|||
assert_markup_parsed_as(
|
||||
%{<p>equation <math class='maruku-mathml' displa} +
|
||||
%{y='inline' xmlns='http://www.w3.org/1998/Math/} +
|
||||
%{MathML'><mi>A</mi><mo>\342\253\275</mo><mi>B</} +
|
||||
%{MathML'><mi>A</mi><mi>\342\200\246</mi><mo>\342\253\275</mo><mi>B</} +
|
||||
%{mi></math></p>},
|
||||
"equation $A\\sslash B$")
|
||||
"equation $A\\dots\\sslash B$")
|
||||
|
||||
assert_markup_parsed_as(
|
||||
%{<p>boxed equation <math class='maruku-mathml' } +
|
||||
|
|
|
@ -4,7 +4,7 @@ module ActionView
|
|||
module TagHelper
|
||||
# Now that form_tag accepts blocks, it was easier to alias tag when name == :form
|
||||
def tag_with_form_spam_protection(name, *args)
|
||||
returning tag_without_form_spam_protection(name, *args) do |out|
|
||||
tag_without_form_spam_protection(name, *args).tap do |out|
|
||||
if name == :form && @protect_form_from_spam
|
||||
session[:form_keys] ||= {}
|
||||
form_key = Digest::SHA1.hexdigest(self.object_id.to_s + rand.to_s)
|
||||
|
|
5
vendor/rails/actionmailer/CHANGELOG
vendored
5
vendor/rails/actionmailer/CHANGELOG
vendored
|
@ -1,8 +1,5 @@
|
|||
*2.3.9 (September 4, 2010)*
|
||||
*2.3.8 (May 24, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
||||
|
||||
*2.3.7 (May 24, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
|
2
vendor/rails/actionmailer/Rakefile
vendored
2
vendor/rails/actionmailer/Rakefile
vendored
|
@ -54,7 +54,7 @@ spec = Gem::Specification.new do |s|
|
|||
s.rubyforge_project = "actionmailer"
|
||||
s.homepage = "http://www.rubyonrails.org"
|
||||
|
||||
s.add_dependency('actionpack', '= 2.3.8' + PKG_BUILD)
|
||||
s.add_dependency('actionpack', '= 2.3.9' + PKG_BUILD)
|
||||
|
||||
s.has_rdoc = true
|
||||
s.requirements << 'none'
|
||||
|
|
|
@ -278,7 +278,7 @@ module ActionMailer #:nodoc:
|
|||
@@raise_delivery_errors = true
|
||||
cattr_accessor :raise_delivery_errors
|
||||
|
||||
superclass_delegating_accessor :delivery_method
|
||||
class_attribute :delivery_method
|
||||
self.delivery_method = :smtp
|
||||
|
||||
@@perform_deliveries = true
|
||||
|
|
|
@ -105,7 +105,7 @@ module ActionMailer
|
|||
private
|
||||
# Extend the template class instance with our controller's helper module.
|
||||
def initialize_template_class_with_helper(assigns)
|
||||
returning(template = initialize_template_class_without_helper(assigns)) do
|
||||
initialize_template_class_without_helper(assigns).tap do |template|
|
||||
template.extend self.class.master_helper_module
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ module ActionMailer
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 3
|
||||
TINY = 8
|
||||
TINY = 9
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
5
vendor/rails/actionpack/CHANGELOG
vendored
5
vendor/rails/actionpack/CHANGELOG
vendored
|
@ -1,3 +1,8 @@
|
|||
*2.3.9 (September 4, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
||||
|
||||
*2.3.8 (May 24, 2010)*
|
||||
|
||||
* HTML safety: fix compatibility *without* the optional rails_xss plugin.
|
||||
|
|
2
vendor/rails/actionpack/Rakefile
vendored
2
vendor/rails/actionpack/Rakefile
vendored
|
@ -79,7 +79,7 @@ spec = Gem::Specification.new do |s|
|
|||
s.has_rdoc = true
|
||||
s.requirements << 'none'
|
||||
|
||||
s.add_dependency('activesupport', '= 2.3.8' + PKG_BUILD)
|
||||
s.add_dependency('activesupport', '= 2.3.9' + PKG_BUILD)
|
||||
s.add_dependency('rack', '~> 1.1.0')
|
||||
|
||||
s.require_path = 'lib'
|
||||
|
|
|
@ -65,8 +65,8 @@ module ActionController #:nodoc:
|
|||
def read_fragment(key, options = nil)
|
||||
return unless cache_configured?
|
||||
|
||||
self.class.benchmark "Cached fragment hit: #{key}" do
|
||||
key = fragment_cache_key(key)
|
||||
self.class.benchmark "Cached fragment hit: #{key}" do
|
||||
result = cache_store.read(key, options)
|
||||
result.respond_to?(:html_safe) ? result.html_safe : result
|
||||
end
|
||||
|
|
|
@ -414,15 +414,25 @@ module ActionController
|
|||
end
|
||||
|
||||
def multipart_requestify(params, first=true)
|
||||
returning Hash.new do |p|
|
||||
Array.new.tap do |p|
|
||||
params.each do |key, value|
|
||||
k = first ? key.to_s : "[#{key.to_s}]"
|
||||
if Hash === value
|
||||
multipart_requestify(value, false).each do |subkey, subvalue|
|
||||
p[k + subkey] = subvalue
|
||||
p << [k + subkey, subvalue]
|
||||
end
|
||||
elsif Array === value
|
||||
value.each do |element|
|
||||
if Hash === element || Array === element
|
||||
multipart_requestify(element, false).each do |subkey, subvalue|
|
||||
p << ["#{k}[]#{subkey}", subvalue]
|
||||
end
|
||||
else
|
||||
p[k] = value
|
||||
p << ["#{k}[]", element]
|
||||
end
|
||||
end
|
||||
else
|
||||
p << [k, value]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -453,6 +463,7 @@ EOF
|
|||
end
|
||||
end.join("")+"--#{boundary}--\r"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A module used to extend ActionController::Base, so that integration tests
|
||||
|
@ -500,7 +511,7 @@ EOF
|
|||
reset! unless @integration_session
|
||||
# reset the html_document variable, but only for new get/post calls
|
||||
@html_document = nil unless %w(cookies assigns).include?(method)
|
||||
returning @integration_session.__send__(method, *args) do
|
||||
@integration_session.__send__(method, *args).tap do
|
||||
copy_session_variables!
|
||||
end
|
||||
end
|
||||
|
@ -556,7 +567,7 @@ EOF
|
|||
def method_missing(sym, *args, &block)
|
||||
reset! unless @integration_session
|
||||
if @integration_session.respond_to?(sym)
|
||||
returning @integration_session.__send__(sym, *args, &block) do
|
||||
@integration_session.__send__(sym, *args, &block).tap do
|
||||
copy_session_variables!
|
||||
end
|
||||
else
|
||||
|
|
|
@ -446,8 +446,8 @@ EOM
|
|||
end
|
||||
|
||||
def reset_session
|
||||
@env['rack.session.options'].delete(:id)
|
||||
@env['rack.session'] = {}
|
||||
session.destroy if session
|
||||
self.session = {}
|
||||
end
|
||||
|
||||
def session_options
|
||||
|
|
|
@ -15,7 +15,7 @@ module ActionController #:nodoc:
|
|||
# behavior is achieved by overriding the <tt>rescue_action_in_public</tt>
|
||||
# and <tt>rescue_action_locally</tt> methods.
|
||||
module Rescue
|
||||
LOCALHOST = ['127.0.0.1', '::1'].freeze
|
||||
LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
|
||||
|
||||
DEFAULT_RESCUE_RESPONSE = :internal_server_error
|
||||
DEFAULT_RESCUE_RESPONSES = {
|
||||
|
@ -122,7 +122,7 @@ module ActionController #:nodoc:
|
|||
# method if you wish to redefine the meaning of a local request to
|
||||
# include remote IP addresses or other criteria.
|
||||
def local_request? #:doc:
|
||||
LOCALHOST.any?{ |local_ip| request.remote_addr == local_ip && request.remote_ip == local_ip }
|
||||
LOCALHOST.any?{ |local_ip| request.remote_addr =~ local_ip && request.remote_ip =~ local_ip }
|
||||
end
|
||||
|
||||
# Render detailed diagnostics for unhandled exceptions rescued from
|
||||
|
|
|
@ -659,7 +659,7 @@ module ActionController
|
|||
end
|
||||
|
||||
def add_conditions_for(conditions, method)
|
||||
returning({:conditions => conditions.dup}) do |options|
|
||||
({:conditions => conditions.dup}).tap do |options|
|
||||
options[:conditions][:method] = method unless method == :any
|
||||
end
|
||||
end
|
||||
|
|
|
@ -377,7 +377,7 @@ module ActionController
|
|||
ActiveSupport::Inflector.module_eval do
|
||||
# Ensures that routes are reloaded when Rails inflections are updated.
|
||||
def inflections_with_route_reloading(&block)
|
||||
returning(inflections_without_route_reloading(&block)) {
|
||||
(inflections_without_route_reloading(&block)).tap {
|
||||
ActionController::Routing::Routes.reload! if block_given?
|
||||
}
|
||||
end
|
||||
|
|
|
@ -65,7 +65,7 @@ module ActionController
|
|||
# map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
|
||||
#
|
||||
def parameter_shell
|
||||
@parameter_shell ||= returning({}) do |shell|
|
||||
@parameter_shell ||= {}.tap do |shell|
|
||||
requirements.each do |key, requirement|
|
||||
shell[key] = requirement unless requirement.is_a? Regexp
|
||||
end
|
||||
|
@ -76,7 +76,7 @@ module ActionController
|
|||
# includes keys that appear inside the path, and keys that have requirements
|
||||
# placed upon them.
|
||||
def significant_keys
|
||||
@significant_keys ||= returning([]) do |sk|
|
||||
@significant_keys ||= [].tap do |sk|
|
||||
segments.each { |segment| sk << segment.key if segment.respond_to? :key }
|
||||
sk.concat requirements.keys
|
||||
sk.uniq!
|
||||
|
@ -86,7 +86,7 @@ module ActionController
|
|||
# Return a hash of key/value pairs representing the keys in the route that
|
||||
# have defaults, or which are specified by non-regexp requirements.
|
||||
def defaults
|
||||
@defaults ||= returning({}) do |hash|
|
||||
@defaults ||= {}.tap do |hash|
|
||||
segments.each do |segment|
|
||||
next unless segment.respond_to? :default
|
||||
hash[segment.key] = segment.default unless segment.default.nil?
|
||||
|
|
|
@ -9,6 +9,35 @@ module ActionController
|
|||
HTTP_COOKIE = 'HTTP_COOKIE'.freeze
|
||||
SET_COOKIE = 'Set-Cookie'.freeze
|
||||
|
||||
# thin wrapper around Hash that allows us to lazily
|
||||
# load session id into session_options
|
||||
class OptionsHash < Hash
|
||||
def initialize(by, env, default_options)
|
||||
@by = by
|
||||
@env = env
|
||||
@session_id_loaded = false
|
||||
merge!(default_options)
|
||||
end
|
||||
|
||||
def [](key)
|
||||
if key == :id
|
||||
load_session_id! unless super(:id) || has_session_id?
|
||||
end
|
||||
super(key)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def has_session_id?
|
||||
@session_id_loaded
|
||||
end
|
||||
|
||||
def load_session_id!
|
||||
self[:id] = @by.send(:extract_session_id, @env)
|
||||
@session_id_loaded = true
|
||||
end
|
||||
end
|
||||
|
||||
class SessionHash < Hash
|
||||
def initialize(by, env)
|
||||
super()
|
||||
|
@ -25,21 +54,42 @@ module ActionController
|
|||
end
|
||||
|
||||
def [](key)
|
||||
load! unless @loaded
|
||||
load_for_read!
|
||||
super
|
||||
end
|
||||
|
||||
def has_key?(key)
|
||||
load_for_read!
|
||||
super
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
load! unless @loaded
|
||||
load_for_write!
|
||||
super
|
||||
end
|
||||
|
||||
def clear
|
||||
load_for_write!
|
||||
super
|
||||
end
|
||||
|
||||
def to_hash
|
||||
load_for_read!
|
||||
h = {}.replace(self)
|
||||
h.delete_if { |k,v| v.nil? }
|
||||
h
|
||||
end
|
||||
|
||||
def update(hash)
|
||||
load_for_write!
|
||||
super
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
load_for_write!
|
||||
super
|
||||
end
|
||||
|
||||
def data
|
||||
ActiveSupport::Deprecation.warn(
|
||||
"ActionController::Session::AbstractStore::SessionHash#data " +
|
||||
|
@ -48,40 +98,43 @@ module ActionController
|
|||
end
|
||||
|
||||
def inspect
|
||||
load! unless @loaded
|
||||
load_for_read!
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
def exists?
|
||||
return @exists if instance_variable_defined?(:@exists)
|
||||
@exists = @by.send(:exists?, @env)
|
||||
end
|
||||
|
||||
def loaded?
|
||||
@loaded
|
||||
end
|
||||
|
||||
def destroy
|
||||
clear
|
||||
@by.send(:destroy, @env) if @by
|
||||
@env[ENV_SESSION_OPTIONS_KEY][:id] = nil if @env && @env[ENV_SESSION_OPTIONS_KEY]
|
||||
@loaded = false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_for_read!
|
||||
load! if !loaded? && exists?
|
||||
end
|
||||
|
||||
def load_for_write!
|
||||
load! unless loaded?
|
||||
end
|
||||
|
||||
def load!
|
||||
stale_session_check! do
|
||||
id, session = @by.send(:load_session, @env)
|
||||
(@env[ENV_SESSION_OPTIONS_KEY] ||= {})[:id] = id
|
||||
@env[ENV_SESSION_OPTIONS_KEY][:id] = id
|
||||
replace(session)
|
||||
@loaded = true
|
||||
end
|
||||
end
|
||||
|
||||
def stale_session_check!
|
||||
yield
|
||||
rescue ArgumentError => argument_error
|
||||
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
|
||||
begin
|
||||
# Note that the regexp does not allow $1 to end with a ':'
|
||||
$1.constantize
|
||||
rescue LoadError, NameError => const_error
|
||||
raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
|
||||
end
|
||||
|
||||
retry
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DEFAULT_OPTIONS = {
|
||||
|
@ -120,18 +173,14 @@ module ActionController
|
|||
end
|
||||
|
||||
def call(env)
|
||||
session = SessionHash.new(self, env)
|
||||
|
||||
env[ENV_SESSION_KEY] = session
|
||||
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
|
||||
|
||||
prepare!(env)
|
||||
response = @app.call(env)
|
||||
|
||||
session_data = env[ENV_SESSION_KEY]
|
||||
options = env[ENV_SESSION_OPTIONS_KEY]
|
||||
|
||||
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
|
||||
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
|
||||
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.loaded? || options[:expire_after]
|
||||
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
|
||||
|
||||
sid = options[:id] || generate_sid
|
||||
|
||||
|
@ -139,6 +188,7 @@ module ActionController
|
|||
return response
|
||||
end
|
||||
|
||||
if (env["rack.request.cookie_hash"] && env["rack.request.cookie_hash"][@key] != sid) || options[:expire_after]
|
||||
cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid)
|
||||
cookie << "; domain=#{options[:domain]}" if options[:domain]
|
||||
cookie << "; path=#{options[:path]}" if options[:path]
|
||||
|
@ -156,24 +206,46 @@ module ActionController
|
|||
headers[SET_COOKIE] = cookie
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def prepare!(env)
|
||||
env[ENV_SESSION_KEY] = SessionHash.new(self, env)
|
||||
env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
|
||||
end
|
||||
|
||||
def generate_sid
|
||||
ActiveSupport::SecureRandom.hex(16)
|
||||
end
|
||||
|
||||
def load_session(env)
|
||||
request = Rack::Request.new(env)
|
||||
sid = request.cookies[@key]
|
||||
unless @cookie_only
|
||||
sid ||= request.params[@key]
|
||||
end
|
||||
stale_session_check! do
|
||||
sid = current_session_id(env)
|
||||
sid, session = get_session(env, sid)
|
||||
[sid, session]
|
||||
end
|
||||
end
|
||||
|
||||
def extract_session_id(env)
|
||||
stale_session_check! do
|
||||
request = Rack::Request.new(env)
|
||||
sid = request.cookies[@key]
|
||||
sid ||= request.params[@key] unless @cookie_only
|
||||
sid
|
||||
end
|
||||
end
|
||||
|
||||
def current_session_id(env)
|
||||
env[ENV_SESSION_OPTIONS_KEY][:id]
|
||||
end
|
||||
|
||||
def exists?(env)
|
||||
current_session_id(env).present?
|
||||
end
|
||||
|
||||
def get_session(env, sid)
|
||||
raise '#get_session needs to be implemented.'
|
||||
|
@ -182,6 +254,30 @@ module ActionController
|
|||
def set_session(env, sid, session_data)
|
||||
raise '#set_session needs to be implemented.'
|
||||
end
|
||||
|
||||
def destroy(env)
|
||||
raise '#destroy needs to be implemented.'
|
||||
end
|
||||
|
||||
module SessionUtils
|
||||
private
|
||||
def stale_session_check!
|
||||
yield
|
||||
rescue ArgumentError => argument_error
|
||||
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
|
||||
begin
|
||||
# Note that the regexp does not allow $1 to end with a ':'
|
||||
$1.constantize
|
||||
rescue LoadError, NameError => const_error
|
||||
raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
|
||||
end
|
||||
retry
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
include SessionUtils
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,6 +36,8 @@ module ActionController
|
|||
#
|
||||
# Note that changing digest or secret invalidates all existing sessions!
|
||||
class CookieStore
|
||||
include AbstractStore::SessionUtils
|
||||
|
||||
# Cookies can typically store 4096 bytes.
|
||||
MAX = 4096
|
||||
SECRET_MIN_LENGTH = 30 # characters
|
||||
|
@ -93,20 +95,20 @@ module ActionController
|
|||
end
|
||||
|
||||
def call(env)
|
||||
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
|
||||
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
|
||||
prepare!(env)
|
||||
|
||||
status, headers, body = @app.call(env)
|
||||
|
||||
session_data = env[ENV_SESSION_KEY]
|
||||
options = env[ENV_SESSION_OPTIONS_KEY]
|
||||
|
||||
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
|
||||
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
|
||||
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.loaded? || options[:expire_after]
|
||||
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
|
||||
|
||||
persistent_session_id!(session_data)
|
||||
session_data = marshal(session_data.to_hash)
|
||||
|
||||
raise CookieOverflow if session_data.size > MAX
|
||||
|
||||
cookie = Hash.new
|
||||
cookie[:value] = session_data
|
||||
unless options[:expire_after].nil?
|
||||
|
@ -114,17 +116,20 @@ module ActionController
|
|||
end
|
||||
|
||||
cookie = build_cookie(@key, cookie.merge(options))
|
||||
unless headers[HTTP_SET_COOKIE].blank?
|
||||
headers[HTTP_SET_COOKIE] << "\n#{cookie}"
|
||||
else
|
||||
headers[HTTP_SET_COOKIE] = cookie
|
||||
end
|
||||
headers[HTTP_SET_COOKIE] = [] if headers[HTTP_SET_COOKIE].blank?
|
||||
headers[HTTP_SET_COOKIE] << cookie
|
||||
end
|
||||
|
||||
[status, headers, body]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def prepare!(env)
|
||||
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
|
||||
env[ENV_SESSION_OPTIONS_KEY] = AbstractStore::OptionsHash.new(self, env, @default_options)
|
||||
end
|
||||
|
||||
# Should be in Rack::Utils soon
|
||||
def build_cookie(key, value)
|
||||
case value
|
||||
|
@ -146,20 +151,46 @@ module ActionController
|
|||
end
|
||||
|
||||
def load_session(env)
|
||||
data = unpacked_cookie_data(env)
|
||||
data = persistent_session_id!(data)
|
||||
[data[:session_id], data]
|
||||
end
|
||||
|
||||
def extract_session_id(env)
|
||||
if data = unpacked_cookie_data(env)
|
||||
persistent_session_id!(data) unless data.empty?
|
||||
data[:session_id]
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def current_session_id(env)
|
||||
env[ENV_SESSION_OPTIONS_KEY][:id]
|
||||
end
|
||||
|
||||
def exists?(env)
|
||||
current_session_id(env).present?
|
||||
end
|
||||
|
||||
def unpacked_cookie_data(env)
|
||||
env["action_dispatch.request.unsigned_session_cookie"] ||= begin
|
||||
stale_session_check! do
|
||||
request = Rack::Request.new(env)
|
||||
session_data = request.cookies[@key]
|
||||
data = unmarshal(session_data) || persistent_session_id!({})
|
||||
[data[:session_id], data]
|
||||
unmarshal(session_data) || {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Marshal a session hash into safe cookie data. Include an integrity hash.
|
||||
def marshal(session)
|
||||
@verifier.generate(persistent_session_id!(session))
|
||||
@verifier.generate(session)
|
||||
end
|
||||
|
||||
# Unmarshal cookie data to a hash and verify its integrity.
|
||||
def unmarshal(cookie)
|
||||
persistent_session_id!(@verifier.verify(cookie)) if cookie
|
||||
@verifier.verify(cookie) if cookie
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
nil
|
||||
end
|
||||
|
@ -207,6 +238,10 @@ module ActionController
|
|||
ActiveSupport::SecureRandom.hex(16)
|
||||
end
|
||||
|
||||
def destroy(env)
|
||||
# session data is stored on client; nothing to do here
|
||||
end
|
||||
|
||||
def persistent_session_id!(data)
|
||||
(data ||= {}).merge!(inject_persistent_session_id(data))
|
||||
end
|
||||
|
|
|
@ -43,6 +43,15 @@ begin
|
|||
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
||||
return false
|
||||
end
|
||||
|
||||
def destroy(env)
|
||||
if sid = current_session_id(env)
|
||||
@pool.delete(sid)
|
||||
end
|
||||
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -450,7 +450,7 @@ module ActionController #:nodoc:
|
|||
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
|
||||
__send__(request_method, action, parameters, session, flash).tap do
|
||||
@request.env.delete 'HTTP_X_REQUESTED_WITH'
|
||||
@request.env.delete 'HTTP_ACCEPT'
|
||||
end
|
||||
|
|
|
@ -92,6 +92,14 @@ module ActionController
|
|||
# end
|
||||
# end
|
||||
module UrlWriter
|
||||
RESERVED_PCHAR = ':@&=+$,;%'
|
||||
SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}"
|
||||
if RUBY_VERSION >= '1.9'
|
||||
UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze
|
||||
else
|
||||
UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze
|
||||
end
|
||||
|
||||
def self.included(base) #:nodoc:
|
||||
ActionController::Routing::Routes.install_helpers(base)
|
||||
base.mattr_accessor :default_url_options
|
||||
|
@ -142,7 +150,7 @@ module ActionController
|
|||
end
|
||||
trailing_slash = options.delete(:trailing_slash) if options.key?(:trailing_slash)
|
||||
url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root]
|
||||
anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options[:anchor]
|
||||
anchor = "##{URI.escape(options.delete(:anchor).to_param.to_s, UNSAFE_PCHAR)}" if options[:anchor]
|
||||
generated = Routing::Routes.generate(options, {})
|
||||
url << (trailing_slash ? generated.sub(/\?|\z/) { "/" + $& } : generated)
|
||||
url << anchor if anchor
|
||||
|
|
|
@ -2,7 +2,7 @@ module ActionPack #:nodoc:
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 3
|
||||
TINY = 8
|
||||
TINY = 9
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
|
@ -877,9 +877,9 @@ module ActionView
|
|||
|
||||
def value_before_type_cast(object, method_name)
|
||||
unless object.nil?
|
||||
object.respond_to?(method_name + "_before_type_cast") ?
|
||||
object.send(method_name + "_before_type_cast") :
|
||||
object.send(method_name)
|
||||
object.respond_to?(method_name) ?
|
||||
object.send(method_name) :
|
||||
object.send(method_name + "_before_type_cast")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -481,7 +481,7 @@ module ActionView
|
|||
end
|
||||
|
||||
zone_options += options_for_select(convert_zones[zones], selected)
|
||||
zone_options
|
||||
zone_options.html_safe
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -440,7 +440,7 @@ module ActionView
|
|||
|
||||
private
|
||||
def html_options_for_form(url_for_options, options, *parameters_for_url)
|
||||
returning options.stringify_keys do |html_options|
|
||||
options.stringify_keys.tap do |html_options|
|
||||
html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
|
||||
html_options["action"] = url_for(url_for_options, *parameters_for_url)
|
||||
end
|
||||
|
|
|
@ -653,7 +653,7 @@ module ActionView
|
|||
# <script> tag.
|
||||
module GeneratorMethods
|
||||
def to_s #:nodoc:
|
||||
returning javascript = @lines * $/ do
|
||||
(@lines * $/).tap do |javascript|
|
||||
if ActionView::Base.debug_rjs
|
||||
source = javascript.dup
|
||||
javascript.replace "try {\n#{source}\n} catch (e) "
|
||||
|
@ -981,8 +981,8 @@ module ActionView
|
|||
end
|
||||
|
||||
def record(line)
|
||||
returning line = "#{line.to_s.chomp.gsub(/\;\z/, '')};" do
|
||||
self << line
|
||||
"#{line.to_s.chomp.gsub(/\;\z/, '')};".tap do |_line|
|
||||
self << _line
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -532,9 +532,14 @@ module ActionView
|
|||
end
|
||||
|
||||
AUTO_LINK_RE = %r{
|
||||
( https?:// | www\. )
|
||||
(?: ([\w+.:-]+:)// | www\. )
|
||||
[^\s<]+
|
||||
}x unless const_defined?(:AUTO_LINK_RE)
|
||||
}x
|
||||
|
||||
# regexps for determining context, used high-volume
|
||||
AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
|
||||
|
||||
AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
|
||||
|
||||
BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
|
||||
|
||||
|
@ -543,26 +548,26 @@ module ActionView
|
|||
def auto_link_urls(text, html_options = {})
|
||||
link_attributes = html_options.stringify_keys
|
||||
text.gsub(AUTO_LINK_RE) do
|
||||
href = $&
|
||||
punctuation = ''
|
||||
left, right = $`, $'
|
||||
# detect already linked URLs and URLs in the middle of a tag
|
||||
if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
|
||||
scheme, href = $1, $&
|
||||
punctuation = []
|
||||
|
||||
if auto_linked?($`, $')
|
||||
# do not change string; URL is already linked
|
||||
href
|
||||
else
|
||||
# don't include trailing punctuation character as part of the URL
|
||||
if href.sub!(/[^\w\/-]$/, '') and punctuation = $& and opening = BRACKETS[punctuation]
|
||||
if href.scan(opening).size > href.scan(punctuation).size
|
||||
href << punctuation
|
||||
punctuation = ''
|
||||
while href.sub!(/[^\w\/-]$/, '')
|
||||
punctuation.push $&
|
||||
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
|
||||
href << punctuation.pop
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
link_text = block_given?? yield(href) : href
|
||||
href = 'http://' + href unless href =~ %r{^[a-z]+://}i
|
||||
href = 'http://' + href unless scheme
|
||||
|
||||
content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation
|
||||
content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation.reverse.join('')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -570,11 +575,10 @@ module ActionView
|
|||
# Turns all email addresses into clickable links. If a block is given,
|
||||
# each email is yielded and the result is used as the link text.
|
||||
def auto_link_email_addresses(text, html_options = {})
|
||||
body = text.dup
|
||||
text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
|
||||
text = $1
|
||||
text.gsub(AUTO_EMAIL_RE) do
|
||||
text = $&
|
||||
|
||||
if body.match(/<a\b[^>]*>(.*)(#{Regexp.escape(text)})(.*)<\/a>/)
|
||||
if auto_linked?($`, $')
|
||||
text
|
||||
else
|
||||
display_text = (block_given?) ? yield(text) : text
|
||||
|
@ -582,6 +586,12 @@ module ActionView
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Detects already linked context or position in the middle of a tag
|
||||
def auto_linked?(left, right)
|
||||
(left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
|
||||
(left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,37 +63,37 @@
|
|||
half_a_minute: "half a minute"
|
||||
less_than_x_seconds:
|
||||
one: "less than 1 second"
|
||||
other: "less than {{count}} seconds"
|
||||
other: "less than %{count} seconds"
|
||||
x_seconds:
|
||||
one: "1 second"
|
||||
other: "{{count}} seconds"
|
||||
other: "%{count} seconds"
|
||||
less_than_x_minutes:
|
||||
one: "less than a minute"
|
||||
other: "less than {{count}} minutes"
|
||||
other: "less than %{count} minutes"
|
||||
x_minutes:
|
||||
one: "1 minute"
|
||||
other: "{{count}} minutes"
|
||||
other: "%{count} minutes"
|
||||
about_x_hours:
|
||||
one: "about 1 hour"
|
||||
other: "about {{count}} hours"
|
||||
other: "about %{count} hours"
|
||||
x_days:
|
||||
one: "1 day"
|
||||
other: "{{count}} days"
|
||||
other: "%{count} days"
|
||||
about_x_months:
|
||||
one: "about 1 month"
|
||||
other: "about {{count}} months"
|
||||
other: "about %{count} months"
|
||||
x_months:
|
||||
one: "1 month"
|
||||
other: "{{count}} months"
|
||||
other: "%{count} months"
|
||||
about_x_years:
|
||||
one: "about 1 year"
|
||||
other: "about {{count}} years"
|
||||
other: "about %{count} years"
|
||||
over_x_years:
|
||||
one: "over 1 year"
|
||||
other: "over {{count}} years"
|
||||
other: "over %{count} years"
|
||||
almost_x_years:
|
||||
one: "almost 1 year"
|
||||
other: "almost {{count}} years"
|
||||
other: "almost %{count} years"
|
||||
prompts:
|
||||
year: "Year"
|
||||
month: "Month"
|
||||
|
@ -106,8 +106,8 @@
|
|||
errors:
|
||||
template:
|
||||
header:
|
||||
one: "1 error prohibited this {{model}} from being saved"
|
||||
other: "{{count}} errors prohibited this {{model}} from being saved"
|
||||
one: "1 error prohibited this %{model} from being saved"
|
||||
other: "%{count} errors prohibited this %{model} from being saved"
|
||||
# The variable :count is also available
|
||||
body: "There were problems with the following fields:"
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ module ActionView #:nodoc:
|
|||
end
|
||||
|
||||
def self.new_and_loaded(path)
|
||||
returning new(path) do |path|
|
||||
path.load!
|
||||
new(path).tap do |_path|
|
||||
_path.load!
|
||||
end
|
||||
end
|
||||
|
||||
|
|
17
vendor/rails/actionpack/test/abstract_unit.rb
vendored
17
vendor/rails/actionpack/test/abstract_unit.rb
vendored
|
@ -58,4 +58,21 @@ class DummyMutex
|
|||
end
|
||||
end
|
||||
|
||||
class ActionController::IntegrationTest < ActiveSupport::TestCase
|
||||
def with_autoload_path(path)
|
||||
path = File.join(File.dirname(__FILE__), "fixtures", path)
|
||||
if ActiveSupport::Dependencies.autoload_paths.include?(path)
|
||||
yield
|
||||
else
|
||||
begin
|
||||
ActiveSupport::Dependencies.autoload_paths << path
|
||||
yield
|
||||
ensure
|
||||
ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
|
||||
ActiveSupport::Dependencies.clear
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ActionController::Reloader.default_lock = DummyMutex.new
|
||||
|
|
|
@ -22,7 +22,6 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
|||
end
|
||||
|
||||
def get_session_id
|
||||
session[:foo]
|
||||
render :text => "#{request.session_options[:id]}"
|
||||
end
|
||||
|
||||
|
@ -45,7 +44,9 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
|||
ActiveRecord::SessionStore.session_class.drop_table!
|
||||
end
|
||||
|
||||
def test_setting_and_getting_session_value
|
||||
%w{ session sql_bypass }.each do |class_name|
|
||||
define_method("test_setting_and_getting_session_value_with_#{class_name}_store") do
|
||||
with_store class_name do
|
||||
with_test_route_set do
|
||||
get '/set_session_value'
|
||||
assert_response :success
|
||||
|
@ -64,6 +65,8 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
|||
assert_equal 'foo: "baz"', response.body
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_getting_nil_session_value
|
||||
with_test_route_set do
|
||||
|
@ -107,6 +110,38 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
|||
end
|
||||
end
|
||||
|
||||
def test_getting_session_value
|
||||
with_test_route_set do
|
||||
get '/set_session_value'
|
||||
assert_response :success
|
||||
assert cookies['_session_id']
|
||||
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists"
|
||||
session_id = cookies["_session_id"]
|
||||
|
||||
get '/call_reset_session'
|
||||
assert_response :success
|
||||
assert_not_equal [], headers['Set-Cookie']
|
||||
|
||||
cookies["_session_id"] = session_id # replace our new session_id with our old, pre-reset session_id
|
||||
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from the database"
|
||||
end
|
||||
end
|
||||
|
||||
def test_getting_from_nonexistent_session
|
||||
with_test_route_set do
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: nil', response.body
|
||||
assert_nil cookies['_session_id'], "should only create session on write, not read"
|
||||
end
|
||||
end
|
||||
|
||||
def test_prevents_session_fixation
|
||||
with_test_route_set do
|
||||
get '/set_session_value'
|
||||
|
@ -171,4 +206,16 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
|||
yield
|
||||
end
|
||||
end
|
||||
|
||||
def with_store(class_name)
|
||||
begin
|
||||
session_class = ActiveRecord::SessionStore.session_class
|
||||
ActiveRecord::SessionStore.session_class = "ActiveRecord::SessionStore::#{class_name.camelize}".constantize
|
||||
yield
|
||||
rescue
|
||||
ActiveRecord::SessionStore.session_class = session_class
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -266,6 +266,14 @@ class IntegrationProcessTest < ActionController::IntegrationTest
|
|||
render :text => "foo(1i): #{params[:"foo(1i)"]}, foo(2i): #{params[:"foo(2i)"]}, filesize: #{params[:file].size}", :status => 200
|
||||
end
|
||||
|
||||
def multipart_post_with_nested_params
|
||||
render :text => "foo: #{params[:foo][0]}, #{params[:foo][1]}; [filesize: #{params[:file_list][0][:content].size}, filesize: #{params[:file_list][1][:content].size}]", :status => 200
|
||||
end
|
||||
|
||||
def multipart_post_with_multiparameter_complex_params
|
||||
render :text => "foo(1i): #{params[:"foo(1i)"]}, foo(2i): #{params[:"foo(2i)"]}, [filesize: #{params[:file_list][0][:content].size}, filesize: #{params[:file_list][1][:content].size}]", :status => 200
|
||||
end
|
||||
|
||||
def post
|
||||
render :text => "Created", :status => 201
|
||||
end
|
||||
|
@ -405,6 +413,24 @@ class IntegrationProcessTest < ActionController::IntegrationTest
|
|||
end
|
||||
end
|
||||
|
||||
def test_multipart_post_with_nested_params
|
||||
with_test_route_set do
|
||||
post '/multipart_post_with_nested_params', :"foo" => ['a', 'b'], :file_list => [{:content => fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg")}, {:content => fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg")}]
|
||||
|
||||
assert_equal 200, status
|
||||
assert_equal "foo: a, b; [filesize: 159528, filesize: 159528]", response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_multipart_post_with_multiparameter_complex_attribute_parameters
|
||||
with_test_route_set do
|
||||
post '/multipart_post_with_multiparameter_complex_params', :"foo(1i)" => "bar", :"foo(2i)" => "baz", :file_list => [{:content => fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg")}, {:content => fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg")}]
|
||||
|
||||
assert_equal 200, status
|
||||
assert_equal "foo(1i): bar, foo(2i): baz, [filesize: 159528, filesize: 159528]", response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_head
|
||||
with_test_route_set do
|
||||
head '/get'
|
||||
|
|
|
@ -14,6 +14,10 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest
|
|||
def read
|
||||
render :text => "File: #{params[:uploaded_data].read}"
|
||||
end
|
||||
|
||||
def read_complex
|
||||
render :text => "File: #{params[:level0][:level1][0][:file_data].read}"
|
||||
end
|
||||
end
|
||||
|
||||
FIXTURE_PATH = File.dirname(__FILE__) + '/../../fixtures/multipart'
|
||||
|
@ -133,6 +137,17 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest
|
|||
end
|
||||
end
|
||||
|
||||
test "uploads and reads file in complex parameter" do
|
||||
with_test_routing do
|
||||
post '/read_complex',
|
||||
:level0 => {
|
||||
:level1 => [ { :file_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") }
|
||||
]
|
||||
}
|
||||
assert_equal "File: Hello", response.body
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def fixture(name)
|
||||
File.open(File.join(FIXTURE_PATH, name), 'rb') do |file|
|
||||
|
|
|
@ -281,12 +281,11 @@ class RescueControllerTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_local_request_when_remote_addr_is_localhost
|
||||
@controller.expects(:request).returns(@request).at_least(4)
|
||||
with_remote_addr '127.0.0.1' do
|
||||
@controller.expects(:request).returns(@request).at_least(10)
|
||||
['127.0.0.1', '127.0.0.127', '::1', '0:0:0:0:0:0:0:1', '0:0:0:0:0:0:0:1%0'].each do |ip_address|
|
||||
with_remote_addr ip_address do
|
||||
assert @controller.send(:local_request?)
|
||||
end
|
||||
with_remote_addr '::1' do
|
||||
assert @controller.send(:local_request?)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -34,6 +34,15 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
render :text => "foo: #{session[:foo].inspect}; id: #{request.session_options[:id]}"
|
||||
end
|
||||
|
||||
def get_session_id_only
|
||||
render :text => "id: #{request.session_options[:id]}"
|
||||
end
|
||||
|
||||
def call_session_clear
|
||||
session.clear
|
||||
head :ok
|
||||
end
|
||||
|
||||
def call_reset_session
|
||||
reset_session
|
||||
head :ok
|
||||
|
@ -44,6 +53,12 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
head :ok
|
||||
end
|
||||
|
||||
def set_session_value_and_cookie
|
||||
cookies["foo"] = "bar"
|
||||
session[:foo] = "bar"
|
||||
render :text => Rack::Utils.escape(Verifier.generate(session.to_hash))
|
||||
end
|
||||
|
||||
def rescue_action(e) raise end
|
||||
end
|
||||
|
||||
|
@ -96,7 +111,7 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
with_test_route_set do
|
||||
get '/set_session_value'
|
||||
assert_response :success
|
||||
assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly",
|
||||
assert_equal ["_myapp_session=#{response.body}; path=/; HttpOnly"],
|
||||
headers['Set-Cookie']
|
||||
end
|
||||
end
|
||||
|
@ -121,6 +136,10 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
get '/get_session_id'
|
||||
assert_response :success
|
||||
assert_equal "foo: \"bar\"; id: #{session_id}", response.body
|
||||
|
||||
get '/get_session_id_only'
|
||||
assert_response :success
|
||||
assert_equal "id: #{session_id}", response.body, "should be able to read session id without accessing the session hash"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -164,7 +183,7 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
get '/set_session_value'
|
||||
assert_response :success
|
||||
session_payload = response.body
|
||||
assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly",
|
||||
assert_equal ["_myapp_session=#{response.body}; path=/; HttpOnly"],
|
||||
headers['Set-Cookie']
|
||||
|
||||
get '/call_reset_session'
|
||||
|
@ -178,6 +197,57 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
end
|
||||
end
|
||||
|
||||
def test_setting_session_value_after_session_clear
|
||||
with_test_route_set do
|
||||
get '/set_session_value'
|
||||
assert_response :success
|
||||
session_payload = response.body
|
||||
assert_equal ["_myapp_session=#{response.body}; path=/; HttpOnly"],
|
||||
headers['Set-Cookie']
|
||||
|
||||
get '/call_session_clear'
|
||||
assert_response :success
|
||||
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: nil', response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_getting_from_nonexistent_session
|
||||
with_test_route_set do
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: nil', response.body
|
||||
assert_nil headers['Set-Cookie'], "should only create session on write, not read"
|
||||
end
|
||||
end
|
||||
|
||||
# {:foo=>#<SessionAutoloadTest::Foo bar:"baz">, :session_id=>"ce8b0752a6ab7c7af3cdb8a80e6b9e46"}
|
||||
SignedSerializedCookie = "BAh7BzoIZm9vbzodU2Vzc2lvbkF1dG9sb2FkVGVzdDo6Rm9vBjoJQGJhciIIYmF6Og9zZXNzaW9uX2lkIiVjZThiMDc1MmE2YWI3YzdhZjNjZGI4YTgwZTZiOWU0Ng==--2bf3af1ae8bd4e52b9ac2099258ace0c380e601c"
|
||||
|
||||
def test_deserializes_unloaded_classes_on_get_id
|
||||
with_test_route_set do
|
||||
with_autoload_path "session_autoload_test" do
|
||||
cookies[SessionKey] = SignedSerializedCookie
|
||||
get '/get_session_id_only'
|
||||
assert_response :success
|
||||
assert_equal 'id: ce8b0752a6ab7c7af3cdb8a80e6b9e46', response.body, "should auto-load unloaded class"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_deserializes_unloaded_classes_on_get_value
|
||||
with_test_route_set do
|
||||
with_autoload_path "session_autoload_test" do
|
||||
cookies[SessionKey] = SignedSerializedCookie
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: #<SessionAutoloadTest::Foo bar:"baz">', response.body, "should auto-load unloaded class"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_persistent_session_id
|
||||
with_test_route_set do
|
||||
cookies[SessionKey] = SignedBar
|
||||
|
@ -193,6 +263,14 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
end
|
||||
end
|
||||
|
||||
def test_setting_session_value_and_cookie
|
||||
with_test_route_set do
|
||||
get '/set_session_value_and_cookie'
|
||||
assert_response :success
|
||||
assert_equal({"_myapp_session" => response.body, "foo" => "bar"}, cookies)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def with_test_route_set
|
||||
with_routing do |set|
|
||||
|
|
|
@ -12,12 +12,16 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
|||
head :ok
|
||||
end
|
||||
|
||||
def set_serialized_session_value
|
||||
session[:foo] = SessionAutoloadTest::Foo.new
|
||||
head :ok
|
||||
end
|
||||
|
||||
def get_session_value
|
||||
render :text => "foo: #{session[:foo].inspect}"
|
||||
end
|
||||
|
||||
def get_session_id
|
||||
session[:foo]
|
||||
render :text => "#{request.session_options[:id]}"
|
||||
end
|
||||
|
||||
|
@ -82,6 +86,34 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
|||
end
|
||||
end
|
||||
|
||||
def test_getting_session_value_after_session_reset
|
||||
with_test_route_set do
|
||||
get '/set_session_value'
|
||||
assert_response :success
|
||||
assert cookies['_session_id']
|
||||
session_id = cookies["_session_id"]
|
||||
|
||||
get '/call_reset_session'
|
||||
assert_response :success
|
||||
assert_not_equal [], headers['Set-Cookie']
|
||||
|
||||
cookies["_session_id"] = session_id # replace our new session_id with our old, pre-reset session_id
|
||||
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from memcached"
|
||||
end
|
||||
end
|
||||
|
||||
def test_getting_from_nonexistent_session
|
||||
with_test_route_set do
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: nil', response.body
|
||||
assert_nil cookies['_session_id'], "should only create session on write, not read"
|
||||
end
|
||||
end
|
||||
|
||||
def test_getting_session_id
|
||||
with_test_route_set do
|
||||
get '/set_session_value'
|
||||
|
@ -91,7 +123,38 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
|||
|
||||
get '/get_session_id'
|
||||
assert_response :success
|
||||
assert_equal session_id, response.body
|
||||
assert_equal session_id, response.body, "should be able to read session id without accessing the session hash"
|
||||
end
|
||||
end
|
||||
|
||||
def test_doesnt_write_session_cookie_if_session_id_is_already_exists
|
||||
with_test_route_set do
|
||||
get '/set_session_value'
|
||||
assert_response :success
|
||||
assert cookies['_session_id']
|
||||
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists"
|
||||
end
|
||||
end
|
||||
|
||||
def test_deserializes_unloaded_class
|
||||
with_test_route_set do
|
||||
with_autoload_path "session_autoload_test" do
|
||||
get '/set_serialized_session_value'
|
||||
assert_response :success
|
||||
assert cookies['_session_id']
|
||||
end
|
||||
with_autoload_path "session_autoload_test" do
|
||||
get '/get_session_id'
|
||||
assert_response :success
|
||||
end
|
||||
with_autoload_path "session_autoload_test" do
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: #<SessionAutoloadTest::Foo bar:"baz">', response.body, "should auto-load unloaded class"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -134,9 +134,15 @@ class UrlWriterTests < ActionController::TestCase
|
|||
)
|
||||
end
|
||||
|
||||
def test_anchor_should_be_cgi_escaped
|
||||
assert_equal('/c/a#anc%2Fhor',
|
||||
W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('anc/hor'))
|
||||
def test_anchor_should_escape_unsafe_pchar
|
||||
assert_equal('/c/a#%23anchor',
|
||||
W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('#anchor'))
|
||||
)
|
||||
end
|
||||
|
||||
def test_anchor_should_not_escape_safe_pchar
|
||||
assert_equal('/c/a#name=user&email=user@domain.com',
|
||||
W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('name=user&email=user@domain.com'))
|
||||
)
|
||||
end
|
||||
|
||||
|
|
10
vendor/rails/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb
vendored
Normal file
10
vendor/rails/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
module SessionAutoloadTest
|
||||
class Foo
|
||||
def initialize(bar='baz')
|
||||
@bar = bar
|
||||
end
|
||||
def inspect
|
||||
"#<#{self.class} bar:#{@bar.inspect}>"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -91,6 +91,16 @@ end
|
|||
class FormHelperTest < ActionView::TestCase
|
||||
tests ActionView::Helpers::FormHelper
|
||||
|
||||
class Developer
|
||||
def name_before_type_cast
|
||||
"David"
|
||||
end
|
||||
|
||||
def name
|
||||
"Santiago"
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
super
|
||||
|
||||
|
@ -256,6 +266,13 @@ class FormHelperTest < ActionView::TestCase
|
|||
assert_equal object_name, "post[]"
|
||||
end
|
||||
|
||||
def test_text_field_from_a_user_defined_method
|
||||
@developer = Developer.new
|
||||
assert_dom_equal(
|
||||
'<input id="developer_name" name="developer[name]" size="30" type="text" value="Santiago" />', text_field("developer", "name")
|
||||
)
|
||||
end
|
||||
|
||||
def test_hidden_field
|
||||
assert_dom_equal '<input id="post_title" name="post[title]" type="hidden" value="Hello World" />',
|
||||
hidden_field("post", "title")
|
||||
|
|
|
@ -280,6 +280,10 @@ class FormOptionsHelperTest < ActionView::TestCase
|
|||
opts
|
||||
end
|
||||
|
||||
def test_time_zone_options_returns_html_safe_string
|
||||
assert time_zone_options_for_select.html_safe?
|
||||
end
|
||||
|
||||
def test_select
|
||||
@post = Post.new
|
||||
@post.category = "<mus>"
|
||||
|
|
|
@ -296,6 +296,7 @@ class TextHelperTest < ActionView::TestCase
|
|||
assert_equal %(<p>Link #{link_result_with_options}</p>), auto_link("<p>Link #{link_raw}</p>", :all, {:target => "_blank"})
|
||||
assert_equal %(Go to #{link_result}.), auto_link(%(Go to #{link_raw}.))
|
||||
assert_equal %(<p>Go to #{link_result}, then say hello to #{email_result}.</p>), auto_link(%(<p>Go to #{link_raw}, then say hello to #{email_raw}.</p>))
|
||||
assert_equal %(#{link_result} #{link_result}), auto_link(%(#{link_result} #{link_raw}))
|
||||
|
||||
email2_raw = '+david@loudthinking.com'
|
||||
email2_result = %{<a href="mailto:#{email2_raw}">#{email2_raw}</a>}
|
||||
|
@ -368,24 +369,38 @@ class TextHelperTest < ActionView::TestCase
|
|||
end
|
||||
|
||||
def test_auto_link_other_protocols
|
||||
silence_warnings do
|
||||
begin
|
||||
old_re_value = ActionView::Helpers::TextHelper::AUTO_LINK_RE
|
||||
ActionView::Helpers::TextHelper.const_set :AUTO_LINK_RE, %r{(ftp://)[^\s<]+}
|
||||
link_raw = 'ftp://example.com/file.txt'
|
||||
link_result = generate_result(link_raw)
|
||||
assert_equal %(Download #{link_result}), auto_link("Download #{link_raw}")
|
||||
ensure
|
||||
ActionView::Helpers::TextHelper.const_set :AUTO_LINK_RE, old_re_value
|
||||
end
|
||||
end
|
||||
ftp_raw = 'ftp://example.com/file.txt'
|
||||
assert_equal %(Download #{generate_result(ftp_raw)}), auto_link("Download #{ftp_raw}")
|
||||
|
||||
file_scheme = 'file:///home/username/RomeoAndJuliet.pdf'
|
||||
z39_scheme = 'z39.50r://host:696/db'
|
||||
chrome_scheme = 'chrome://package/section/path'
|
||||
view_source = 'view-source:http://en.wikipedia.org/wiki/URI_scheme'
|
||||
assert_equal generate_result(z39_scheme), auto_link(z39_scheme)
|
||||
assert_equal generate_result(chrome_scheme), auto_link(chrome_scheme)
|
||||
assert_equal generate_result(view_source), auto_link(view_source)
|
||||
end
|
||||
|
||||
def test_auto_link_already_linked
|
||||
linked1 = generate_result('Ruby On Rails', 'http://www.rubyonrails.com')
|
||||
linked2 = generate_result('www.rubyonrails.com', 'http://www.rubyonrails.com')
|
||||
linked2 = %('<a href="http://www.example.com">www.example.com</a>')
|
||||
linked3 = %('<a href="http://www.example.com" rel="nofollow">www.example.com</a>')
|
||||
linked4 = %('<a href="http://www.example.com"><b>www.example.com</b></a>')
|
||||
linked5 = %('<a href="#close">close</a> <a href="http://www.example.com"><b>www.example.com</b></a>')
|
||||
assert_equal linked1, auto_link(linked1)
|
||||
assert_equal linked2, auto_link(linked2)
|
||||
assert_equal linked3, auto_link(linked3)
|
||||
assert_equal linked4, auto_link(linked4)
|
||||
assert_equal linked5, auto_link(linked5)
|
||||
|
||||
linked_email = %Q(<a href="mailto:david@loudthinking.com">Mail me</a>)
|
||||
assert_equal linked_email, auto_link(linked_email)
|
||||
end
|
||||
|
||||
def test_auto_link_within_tags
|
||||
link_raw = 'http://www.rubyonrails.org/images/rails.png'
|
||||
link_result = %Q(<img src="#{link_raw}" />)
|
||||
assert_equal link_result, auto_link(link_result)
|
||||
end
|
||||
|
||||
def test_auto_link_with_brackets
|
||||
|
@ -405,12 +420,6 @@ class TextHelperTest < ActionView::TestCase
|
|||
assert_equal "{link: #{link3_result}}", auto_link("{link: #{link3_raw}}")
|
||||
end
|
||||
|
||||
def test_auto_link_in_tags
|
||||
link_raw = 'http://www.rubyonrails.org/images/rails.png'
|
||||
link_result = %Q(<img src="#{link_raw}" />)
|
||||
assert_equal link_result, auto_link(link_result)
|
||||
end
|
||||
|
||||
def test_auto_link_at_eol
|
||||
url1 = "http://api.rubyonrails.com/Foo.html"
|
||||
url2 = "http://www.ruby-doc.org/core/Bar.html"
|
||||
|
@ -425,12 +434,32 @@ class TextHelperTest < ActionView::TestCase
|
|||
assert_equal %(<p><a href="#{url}">#{url[0...7]}...</a><br /><a href="mailto:#{email}">#{email[0...7]}...</a><br /></p>), auto_link("<p>#{url}<br />#{email}<br /></p>") { |url| truncate(url, :length => 10) }
|
||||
end
|
||||
|
||||
def test_auto_link_with_block_with_html
|
||||
pic = "http://example.com/pic.png"
|
||||
url = "http://example.com/album?a&b=c"
|
||||
|
||||
assert_equal %(My pic: <a href="#{pic}"><img src="#{pic}" width="160px"></a> -- full album here #{generate_result(url)}), auto_link("My pic: #{pic} -- full album here #{url}") { |link|
|
||||
if link =~ /\.(jpg|gif|png|bmp|tif)$/i
|
||||
raw %(<img src="#{link}" width="160px">)
|
||||
else
|
||||
link
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def test_auto_link_with_options_hash
|
||||
assert_dom_equal 'Welcome to my new blog at <a href="http://www.myblog.com/" class="menu" target="_blank">http://www.myblog.com/</a>. Please e-mail me at <a href="mailto:me@email.com" class="menu" target="_blank">me@email.com</a>.',
|
||||
auto_link("Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.",
|
||||
:link => :all, :html => { :class => "menu", :target => "_blank" })
|
||||
end
|
||||
|
||||
def test_auto_link_with_multiple_trailing_punctuations
|
||||
url = "http://youtube.com"
|
||||
url_result = generate_result(url)
|
||||
assert_equal url_result, auto_link(url)
|
||||
assert_equal "(link: #{url_result}).", auto_link("(link: #{url}).")
|
||||
end
|
||||
|
||||
def test_cycle_class
|
||||
value = Cycle.new("one", 2, "3")
|
||||
assert_equal("one", value.to_s)
|
||||
|
|
5
vendor/rails/activerecord/CHANGELOG
vendored
5
vendor/rails/activerecord/CHANGELOG
vendored
|
@ -1,8 +1,5 @@
|
|||
*2.3.9 (September 4, 2010)*
|
||||
*2.3.8 (May 24, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
||||
|
||||
*2.3.7 (May 24, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
|
2
vendor/rails/activerecord/Rakefile
vendored
2
vendor/rails/activerecord/Rakefile
vendored
|
@ -192,7 +192,7 @@ spec = Gem::Specification.new do |s|
|
|||
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
||||
end
|
||||
|
||||
s.add_dependency('activesupport', '= 2.3.8' + PKG_BUILD)
|
||||
s.add_dependency('activesupport', '= 2.3.9' + PKG_BUILD)
|
||||
|
||||
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
|
||||
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"
|
||||
|
|
|
@ -12,6 +12,8 @@ require 'rbench'
|
|||
|
||||
__DIR__ = File.dirname(__FILE__)
|
||||
$:.unshift "#{__DIR__}/../lib"
|
||||
$:.unshift "#{__DIR__}/../../activesupport/lib"
|
||||
|
||||
require 'active_record'
|
||||
|
||||
conn = { :adapter => 'mysql',
|
||||
|
|
|
@ -282,7 +282,11 @@ module ActiveRecord
|
|||
end
|
||||
through_records.flatten!
|
||||
else
|
||||
records.first.class.preload_associations(records, through_association)
|
||||
options = {}
|
||||
options[:include] = reflection.options[:include] || reflection.options[:source] if reflection.options[:conditions]
|
||||
options[:order] = reflection.options[:order]
|
||||
options[:conditions] = reflection.options[:conditions]
|
||||
records.first.class.preload_associations(records, through_association, options)
|
||||
through_records = records.map {|record| record.send(through_association)}.flatten
|
||||
end
|
||||
through_records.compact!
|
||||
|
@ -357,7 +361,13 @@ module ActiveRecord
|
|||
table_name = reflection.klass.quoted_table_name
|
||||
|
||||
if interface = reflection.options[:as]
|
||||
conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'"
|
||||
parent_type = if reflection.active_record.abstract_class?
|
||||
self.base_class.sti_name
|
||||
else
|
||||
reflection.active_record.sti_name
|
||||
end
|
||||
|
||||
conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{parent_type}'"
|
||||
else
|
||||
foreign_key = reflection.primary_key_name
|
||||
conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} #{in_or_equals_for_ids(ids)}"
|
||||
|
|
|
@ -1782,7 +1782,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def using_limitable_reflections?(reflections)
|
||||
reflections.collect(&:collection?).length.zero?
|
||||
reflections.none?(&:collection?)
|
||||
end
|
||||
|
||||
def column_aliases(join_dependency)
|
||||
|
|
|
@ -234,9 +234,10 @@ module ActiveRecord
|
|||
# See destroy for more info.
|
||||
def destroy_all
|
||||
load_target
|
||||
destroy(@target)
|
||||
destroy(@target).tap do
|
||||
reset_target!
|
||||
end
|
||||
end
|
||||
|
||||
def create(attrs = {})
|
||||
if attrs.is_a?(Array)
|
||||
|
@ -349,7 +350,17 @@ module ActiveRecord
|
|||
begin
|
||||
if !loaded?
|
||||
if @target.is_a?(Array) && @target.any?
|
||||
@target = find_target + @target.find_all {|t| t.new_record? }
|
||||
@target = find_target.map do |f|
|
||||
i = @target.index(f)
|
||||
if i
|
||||
@target.delete_at(i).tap do |t|
|
||||
keys = ["id"] + t.changes.keys + (f.attribute_names - t.attribute_names)
|
||||
t.attributes = f.attributes.except(*keys)
|
||||
end
|
||||
else
|
||||
f
|
||||
end
|
||||
end + @target
|
||||
else
|
||||
@target = find_target
|
||||
end
|
||||
|
@ -364,6 +375,17 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def method_missing(method, *args)
|
||||
case method.to_s
|
||||
when 'find_or_create'
|
||||
return find(:first, :conditions => args.first) || create(args.first)
|
||||
when /^find_or_create_by_(.*)$/
|
||||
rest = $1
|
||||
return send("find_by_#{rest}", *args) ||
|
||||
method_missing("create_by_#{rest}", *args)
|
||||
when /^create_by_(.*)$/
|
||||
return create($1.split('_and_').zip(args).inject({}) { |h,kv| k,v=kv ; h[k] = v ; h })
|
||||
end
|
||||
|
||||
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
|
||||
if block_given?
|
||||
super { |*block_args| yield(*block_args) }
|
||||
|
@ -411,7 +433,14 @@ module ActiveRecord
|
|||
callback(:before_add, record)
|
||||
yield(record) if block_given?
|
||||
@target ||= [] unless loaded?
|
||||
@target << record unless @reflection.options[:uniq] && @target.include?(record)
|
||||
index = @target.index(record)
|
||||
unless @reflection.options[:uniq] && index
|
||||
if index
|
||||
@target[index] = record
|
||||
else
|
||||
@target << record
|
||||
end
|
||||
end
|
||||
callback(:after_add, record)
|
||||
set_inverse_instance(record, @owner)
|
||||
record
|
||||
|
|
|
@ -230,10 +230,6 @@ module ActiveRecord
|
|||
# It's also possible to instantiate related objects, so a Client class belonging to the clients
|
||||
# table with a +master_id+ foreign key can instantiate master through Client#master.
|
||||
def method_missing(method_id, *args, &block)
|
||||
if method_id == :to_ary || method_id == :to_str
|
||||
raise NoMethodError, "undefined method `#{method_id}' for #{inspect}:#{self.class}"
|
||||
end
|
||||
|
||||
method_name = method_id.to_s
|
||||
|
||||
if self.class.private_method_defined?(method_name)
|
||||
|
|
|
@ -146,12 +146,12 @@ module ActiveRecord
|
|||
# add_autosave_association_callbacks(reflect_on_association(name))
|
||||
# end
|
||||
ASSOCIATION_TYPES.each do |type|
|
||||
module_eval %{
|
||||
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
||||
def #{type}(name, options = {})
|
||||
super
|
||||
add_autosave_association_callbacks(reflect_on_association(name))
|
||||
end
|
||||
}
|
||||
CODE
|
||||
end
|
||||
|
||||
# Adds a validate and save callback for the association as specified by
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'yaml'
|
||||
require 'set'
|
||||
require 'active_support/core_ext/class/attribute'
|
||||
|
||||
module ActiveRecord #:nodoc:
|
||||
# Generic Active Record exception class.
|
||||
|
@ -515,7 +516,7 @@ module ActiveRecord #:nodoc:
|
|||
@@timestamped_migrations = true
|
||||
|
||||
# Determine whether to store the full constant name including namespace when using STI
|
||||
superclass_delegating_accessor :store_full_sti_class
|
||||
class_attribute :store_full_sti_class
|
||||
self.store_full_sti_class = false
|
||||
|
||||
# Stores the default scope for the class
|
||||
|
@ -935,11 +936,18 @@ module ActiveRecord #:nodoc:
|
|||
def reset_counters(id, *counters)
|
||||
object = find(id)
|
||||
counters.each do |association|
|
||||
child_class = reflect_on_association(association).klass
|
||||
counter_name = child_class.reflect_on_association(self.name.downcase.to_sym).counter_cache_column
|
||||
child_class = reflect_on_association(association.to_sym).klass
|
||||
belongs_name = self.name.demodulize.underscore.to_sym
|
||||
counter_name = child_class.reflect_on_association(belongs_name).counter_cache_column
|
||||
value = object.send(association).count
|
||||
|
||||
connection.update("UPDATE #{quoted_table_name} SET #{connection.quote_column_name(counter_name)} = #{object.send(association).count} WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}", "#{name} UPDATE")
|
||||
connection.update(<<-CMD, "#{name} UPDATE")
|
||||
UPDATE #{quoted_table_name}
|
||||
SET #{connection.quote_column_name(counter_name)} = #{value}
|
||||
WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}
|
||||
CMD
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# A generic "counter updater" implementation, intended primarily to be
|
||||
|
@ -972,19 +980,13 @@ module ActiveRecord #:nodoc:
|
|||
# # SET comment_count = comment_count + 1,
|
||||
# # WHERE id IN (10, 15)
|
||||
def update_counters(id, counters)
|
||||
updates = counters.inject([]) { |list, (counter_name, increment)|
|
||||
sign = increment < 0 ? "-" : "+"
|
||||
list << "#{connection.quote_column_name(counter_name)} = COALESCE(#{connection.quote_column_name(counter_name)}, 0) #{sign} #{increment.abs}"
|
||||
}.join(", ")
|
||||
|
||||
if id.is_a?(Array)
|
||||
ids_list = id.map {|i| quote_value(i)}.join(', ')
|
||||
condition = "IN (#{ids_list})"
|
||||
else
|
||||
condition = "= #{quote_value(id)}"
|
||||
updates = counters.map do |counter_name, value|
|
||||
operator = value < 0 ? '-' : '+'
|
||||
quoted_column = connection.quote_column_name(counter_name)
|
||||
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
|
||||
end
|
||||
|
||||
update_all(updates, "#{connection.quote_column_name(primary_key)} #{condition}")
|
||||
update_all(updates.join(', '), primary_key => id )
|
||||
end
|
||||
|
||||
# Increment a number field by one, usually representing a count.
|
||||
|
@ -1284,6 +1286,8 @@ module ActiveRecord #:nodoc:
|
|||
|
||||
# Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
|
||||
def class_name(table_name = table_name) # :nodoc:
|
||||
ActiveSupport::Deprecation.warn("ActiveRecord::Base#class_name is deprecated and will be removed in Rails 2.3.9.", caller)
|
||||
|
||||
# remove any prefix and/or suffix from the table name
|
||||
class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize
|
||||
class_name = class_name.singularize if pluralize_table_names
|
||||
|
@ -2642,7 +2646,7 @@ module ActiveRecord #:nodoc:
|
|||
# Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either
|
||||
# instance will affect the other.
|
||||
def becomes(klass)
|
||||
returning klass.new do |became|
|
||||
klass.new.tap do |became|
|
||||
became.instance_variable_set("@attributes", @attributes)
|
||||
became.instance_variable_set("@attributes_cache", @attributes_cache)
|
||||
became.instance_variable_set("@new_record", new_record?)
|
||||
|
@ -2660,12 +2664,20 @@ module ActiveRecord #:nodoc:
|
|||
# Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will
|
||||
# fail and false will be returned.
|
||||
def update_attributes(attributes)
|
||||
with_transaction_returning_status(:update_attributes_inside_transaction, attributes)
|
||||
end
|
||||
|
||||
def update_attributes_inside_transaction(attributes) #:nodoc:
|
||||
self.attributes = attributes
|
||||
save
|
||||
end
|
||||
|
||||
# Updates an object just like Base.update_attributes but calls save! instead of save so an exception is raised if the record is invalid.
|
||||
def update_attributes!(attributes)
|
||||
with_transaction_returning_status(:update_attributes_inside_transaction!, attributes)
|
||||
end
|
||||
|
||||
def update_attributes_inside_transaction!(attributes) #:nodoc:
|
||||
self.attributes = attributes
|
||||
save!
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ module ActiveRecord
|
|||
##
|
||||
# :singleton-method:
|
||||
# The connection handler
|
||||
superclass_delegating_accessor :connection_handler
|
||||
class_attribute :connection_handler
|
||||
self.connection_handler = ConnectionAdapters::ConnectionHandler.new
|
||||
|
||||
# Returns the connection currently associated with the class. This can
|
||||
|
|
|
@ -195,6 +195,7 @@ module ActiveRecord
|
|||
# remove_column(:suppliers, :qualification)
|
||||
# remove_columns(:suppliers, :qualification, :experience)
|
||||
def remove_column(table_name, *column_names)
|
||||
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
|
||||
column_names.flatten.each do |column_name|
|
||||
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
|
||||
end
|
||||
|
|
|
@ -211,6 +211,12 @@ module ActiveRecord
|
|||
log_info(sql, name, 0)
|
||||
nil
|
||||
end
|
||||
rescue SystemExit, SignalException, NoMemoryError => e
|
||||
# Don't re-wrap these exceptions. They are probably not being caused by invalid
|
||||
# sql, but rather some external stimulus beyond the responsibilty of this code.
|
||||
# Additionaly, wrapping these exceptions with StatementInvalid would lead to
|
||||
# meaningful loss of data, such as losing SystemExit#status.
|
||||
raise e
|
||||
rescue Exception => e
|
||||
# Log message and raise exception.
|
||||
# Set last_verification to 0, so that connection gets verified
|
||||
|
|
|
@ -315,6 +315,7 @@ module ActiveRecord
|
|||
rows = []
|
||||
result.each { |row| rows << row }
|
||||
result.free
|
||||
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
||||
rows
|
||||
end
|
||||
|
||||
|
@ -638,6 +639,7 @@ module ActiveRecord
|
|||
result = execute(sql, name)
|
||||
rows = result.all_hashes
|
||||
result.free
|
||||
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
||||
rows
|
||||
end
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ module ActiveRecord
|
|||
module ConnectionAdapters #:nodoc:
|
||||
class SQLite3Adapter < SQLiteAdapter # :nodoc:
|
||||
def table_structure(table_name)
|
||||
returning structure = @connection.table_info(quote_table_name(table_name)) do
|
||||
@connection.table_info(quote_table_name(table_name)).tap do |structure|
|
||||
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -269,6 +269,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def remove_column(table_name, *column_names) #:nodoc:
|
||||
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
|
||||
column_names.flatten.each do |column_name|
|
||||
alter_table(table_name) do |definition|
|
||||
definition.columns.delete(definition[column_name])
|
||||
|
@ -329,7 +330,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def table_structure(table_name)
|
||||
returning structure = execute("PRAGMA table_info(#{quote_table_name(table_name)})") do
|
||||
execute("PRAGMA table_info(#{quote_table_name(table_name)})").tap do |structure|
|
||||
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -44,7 +44,7 @@ module ActiveRecord
|
|||
base.alias_method_chain :update, :dirty
|
||||
base.alias_method_chain :reload, :dirty
|
||||
|
||||
base.superclass_delegating_accessor :partial_updates
|
||||
base.class_attribute :partial_updates
|
||||
base.partial_updates = true
|
||||
|
||||
base.send(:extend, ClassMethods)
|
||||
|
|
|
@ -11,23 +11,23 @@ en:
|
|||
accepted: "must be accepted"
|
||||
empty: "can't be empty"
|
||||
blank: "can't be blank"
|
||||
too_long: "is too long (maximum is {{count}} characters)"
|
||||
too_short: "is too short (minimum is {{count}} characters)"
|
||||
wrong_length: "is the wrong length (should be {{count}} characters)"
|
||||
too_long: "is too long (maximum is %{count} characters)"
|
||||
too_short: "is too short (minimum is %{count} characters)"
|
||||
wrong_length: "is the wrong length (should be %{count} characters)"
|
||||
taken: "has already been taken"
|
||||
not_a_number: "is not a number"
|
||||
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}}"
|
||||
less_than: "must be less than {{count}}"
|
||||
less_than_or_equal_to: "must be less than or equal to {{count}}"
|
||||
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}"
|
||||
less_than: "must be less than %{count}"
|
||||
less_than_or_equal_to: "must be less than or equal to %{count}"
|
||||
odd: "must be odd"
|
||||
even: "must be even"
|
||||
record_invalid: "Validation failed: {{errors}}"
|
||||
record_invalid: "Validation failed: %{errors}"
|
||||
# Append your own errors here or at the model/attributes scope.
|
||||
|
||||
full_messages:
|
||||
format: "{{attribute}} {{message}}"
|
||||
format: "%{attribute} %{message}"
|
||||
|
||||
# You can define own errors for models or model attributes.
|
||||
# The values :model, :attribute and :value are always available for interpolation.
|
||||
|
@ -35,7 +35,7 @@ en:
|
|||
# For example,
|
||||
# models:
|
||||
# user:
|
||||
# blank: "This is a custom blank message for {{model}}: {{attribute}}"
|
||||
# blank: "This is a custom blank message for %{model}: %{attribute}"
|
||||
# attributes:
|
||||
# login:
|
||||
# blank: "This is a custom blank message for User login"
|
||||
|
|
|
@ -128,6 +128,7 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
@destroyed = true
|
||||
freeze
|
||||
end
|
||||
|
||||
|
|
|
@ -516,7 +516,7 @@ module ActiveRecord
|
|||
raise DuplicateMigrationNameError.new(name.camelize)
|
||||
end
|
||||
|
||||
klasses << returning(MigrationProxy.new) do |migration|
|
||||
klasses << (MigrationProxy.new).tap do |migration|
|
||||
migration.name = name.camelize
|
||||
migration.version = version
|
||||
migration.filename = file
|
||||
|
|
|
@ -8,10 +8,7 @@ module ActiveRecord
|
|||
#
|
||||
# You can define a scope that applies to all finders using ActiveRecord::Base.default_scope.
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
extend ClassMethods
|
||||
named_scope :scoped, lambda { |scope| scope }
|
||||
end
|
||||
base.extend ClassMethods
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
@ -19,6 +16,10 @@ module ActiveRecord
|
|||
read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
|
||||
end
|
||||
|
||||
def scoped(scope, &block)
|
||||
Scope.new(self, scope, &block)
|
||||
end
|
||||
|
||||
# Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
|
||||
# such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.
|
||||
#
|
||||
|
@ -84,21 +85,25 @@ module ActiveRecord
|
|||
# assert_equal expected_options, Shirt.colored('red').proxy_options
|
||||
def named_scope(name, options = {}, &block)
|
||||
name = name.to_sym
|
||||
|
||||
scopes[name] = lambda do |parent_scope, *args|
|
||||
Scope.new(parent_scope, case options
|
||||
when Hash
|
||||
options
|
||||
when Proc
|
||||
if self.model_name != parent_scope.model_name
|
||||
options.bind(parent_scope).call(*args)
|
||||
else
|
||||
options.call(*args)
|
||||
end
|
||||
end, &block)
|
||||
end
|
||||
(class << self; self end).instance_eval do
|
||||
define_method name do |*args|
|
||||
|
||||
singleton_class.send :define_method, name do |*args|
|
||||
scopes[name].call(self, *args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Scope
|
||||
attr_reader :proxy_scope, :proxy_options, :current_scoped_methods_when_defined
|
||||
|
|
|
@ -286,7 +286,9 @@ module ActiveRecord
|
|||
assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy])
|
||||
|
||||
elsif attributes['id']
|
||||
raise_nested_attributes_record_not_found(association_name, attributes['id'])
|
||||
existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
|
||||
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
||||
self.send(association_name.to_s+'=', existing_record)
|
||||
|
||||
elsif !reject_new_record?(association_name, attributes)
|
||||
method = "build_#{association_name}"
|
||||
|
@ -356,11 +358,16 @@ module ActiveRecord
|
|||
unless reject_new_record?(association_name, attributes)
|
||||
association.build(attributes.except(*UNASSIGNABLE_KEYS))
|
||||
end
|
||||
|
||||
elsif existing_records.size == 0 # Existing record but not yet associated
|
||||
existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
|
||||
association.send(:add_record_to_target_with_callbacks, existing_record) unless association.loaded?
|
||||
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
||||
|
||||
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
|
||||
association.send(:add_record_to_target_with_callbacks, existing_record) unless association.loaded?
|
||||
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
||||
else
|
||||
raise_nested_attributes_record_not_found(association_name, attributes['id'])
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -380,7 +387,7 @@ module ActiveRecord
|
|||
ConnectionAdapters::Column.value_to_boolean(hash['_destroy'])
|
||||
end
|
||||
|
||||
# Determines if a new record should be build by checking for
|
||||
# Determines if a new record should be built by checking for
|
||||
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
||||
# association and evaluates to +true+.
|
||||
def reject_new_record?(association_name, attributes)
|
||||
|
@ -396,9 +403,5 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
def raise_nested_attributes_record_not_found(association_name, record_id)
|
||||
reflection = self.class.reflect_on_association(association_name)
|
||||
raise RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -74,7 +74,7 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
|
||||
def serializable_record
|
||||
returning(serializable_record = {}) do
|
||||
{}.tap do |serializable_record|
|
||||
serializable_names.each { |name| serializable_record[name] = @record.send(name) }
|
||||
add_includes do |association, records, opts|
|
||||
if records.is_a?(Enumerable)
|
||||
|
|
|
@ -184,7 +184,7 @@ module ActiveRecord
|
|||
|
||||
# Look up a session by id and unmarshal its data if found.
|
||||
def find_by_session_id(session_id)
|
||||
if record = @@connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{@@connection.quote(session_id)}")
|
||||
if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id)}")
|
||||
new(:session_id => session_id, :marshaled_data => record['data'])
|
||||
end
|
||||
end
|
||||
|
@ -310,6 +310,14 @@ module ActiveRecord
|
|||
return true
|
||||
end
|
||||
|
||||
def destroy(env)
|
||||
if sid = current_session_id(env)
|
||||
Base.silence do
|
||||
get_session_model(env, sid).destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_session_model(env, sid)
|
||||
if env[ENV_SESSION_OPTIONS_KEY][:id].nil?
|
||||
env[SESSION_RECORD_KEY] = find_session(sid)
|
||||
|
|
|
@ -80,7 +80,7 @@ module ActiveRecord
|
|||
|
||||
# Wraps an error message into a full_message format.
|
||||
#
|
||||
# The default full_message format for any locale is <tt>"{{attribute}} {{message}}"</tt>.
|
||||
# The default full_message format for any locale is <tt>"%{attribute} %{message}"</tt>.
|
||||
# One can specify locale specific default full_message format by storing it as a
|
||||
# translation for the key <tt>:"activerecord.errors.full_messages.format"</tt>.
|
||||
#
|
||||
|
@ -109,7 +109,7 @@ module ActiveRecord
|
|||
keys = [
|
||||
:"full_messages.#{@message}",
|
||||
:'full_messages.format',
|
||||
'{{attribute}} {{message}}'
|
||||
'%{attribute} %{message}'
|
||||
]
|
||||
|
||||
options.merge!(:default => keys, :message => self.message)
|
||||
|
@ -604,13 +604,13 @@ module ActiveRecord
|
|||
#
|
||||
# class Person < ActiveRecord::Base
|
||||
# validates_length_of :first_name, :maximum=>30
|
||||
# validates_length_of :last_name, :maximum=>30, :message=>"less than {{count}} if you don't mind"
|
||||
# validates_length_of :last_name, :maximum=>30, :message=>"less than %{count} if you don't mind"
|
||||
# validates_length_of :fax, :in => 7..32, :allow_nil => true
|
||||
# validates_length_of :phone, :in => 7..32, :allow_blank => true
|
||||
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
|
||||
# validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least {{count}} character"
|
||||
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with {{count}} characters... don't play me."
|
||||
# validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least {{count}} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
|
||||
# validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least %{count} character"
|
||||
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with %{count} characters... don't play me."
|
||||
# validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least %{count} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
|
||||
# end
|
||||
#
|
||||
# Configuration options:
|
||||
|
@ -621,9 +621,9 @@ module ActiveRecord
|
|||
# * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
|
||||
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
|
||||
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
|
||||
# * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is {{count}} characters)").
|
||||
# * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is {{count}} characters)").
|
||||
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be {{count}} characters)").
|
||||
# * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %{count} characters)").
|
||||
# * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %{count} characters)").
|
||||
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %{count} characters)").
|
||||
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
|
||||
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
||||
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
||||
|
@ -825,7 +825,7 @@ module ActiveRecord
|
|||
if scope = configuration[:scope]
|
||||
Array(scope).map do |scope_item|
|
||||
scope_value = record.send(scope_item)
|
||||
condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{scope_item}", scope_value)
|
||||
condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{connection.quote_column_name(scope_item)}", scope_value)
|
||||
condition_params << scope_value
|
||||
end
|
||||
end
|
||||
|
@ -885,7 +885,7 @@ module ActiveRecord
|
|||
# class Person < ActiveRecord::Base
|
||||
# validates_inclusion_of :gender, :in => %w( m f )
|
||||
# validates_inclusion_of :age, :in => 0..99
|
||||
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension {{value}} is not included in the list"
|
||||
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %{value} is not included in the list"
|
||||
# end
|
||||
#
|
||||
# Configuration options:
|
||||
|
@ -919,7 +919,7 @@ module ActiveRecord
|
|||
# class Person < ActiveRecord::Base
|
||||
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
|
||||
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
|
||||
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension {{value}} is not allowed"
|
||||
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
|
||||
# end
|
||||
#
|
||||
# Configuration options:
|
||||
|
|
|
@ -2,7 +2,7 @@ module ActiveRecord
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 3
|
||||
TINY = 8
|
||||
TINY = 9
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
|
@ -65,17 +65,16 @@ class AdapterTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_not_specifying_database_name_for_cross_database_selects
|
||||
begin
|
||||
assert_nothing_raised do
|
||||
ActiveRecord::Base.establish_connection({
|
||||
:adapter => 'mysql',
|
||||
:username => 'rails'
|
||||
})
|
||||
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['arunit'].except(:database))
|
||||
ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
|
||||
end
|
||||
|
||||
ensure
|
||||
ActiveRecord::Base.establish_connection 'arunit'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter)
|
||||
def test_encoding
|
||||
|
|
|
@ -18,7 +18,7 @@ module Remembered
|
|||
|
||||
module ClassMethods
|
||||
def remembered; @@remembered ||= []; end
|
||||
def random_element; @@remembered.random_element; end
|
||||
def sample; @@remembered.sample; end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -82,14 +82,14 @@ class EagerLoadPolyAssocsTest < ActiveRecord::TestCase
|
|||
[Circle, Square, Triangle, NonPolyOne, NonPolyTwo].map(&:create!)
|
||||
end
|
||||
1.upto(NUM_SIMPLE_OBJS) do
|
||||
PaintColor.create!(:non_poly_one_id => NonPolyOne.random_element.id)
|
||||
PaintTexture.create!(:non_poly_two_id => NonPolyTwo.random_element.id)
|
||||
PaintColor.create!(:non_poly_one_id => NonPolyOne.sample.id)
|
||||
PaintTexture.create!(:non_poly_two_id => NonPolyTwo.sample.id)
|
||||
end
|
||||
1.upto(NUM_SHAPE_EXPRESSIONS) do
|
||||
shape_type = [Circle, Square, Triangle].random_element
|
||||
paint_type = [PaintColor, PaintTexture].random_element
|
||||
ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.random_element.id,
|
||||
:paint_type => paint_type.to_s, :paint_id => paint_type.random_element.id)
|
||||
shape_type = [Circle, Square, Triangle].sample
|
||||
paint_type = [PaintColor, PaintTexture].sample
|
||||
ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.sample.id,
|
||||
:paint_type => paint_type.to_s, :paint_id => paint_type.sample.id)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
19
vendor/rails/activerecord/test/cases/associations/eager_load_nested_polymorphic_include.rb
vendored
Normal file
19
vendor/rails/activerecord/test/cases/associations/eager_load_nested_polymorphic_include.rb
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
require 'cases/helper'
|
||||
require 'models/tee'
|
||||
require 'models/tie'
|
||||
require 'models/polymorphic_design'
|
||||
require 'models/polymorphic_price'
|
||||
|
||||
class EagerLoadNestedPolymorphicIncludeTest < ActiveRecord::TestCase
|
||||
fixtures :tees, :ties, :polymorphic_designs, :polymorphic_prices
|
||||
|
||||
def test_eager_load_polymorphic_has_one_nested_under_polymorphic_belongs_to
|
||||
designs = PolymorphicDesign.scoped(:include => {:designable => :polymorphic_price})
|
||||
|
||||
associated_price_ids = designs.map{|design| design.designable.polymorphic_price.id}
|
||||
expected_price_ids = [1, 2, 3, 4]
|
||||
|
||||
assert expected_price_ids.all?{|expected_id| associated_price_ids.include?(expected_id)},
|
||||
"Expected associated prices to be #{expected_price_ids.inspect} but they were #{associated_price_ids.sort.inspect}"
|
||||
end
|
||||
end
|
|
@ -357,6 +357,13 @@ class EagerAssociationTest < ActiveRecord::TestCase
|
|||
assert_equal comments(:more_greetings), Author.find(authors(:david).id, :include => :comments_with_order_and_conditions).comments_with_order_and_conditions.first
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_through_with_conditions_join_model_with_include
|
||||
post_tags = Post.find(posts(:welcome).id).misc_tags
|
||||
eager_post_tags = Post.find(1, :include => :misc_tags).misc_tags
|
||||
assert_equal post_tags, eager_post_tags
|
||||
end
|
||||
|
||||
|
||||
def test_eager_with_has_many_through_join_model_with_include
|
||||
author_comments = Author.find(authors(:david).id, :include => :comments_with_include).comments_with_include.to_a
|
||||
assert_no_queries do
|
||||
|
|
|
@ -21,6 +21,68 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|||
Client.destroyed_client_ids.clear
|
||||
end
|
||||
|
||||
def test_create_by
|
||||
person = Person.create! :first_name => 'tenderlove'
|
||||
post = Post.find :first
|
||||
|
||||
assert_equal [], person.readers
|
||||
assert_nil person.readers.find_by_post_id(post.id)
|
||||
|
||||
reader = person.readers.create_by_post_id post.id
|
||||
|
||||
assert_equal 1, person.readers.count
|
||||
assert_equal 1, person.readers.length
|
||||
assert_equal post, person.readers.first.post
|
||||
assert_equal person, person.readers.first.person
|
||||
end
|
||||
|
||||
def test_create_by_multi
|
||||
person = Person.create! :first_name => 'tenderlove'
|
||||
post = Post.find :first
|
||||
|
||||
assert_equal [], person.readers
|
||||
|
||||
reader = person.readers.create_by_post_id_and_skimmer post.id, false
|
||||
|
||||
assert_equal 1, person.readers.count
|
||||
assert_equal 1, person.readers.length
|
||||
assert_equal post, person.readers.first.post
|
||||
assert_equal person, person.readers.first.person
|
||||
end
|
||||
|
||||
def test_find_or_create_by
|
||||
person = Person.create! :first_name => 'tenderlove'
|
||||
post = Post.find :first
|
||||
|
||||
assert_equal [], person.readers
|
||||
assert_nil person.readers.find_by_post_id(post.id)
|
||||
|
||||
reader = person.readers.find_or_create_by_post_id post.id
|
||||
|
||||
assert_equal 1, person.readers.count
|
||||
assert_equal 1, person.readers.length
|
||||
assert_equal post, person.readers.first.post
|
||||
assert_equal person, person.readers.first.person
|
||||
end
|
||||
|
||||
def test_find_or_create
|
||||
person = Person.create! :first_name => 'tenderlove'
|
||||
post = Post.find :first
|
||||
|
||||
assert_equal [], person.readers
|
||||
assert_nil person.readers.find(:first, :conditions => {
|
||||
:post_id => post.id
|
||||
})
|
||||
|
||||
reader = person.readers.find_or_create :post_id => post.id
|
||||
|
||||
assert_equal 1, person.readers.count
|
||||
assert_equal 1, person.readers.length
|
||||
assert_equal post, person.readers.first.post
|
||||
assert_equal person, person.readers.first.person
|
||||
end
|
||||
|
||||
|
||||
def force_signal37_to_load_all_clients_of_firm
|
||||
companies(:first_firm).clients_of_firm.each {|f| }
|
||||
end
|
||||
|
@ -486,7 +548,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|||
assert the_client.new_record?
|
||||
end
|
||||
|
||||
def test_find_or_create
|
||||
def test_find_or_create_updates_size
|
||||
number_of_clients = companies(:first_firm).clients.size
|
||||
the_client = companies(:first_firm).clients.find_or_create_by_name("Yet another client")
|
||||
assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
|
||||
|
@ -772,8 +834,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_destroy_all
|
||||
force_signal37_to_load_all_clients_of_firm
|
||||
assert !companies(:first_firm).clients_of_firm.empty?, "37signals has clients after load"
|
||||
companies(:first_firm).clients_of_firm.destroy_all
|
||||
clients = companies(:first_firm).clients_of_firm.to_a
|
||||
assert !clients.empty?, "37signals has clients after load"
|
||||
destroyed = companies(:first_firm).clients_of_firm.destroy_all
|
||||
assert_equal clients.sort_by(&:id), destroyed.sort_by(&:id)
|
||||
assert destroyed.all? { |client| client.frozen? }, "destroyed clients should be frozen"
|
||||
assert companies(:first_firm).clients_of_firm.empty?, "37signals has no clients after destroy all"
|
||||
assert companies(:first_firm).clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
|
||||
end
|
||||
|
|
|
@ -18,6 +18,8 @@ require 'models/person'
|
|||
require 'models/reader'
|
||||
require 'models/parrot'
|
||||
require 'models/pirate'
|
||||
require 'models/ship'
|
||||
require 'models/ship_part'
|
||||
require 'models/treasure'
|
||||
require 'models/price_estimate'
|
||||
require 'models/club'
|
||||
|
@ -29,6 +31,23 @@ class AssociationsTest < ActiveRecord::TestCase
|
|||
fixtures :accounts, :companies, :developers, :projects, :developers_projects,
|
||||
:computers, :people, :readers
|
||||
|
||||
def test_loading_the_association_target_should_keep_child_records_marked_for_destruction
|
||||
ship = Ship.create!(:name => "The good ship Dollypop")
|
||||
part = ship.parts.create!(:name => "Mast")
|
||||
part.mark_for_destruction
|
||||
ship.parts.send(:load_target)
|
||||
assert ship.parts[0].marked_for_destruction?
|
||||
end
|
||||
|
||||
def test_loading_the_association_target_should_load_most_recent_attributes_for_child_records_marked_for_destruction
|
||||
ship = Ship.create!(:name => "The good ship Dollypop")
|
||||
part = ship.parts.create!(:name => "Mast")
|
||||
part.mark_for_destruction
|
||||
ShipPart.find(part.id).update_attribute(:name, 'Deck')
|
||||
ship.parts.send(:load_target)
|
||||
assert_equal 'Deck', ship.parts[0].name
|
||||
end
|
||||
|
||||
def test_include_with_order_works
|
||||
assert_nothing_raised {Account.find(:first, :order => 'id', :include => :firm)}
|
||||
assert_nothing_raised {Account.find(:first, :order => :id, :include => :firm)}
|
||||
|
@ -75,6 +94,16 @@ class AssociationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_using_limitable_reflections_helper
|
||||
using_limitable_reflections = lambda { |reflections| ActiveRecord::Base.send :using_limitable_reflections?, reflections }
|
||||
belongs_to_reflections = [Tagging.reflect_on_association(:tag), Tagging.reflect_on_association(:super_tag)]
|
||||
has_many_reflections = [Tag.reflect_on_association(:taggings), Developer.reflect_on_association(:projects)]
|
||||
mixed_reflections = (belongs_to_reflections + has_many_reflections).uniq
|
||||
assert using_limitable_reflections.call(belongs_to_reflections), "Belong to associations are limitable"
|
||||
assert !using_limitable_reflections.call(has_many_reflections), "All has many style associations are not limitable"
|
||||
assert !using_limitable_reflections.call(mixed_reflections), "No collection associations (has many style) should pass"
|
||||
end
|
||||
|
||||
def test_storing_in_pstore
|
||||
require "tmpdir"
|
||||
store_filename = File.join(Dir.tmpdir, "ar-pstore-association-test")
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/author'
|
||||
require 'models/event_author'
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
|
@ -588,17 +587,25 @@ class BasicsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_destroy_all
|
||||
original_count = Topic.count
|
||||
topics_by_mary = Topic.count(:conditions => mary = "author_name = 'Mary'")
|
||||
conditions = "author_name = 'Mary'"
|
||||
topics_by_mary = Topic.all(:conditions => conditions, :order => 'id')
|
||||
assert ! topics_by_mary.empty?
|
||||
|
||||
Topic.destroy_all mary
|
||||
assert_equal original_count - topics_by_mary, Topic.count
|
||||
assert_difference('Topic.count', -topics_by_mary.size) do
|
||||
destroyed = Topic.destroy_all(conditions).sort_by(&:id)
|
||||
assert_equal topics_by_mary, destroyed
|
||||
assert destroyed.all? { |topic| topic.frozen? }
|
||||
end
|
||||
end
|
||||
|
||||
def test_destroy_many
|
||||
assert_equal 3, Client.count
|
||||
Client.destroy([2, 3])
|
||||
assert_equal 1, Client.count
|
||||
clients = Client.find([2, 3], :order => 'id')
|
||||
|
||||
assert_difference('Client.count', -2) do
|
||||
destroyed = Client.destroy([2, 3]).sort_by(&:id)
|
||||
assert_equal clients, destroyed
|
||||
assert destroyed.all? { |client| client.frozen? }
|
||||
end
|
||||
end
|
||||
|
||||
def test_delete_many
|
||||
|
@ -612,55 +619,6 @@ class BasicsTest < ActiveRecord::TestCase
|
|||
assert Topic.find(2).approved?
|
||||
end
|
||||
|
||||
def test_increment_counter
|
||||
Topic.increment_counter("replies_count", 1)
|
||||
assert_equal 2, Topic.find(1).replies_count
|
||||
|
||||
Topic.increment_counter("replies_count", 1)
|
||||
assert_equal 3, Topic.find(1).replies_count
|
||||
end
|
||||
|
||||
def test_decrement_counter
|
||||
Topic.decrement_counter("replies_count", 2)
|
||||
assert_equal -1, Topic.find(2).replies_count
|
||||
|
||||
Topic.decrement_counter("replies_count", 2)
|
||||
assert_equal -2, Topic.find(2).replies_count
|
||||
end
|
||||
|
||||
def test_reset_counters
|
||||
assert_equal 1, Topic.find(1).replies_count
|
||||
|
||||
Topic.increment_counter("replies_count", 1)
|
||||
assert_equal 2, Topic.find(1).replies_count
|
||||
|
||||
Topic.reset_counters(1, :replies)
|
||||
assert_equal 1, Topic.find(1).replies_count
|
||||
end
|
||||
|
||||
def test_update_counter
|
||||
category = categories(:general)
|
||||
assert_nil category.categorizations_count
|
||||
assert_equal 2, category.categorizations.count
|
||||
|
||||
Category.update_counters(category.id, "categorizations_count" => category.categorizations.count)
|
||||
category.reload
|
||||
assert_not_nil category.categorizations_count
|
||||
assert_equal 2, category.categorizations_count
|
||||
|
||||
Category.update_counters(category.id, "categorizations_count" => category.categorizations.count)
|
||||
category.reload
|
||||
assert_not_nil category.categorizations_count
|
||||
assert_equal 4, category.categorizations_count
|
||||
|
||||
category_2 = categories(:technology)
|
||||
count_1, count_2 = (category.categorizations_count || 0), (category_2.categorizations_count || 0)
|
||||
Category.update_counters([category.id, category_2.id], "categorizations_count" => 2)
|
||||
category.reload; category_2.reload
|
||||
assert_equal count_1 + 2, category.categorizations_count
|
||||
assert_equal count_2 + 2, category_2.categorizations_count
|
||||
end
|
||||
|
||||
def test_update_all
|
||||
assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
|
||||
assert_equal "bulk updated!", Topic.find(1).content
|
||||
|
@ -749,6 +707,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_class_name
|
||||
ActiveSupport::Deprecation.silence do
|
||||
assert_equal "Firm", ActiveRecord::Base.class_name("firms")
|
||||
assert_equal "Category", ActiveRecord::Base.class_name("categories")
|
||||
assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder")
|
||||
|
@ -766,6 +725,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|||
ActiveRecord::Base.table_name_suffix = ""
|
||||
assert_equal "Firm", ActiveRecord::Base.class_name( "firms" )
|
||||
end
|
||||
end
|
||||
|
||||
def test_null_fields
|
||||
assert_nil Topic.find(1).parent_id
|
||||
|
@ -2090,7 +2050,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_inspect_instance
|
||||
topic = topics(:first)
|
||||
assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil>), topic.inspect
|
||||
assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil>), topic.inspect
|
||||
end
|
||||
|
||||
def test_inspect_new_instance
|
||||
|
|
|
@ -48,6 +48,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
|
|||
def test_multi_results
|
||||
rows = ActiveRecord::Base.connection.select_rows('CALL ten();')
|
||||
assert_equal 10, rows[0][0].to_i, "ten() did not return 10 as expected: #{rows.inspect}"
|
||||
assert @connection.active?, "Bad connection use by 'MysqlAdapter.select_rows'"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
84
vendor/rails/activerecord/test/cases/counter_cache_test.rb
vendored
Executable file
84
vendor/rails/activerecord/test/cases/counter_cache_test.rb
vendored
Executable file
|
@ -0,0 +1,84 @@
|
|||
require 'cases/helper'
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/category'
|
||||
require 'models/categorization'
|
||||
|
||||
class CounterCacheTest < ActiveRecord::TestCase
|
||||
fixtures :topics, :categories, :categorizations
|
||||
|
||||
class SpecialTopic < ::Topic
|
||||
has_many :special_replies, :foreign_key => 'parent_id'
|
||||
end
|
||||
|
||||
class SpecialReply < ::Reply
|
||||
belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count'
|
||||
end
|
||||
|
||||
test "increment counter" do
|
||||
topic = Topic.find(1)
|
||||
assert_difference 'topic.reload.replies_count' do
|
||||
Topic.increment_counter(:replies_count, topic.id)
|
||||
end
|
||||
end
|
||||
|
||||
test "decrement counter" do
|
||||
topic = Topic.find(1)
|
||||
assert_difference 'topic.reload.replies_count', -1 do
|
||||
Topic.decrement_counter(:replies_count, topic.id)
|
||||
end
|
||||
end
|
||||
|
||||
test "reset counters" do
|
||||
topic = Topic.find(1)
|
||||
# throw the count off by 1
|
||||
Topic.increment_counter(:replies_count, topic.id)
|
||||
|
||||
# check that it gets reset
|
||||
assert_difference 'topic.reload.replies_count', -1 do
|
||||
Topic.reset_counters(topic.id, :replies)
|
||||
end
|
||||
end
|
||||
|
||||
test "reset counters with string argument" do
|
||||
topic = Topic.find(1)
|
||||
Topic.increment_counter('replies_count', topic.id)
|
||||
|
||||
assert_difference 'topic.reload.replies_count', -1 do
|
||||
Topic.reset_counters(topic.id, 'replies')
|
||||
end
|
||||
end
|
||||
|
||||
test "reset counters with modularized and camelized classnames" do
|
||||
special = SpecialTopic.create!(:title => 'Special')
|
||||
SpecialTopic.increment_counter(:replies_count, special.id)
|
||||
|
||||
assert_difference 'special.reload.replies_count', -1 do
|
||||
SpecialTopic.reset_counters(special.id, :special_replies)
|
||||
end
|
||||
end
|
||||
|
||||
test "update counter with initial null value" do
|
||||
category = categories(:general)
|
||||
assert_equal 2, category.categorizations.count
|
||||
assert_nil category.categorizations_count
|
||||
|
||||
Category.update_counters(category.id, :categorizations_count => category.categorizations.count)
|
||||
assert_equal 2, category.reload.categorizations_count
|
||||
end
|
||||
|
||||
test "update counter for decrement" do
|
||||
topic = Topic.find(1)
|
||||
assert_difference 'topic.reload.replies_count', -3 do
|
||||
Topic.update_counters(topic.id, :replies_count => -3)
|
||||
end
|
||||
end
|
||||
|
||||
test "update counters of multiple records" do
|
||||
t1, t2 = topics(:first, :second)
|
||||
|
||||
assert_difference ['t1.reload.replies_count', 't2.reload.replies_count'], 2 do
|
||||
Topic.update_counters([t1.id, t2.id], :replies_count => 2)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -53,7 +53,8 @@ class OptimisticLockingTest < ActiveRecord::TestCase
|
|||
assert_raises(ActiveRecord::StaleObjectError) { p2.destroy }
|
||||
|
||||
assert p1.destroy
|
||||
assert_equal true, p1.frozen?
|
||||
assert p1.frozen?
|
||||
assert p1.destroyed?
|
||||
assert_raises(ActiveRecord::RecordNotFound) { Person.find(1) }
|
||||
end
|
||||
|
||||
|
|
|
@ -739,6 +739,10 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|||
ActiveRecord::Base.connection.drop_table(:hats)
|
||||
end
|
||||
|
||||
def test_remove_column_no_second_parameter_raises_exception
|
||||
assert_raise(ArgumentError) { Person.connection.remove_column("funny") }
|
||||
end
|
||||
|
||||
def test_change_type_of_not_null_column
|
||||
assert_nothing_raised do
|
||||
Topic.connection.change_column "topics", "written_on", :datetime, :null => false
|
||||
|
|
|
@ -9,6 +9,11 @@ require 'models/developer'
|
|||
class NamedScopeTest < ActiveRecord::TestCase
|
||||
fixtures :posts, :authors, :topics, :comments, :author_addresses
|
||||
|
||||
def test_named_scope_with_STI
|
||||
assert_equal 5,Post.with_type_self.count
|
||||
assert_equal 1,SpecialPost.with_type_self.count
|
||||
end
|
||||
|
||||
def test_implements_enumerable
|
||||
assert !Topic.find(:all).empty?
|
||||
|
||||
|
@ -265,7 +270,7 @@ class NamedScopeTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_rand_should_select_a_random_object_from_proxy
|
||||
assert Topic.approved.random_element.is_a?(Topic)
|
||||
assert Topic.approved.sample.is_a?(Topic)
|
||||
end
|
||||
|
||||
def test_should_use_where_in_query_for_named_scope
|
||||
|
|
|
@ -175,12 +175,6 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
|||
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
||||
end
|
||||
|
||||
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
||||
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Ship with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
|
||||
@pirate.ship_attributes = { :id => 1234567890 }
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
|
||||
@pirate.reload.ship_attributes = { 'id' => @ship.id, 'name' => 'Davy Jones Gold Dagger' }
|
||||
|
||||
|
@ -330,10 +324,13 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
|||
assert_equal 'Arr', @ship.pirate.catchphrase
|
||||
end
|
||||
|
||||
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
||||
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Pirate with ID=1234567890 for Ship with ID=#{@ship.id}" do
|
||||
@ship.pirate_attributes = { :id => 1234567890 }
|
||||
end
|
||||
def test_should_associate_with_record_if_parent_record_is_not_saved
|
||||
@ship.destroy
|
||||
@pirate = Pirate.create(:catchphrase => 'Arr')
|
||||
@ship = Ship.new(:name => 'Nights Dirty Lightning', :pirate_attributes => { :id => @pirate.id, :catchphrase => @pirate.catchphrase})
|
||||
|
||||
assert_equal @ship.name, 'Nights Dirty Lightning'
|
||||
assert_equal @pirate, @ship.pirate
|
||||
end
|
||||
|
||||
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
|
||||
|
@ -437,6 +434,11 @@ module NestedAttributesOnACollectionAssociationTests
|
|||
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name]
|
||||
end
|
||||
|
||||
def test_should_assign_existing_children_if_parent_is_new
|
||||
@pirate = Pirate.new({:catchphrase => "Don' botharr talkin' like one, savvy?"}.merge(@alternate_params))
|
||||
assert_equal ['Grace OMalley', 'Privateers Greed'], [@pirate.send(@association_name)[0].name, @pirate.send(@association_name)[1].name]
|
||||
end
|
||||
|
||||
def test_should_take_an_array_and_assign_the_attributes_to_the_associated_models
|
||||
@pirate.send(association_setter, @alternate_params[association_getter].values)
|
||||
@pirate.save
|
||||
|
@ -465,6 +467,33 @@ module NestedAttributesOnACollectionAssociationTests
|
|||
assert_equal 'Grace OMalley', @child_1.reload.name
|
||||
end
|
||||
|
||||
def test_should_not_overwrite_unsaved_updates_when_loading_association
|
||||
@pirate.reload
|
||||
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
|
||||
assert_equal 'Grace OMalley', @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.name
|
||||
end
|
||||
|
||||
def test_should_preserve_order_when_not_overwriting_unsaved_updates
|
||||
@pirate.reload
|
||||
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
|
||||
assert_equal @child_1.id, @pirate.send(@association_name).send(:load_target).first.id
|
||||
end
|
||||
|
||||
def test_should_refresh_saved_records_when_not_overwriting_unsaved_updates
|
||||
@pirate.reload
|
||||
record = @pirate.class.reflect_on_association(@association_name).klass.new(:name => 'Grace OMalley')
|
||||
@pirate.send(@association_name) << record
|
||||
record.save!
|
||||
@pirate.send(@association_name).last.update_attributes!(:name => 'Polly')
|
||||
assert_equal 'Polly', @pirate.send(@association_name).send(:load_target).last.name
|
||||
end
|
||||
|
||||
def test_should_not_remove_scheduled_destroys_when_loading_association
|
||||
@pirate.reload
|
||||
@pirate.send(association_setter, [{ :id => @child_1.id, :_destroy => '1' }])
|
||||
assert @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.marked_for_destruction?
|
||||
end
|
||||
|
||||
def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models
|
||||
@child_1.stubs(:id).returns('ABC1X')
|
||||
@child_2.stubs(:id).returns('ABC2X')
|
||||
|
@ -479,8 +508,8 @@ module NestedAttributesOnACollectionAssociationTests
|
|||
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name]
|
||||
end
|
||||
|
||||
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
||||
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find #{@child_1.class.name} with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
|
||||
def test_should_not_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
||||
assert_nothing_raised ActiveRecord::RecordNotFound do
|
||||
@pirate.attributes = { association_getter => [{ :id => 1234567890 }] }
|
||||
end
|
||||
end
|
||||
|
@ -782,6 +811,12 @@ class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveR
|
|||
@trinket = @part.trinkets.create!(:name => "Necklace")
|
||||
end
|
||||
|
||||
test "if association is not loaded and association record is saved and then in memory record attributes should be saved" do
|
||||
@ship.parts_attributes=[{:id => @part.id,:name =>'Deck'}]
|
||||
assert_equal 1, @ship.parts.proxy_target.size
|
||||
assert_equal 'Deck', @ship.parts[0].name
|
||||
end
|
||||
|
||||
test "when grandchild changed in memory, saving parent should save grandchild" do
|
||||
@trinket.name = "changed"
|
||||
@ship.save
|
||||
|
|
|
@ -24,25 +24,25 @@ class ReflectionTest < ActiveRecord::TestCase
|
|||
|
||||
def test_read_attribute_names
|
||||
assert_equal(
|
||||
%w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id parent_title type ).sort,
|
||||
%w( id title author_name author_email_address bonus_time written_on last_read content group approved replies_count parent_id parent_title type ).sort,
|
||||
@first.attribute_names
|
||||
)
|
||||
end
|
||||
|
||||
def test_columns
|
||||
assert_equal 13, Topic.columns.length
|
||||
assert_equal 14, Topic.columns.length
|
||||
end
|
||||
|
||||
def test_columns_are_returned_in_the_order_they_were_declared
|
||||
column_names = Topic.columns.map { |column| column.name }
|
||||
assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type), column_names
|
||||
assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type group), column_names
|
||||
end
|
||||
|
||||
def test_content_columns
|
||||
content_columns = Topic.content_columns
|
||||
content_column_names = content_columns.map {|column| column.name}
|
||||
assert_equal 9, content_columns.length
|
||||
assert_equal %w(title author_name author_email_address written_on bonus_time last_read content approved parent_title).sort, content_column_names.sort
|
||||
assert_equal 10, content_columns.length
|
||||
assert_equal %w(title author_name author_email_address written_on bonus_time last_read content group approved parent_title).sort, content_column_names.sort
|
||||
end
|
||||
|
||||
def test_column_string_type_and_limit
|
||||
|
|
16
vendor/rails/activerecord/test/cases/sp_test_mysql.rb
vendored
Normal file
16
vendor/rails/activerecord/test/cases/sp_test_mysql.rb
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/minimalistic'
|
||||
|
||||
class StoredProcedureTest < ActiveRecord::TestCase
|
||||
fixtures :topics
|
||||
|
||||
# Test that MySQL allows multiple results for stored procedures
|
||||
if Mysql.const_defined?(:CLIENT_MULTI_RESULTS)
|
||||
def test_multi_results_from_find_by_sql
|
||||
topics = Topic.find_by_sql 'CALL topics();'
|
||||
assert_equal 1, topics.size
|
||||
assert ActiveRecord::Base.connection.active?, "Bad connection use by 'MysqlAdapter.select'"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,10 +3,12 @@ require 'models/topic'
|
|||
require 'models/reply'
|
||||
require 'models/developer'
|
||||
require 'models/book'
|
||||
require 'models/author'
|
||||
require 'models/post'
|
||||
|
||||
class TransactionTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
fixtures :topics, :developers
|
||||
fixtures :topics, :developers, :authors, :posts
|
||||
|
||||
def setup
|
||||
@first, @second = Topic.find(1, 2).sort_by { |t| t.id }
|
||||
|
@ -34,6 +36,25 @@ class TransactionTest < ActiveRecord::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_update_attributes_should_rollback_on_failure
|
||||
author = Author.find(1)
|
||||
posts_count = author.posts.size
|
||||
assert posts_count > 0
|
||||
status = author.update_attributes(:name => nil, :post_ids => [])
|
||||
assert !status
|
||||
assert_equal posts_count, author.posts(true).size
|
||||
end
|
||||
|
||||
def test_update_attributes_should_rollback_on_failure!
|
||||
author = Author.find(1)
|
||||
posts_count = author.posts.size
|
||||
assert posts_count > 0
|
||||
assert_raise(ActiveRecord::RecordInvalid) do
|
||||
author.update_attributes!(:name => nil, :post_ids => [])
|
||||
end
|
||||
assert_equal posts_count, author.posts(true).size
|
||||
end
|
||||
|
||||
def test_successful_with_return
|
||||
class << Topic.connection
|
||||
alias :real_commit_db_transaction :commit_db_transaction
|
||||
|
|
|
@ -486,20 +486,20 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
test ":default is only given to message if a symbol is supplied" do
|
||||
store_translations(:errors => { :messages => { :"foo bar" => "You fooed: {{value}}." } })
|
||||
store_translations(:errors => { :messages => { :"foo bar" => "You fooed: %{value}." } })
|
||||
@reply.errors.add(:title, :inexistent, :default => "foo bar")
|
||||
assert_equal "foo bar", @reply.errors[:title]
|
||||
end
|
||||
|
||||
test "#generate_message passes the model attribute value for interpolation" do
|
||||
store_translations(:errors => { :messages => { :foo => "You fooed: {{value}}." } })
|
||||
store_translations(:errors => { :messages => { :foo => "You fooed: %{value}." } })
|
||||
@reply.title = "da title"
|
||||
assert_error_message 'You fooed: da title.', :title, :foo
|
||||
end
|
||||
|
||||
test "#generate_message passes the human_name of the model for interpolation" do
|
||||
store_translations(
|
||||
:errors => { :messages => { :foo => "You fooed: {{model}}." } },
|
||||
:errors => { :messages => { :foo => "You fooed: %{model}." } },
|
||||
:models => { :topic => 'da topic' }
|
||||
)
|
||||
assert_error_message 'You fooed: da topic.', :title, :foo
|
||||
|
@ -507,7 +507,7 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|||
|
||||
test "#generate_message passes the human_name of the attribute for interpolation" do
|
||||
store_translations(
|
||||
:errors => { :messages => { :foo => "You fooed: {{attribute}}." } },
|
||||
:errors => { :messages => { :foo => "You fooed: %{attribute}." } },
|
||||
:attributes => { :topic => { :title => 'da topic title' } }
|
||||
)
|
||||
assert_error_message 'You fooed: da topic title.', :title, :foo
|
||||
|
@ -607,17 +607,17 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
test "#full_message with a format present" do
|
||||
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :format => '{{attribute}}: {{message}}' } })
|
||||
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :format => '%{attribute}: %{message}' } })
|
||||
assert_full_message 'Title: is kaputt', :title, :kaputt
|
||||
end
|
||||
|
||||
test "#full_message with a type specific format present" do
|
||||
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :kaputt => '{{attribute}} {{message}}!' } })
|
||||
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :kaputt => '%{attribute} %{message}!' } })
|
||||
assert_full_message 'Title is kaputt!', :title, :kaputt
|
||||
end
|
||||
|
||||
test "#full_message with class-level specified custom message" do
|
||||
store_translations(:errors => { :messages => { :broken => 'is kaputt' }, :full_messages => { :broken => '{{attribute}} {{message}}?!' } })
|
||||
store_translations(:errors => { :messages => { :broken => 'is kaputt' }, :full_messages => { :broken => '%{attribute} %{message}?!' } })
|
||||
assert_full_message 'Title is kaputt?!', :title, :kaputt, :message => :broken
|
||||
end
|
||||
|
||||
|
@ -625,7 +625,7 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|||
store_translations(:my_errors => { :messages => { :kaputt => 'is kaputt' } })
|
||||
assert_full_message 'Title is kaputt', :title, :kaputt, :scope => [:activerecord, :my_errors]
|
||||
|
||||
store_translations(:my_errors => { :full_messages => { :kaputt => '{{attribute}} {{message}}!' } })
|
||||
store_translations(:my_errors => { :full_messages => { :kaputt => '%{attribute} %{message}!' } })
|
||||
assert_full_message 'Title is kaputt!', :title, :kaputt, :scope => [:activerecord, :my_errors]
|
||||
end
|
||||
|
||||
|
@ -763,7 +763,7 @@ class ActiveRecordDefaultErrorMessagesI18nTests < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
test "custom message string interpolation" do
|
||||
assert_equal 'custom message title', error_message(:invalid, :default => 'custom message {{value}}', :value => 'title')
|
||||
assert_equal 'custom message title', error_message(:invalid, :default => 'custom message %{value}', :value => 'title')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -897,14 +897,14 @@ class ActiveRecordValidationsI18nFullMessagesFullStackTests < ActiveSupport::Tes
|
|||
|
||||
test "full_message format stored per custom error message key" do
|
||||
assert_full_message("Name is broken!") do
|
||||
store_translations :errors => { :messages => { :broken => 'is broken' }, :full_messages => { :broken => '{{attribute}} {{message}}!' } }
|
||||
store_translations :errors => { :messages => { :broken => 'is broken' }, :full_messages => { :broken => '%{attribute} %{message}!' } }
|
||||
I18nPerson.validates_presence_of :name, :message => :broken
|
||||
end
|
||||
end
|
||||
|
||||
test "full_message format stored per error type" do
|
||||
assert_full_message("Name can't be blank!") do
|
||||
store_translations :errors => { :full_messages => { :blank => '{{attribute}} {{message}}!' } }
|
||||
store_translations :errors => { :full_messages => { :blank => '%{attribute} %{message}!' } }
|
||||
I18nPerson.validates_presence_of :name
|
||||
end
|
||||
end
|
||||
|
@ -912,7 +912,7 @@ class ActiveRecordValidationsI18nFullMessagesFullStackTests < ActiveSupport::Tes
|
|||
|
||||
test "full_message format stored as default" do
|
||||
assert_full_message("Name: can't be blank") do
|
||||
store_translations :errors => { :full_messages => { :format => '{{attribute}}: {{message}}' } }
|
||||
store_translations :errors => { :full_messages => { :format => '%{attribute}: %{message}' } }
|
||||
I18nPerson.validates_presence_of :name
|
||||
end
|
||||
end
|
||||
|
|
|
@ -434,6 +434,18 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_validate_uniqueness_with_reserved_word_as_scope
|
||||
repair_validations(Reply) do
|
||||
Topic.validates_uniqueness_of(:content, :scope => "group")
|
||||
|
||||
t1 = Topic.create "title" => "t1", "content" => "hello world2"
|
||||
assert t1.valid?
|
||||
|
||||
t2 = Topic.create "title" => "t2", "content" => "hello world2"
|
||||
assert !t2.valid?
|
||||
end
|
||||
end
|
||||
|
||||
def test_validate_uniqueness_scoped_to_defining_class
|
||||
t = Topic.create("title" => "What, me worry?")
|
||||
|
||||
|
@ -678,7 +690,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validate_format_with_formatted_message
|
||||
Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be {{value}}")
|
||||
Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %{value}")
|
||||
t = Topic.create(:title => 'Invalid title')
|
||||
assert_equal "can't be Invalid title", t.errors.on(:title)
|
||||
end
|
||||
|
@ -741,7 +753,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_inclusion_of_with_formatted_message
|
||||
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option {{value}} is not in the list" )
|
||||
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %{value} is not in the list" )
|
||||
|
||||
assert Topic.create("title" => "a", "content" => "abc").valid?
|
||||
|
||||
|
@ -768,7 +780,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_exclusion_of_with_formatted_message
|
||||
Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option {{value}} is restricted" )
|
||||
Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %{value} is restricted" )
|
||||
|
||||
assert Topic.create("title" => "something", "content" => "abc")
|
||||
|
||||
|
@ -868,7 +880,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_optionally_validates_length_of_using_within_on_create
|
||||
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: {{count}}"
|
||||
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %{count}"
|
||||
|
||||
t = Topic.create("title" => "thisisnotvalid", "content" => "whatever")
|
||||
assert !t.save
|
||||
|
@ -889,7 +901,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_optionally_validates_length_of_using_within_on_update
|
||||
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: {{count}}"
|
||||
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %{count}"
|
||||
|
||||
t = Topic.create("title" => "vali", "content" => "whatever")
|
||||
assert !t.save
|
||||
|
@ -953,7 +965,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
def test_validates_length_with_globally_modified_error_message
|
||||
defaults = ActiveSupport::Deprecation.silence { ActiveRecord::Errors.default_error_messages }
|
||||
original_message = defaults[:too_short]
|
||||
defaults[:too_short] = 'tu est trops petit hombre {{count}}'
|
||||
defaults[:too_short] = 'tu est trops petit hombre %{count}'
|
||||
|
||||
Topic.validates_length_of :title, :minimum => 10
|
||||
t = Topic.create(:title => 'too short')
|
||||
|
@ -1004,7 +1016,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_length_of_custom_errors_for_minimum_with_message
|
||||
Topic.validates_length_of( :title, :minimum=>5, :message=>"boo {{count}}" )
|
||||
Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %{count}" )
|
||||
t = Topic.create("title" => "uhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1012,7 +1024,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_length_of_custom_errors_for_minimum_with_too_short
|
||||
Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo {{count}}" )
|
||||
Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %{count}" )
|
||||
t = Topic.create("title" => "uhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1020,7 +1032,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_length_of_custom_errors_for_maximum_with_message
|
||||
Topic.validates_length_of( :title, :maximum=>5, :message=>"boo {{count}}" )
|
||||
Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %{count}" )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1028,7 +1040,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_length_of_custom_errors_for_in
|
||||
Topic.validates_length_of(:title, :in => 10..20, :message => "hoo {{count}}")
|
||||
Topic.validates_length_of(:title, :in => 10..20, :message => "hoo %{count}")
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1041,7 +1053,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_length_of_custom_errors_for_maximum_with_too_long
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}" )
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}" )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1049,7 +1061,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_length_of_custom_errors_for_is_with_message
|
||||
Topic.validates_length_of( :title, :is=>5, :message=>"boo {{count}}" )
|
||||
Topic.validates_length_of( :title, :is=>5, :message=>"boo %{count}" )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1057,7 +1069,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_length_of_custom_errors_for_is_with_wrong_length
|
||||
Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo {{count}}" )
|
||||
Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %{count}" )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1123,7 +1135,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_optionally_validates_length_of_using_within_on_create_utf8
|
||||
with_kcode('UTF8') do
|
||||
Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: {{count}}"
|
||||
Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: %{count}"
|
||||
|
||||
t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
|
||||
assert !t.save
|
||||
|
@ -1146,7 +1158,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_optionally_validates_length_of_using_within_on_update_utf8
|
||||
with_kcode('UTF8') do
|
||||
Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: {{count}}"
|
||||
Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: %{count}"
|
||||
|
||||
t = Topic.create("title" => "一二三4", "content" => "whatever")
|
||||
assert !t.save
|
||||
|
@ -1181,7 +1193,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_length_of_with_block
|
||||
Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least {{count}} words.",
|
||||
Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %{count} words.",
|
||||
:tokenizer => lambda {|str| str.scan(/\w+/) }
|
||||
t = Topic.create!(:content => "this content should be long enough")
|
||||
assert t.valid?
|
||||
|
@ -1356,7 +1368,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_if_validation_using_method_true
|
||||
# When the method returns true
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true )
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1365,7 +1377,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_unless_validation_using_method_true
|
||||
# When the method returns true
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true )
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert t.valid?
|
||||
assert !t.errors.on(:title)
|
||||
|
@ -1373,7 +1385,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_if_validation_using_method_false
|
||||
# When the method returns false
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true_but_its_not )
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true_but_its_not )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert t.valid?
|
||||
assert !t.errors.on(:title)
|
||||
|
@ -1381,7 +1393,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_unless_validation_using_method_false
|
||||
# When the method returns false
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true_but_its_not )
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true_but_its_not )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1390,7 +1402,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_if_validation_using_string_true
|
||||
# When the evaluated string returns true
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "a = 1; a == 1" )
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "a = 1; a == 1" )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1399,7 +1411,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_unless_validation_using_string_true
|
||||
# When the evaluated string returns true
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "a = 1; a == 1" )
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "a = 1; a == 1" )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert t.valid?
|
||||
assert !t.errors.on(:title)
|
||||
|
@ -1407,7 +1419,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_if_validation_using_string_false
|
||||
# When the evaluated string returns false
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "false")
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "false")
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert t.valid?
|
||||
assert !t.errors.on(:title)
|
||||
|
@ -1415,7 +1427,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_unless_validation_using_string_false
|
||||
# When the evaluated string returns false
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "false")
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "false")
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
assert t.errors.on(:title)
|
||||
|
@ -1424,7 +1436,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_if_validation_using_block_true
|
||||
# When the block returns true
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
|
||||
:if => Proc.new { |r| r.content.size > 4 } )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
|
@ -1434,7 +1446,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_unless_validation_using_block_true
|
||||
# When the block returns true
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
|
||||
:unless => Proc.new { |r| r.content.size > 4 } )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert t.valid?
|
||||
|
@ -1443,7 +1455,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_if_validation_using_block_false
|
||||
# When the block returns false
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
|
||||
:if => Proc.new { |r| r.title != "uhohuhoh"} )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert t.valid?
|
||||
|
@ -1452,7 +1464,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_unless_validation_using_block_false
|
||||
# When the block returns false
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
|
||||
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
|
||||
:unless => Proc.new { |r| r.title != "uhohuhoh"} )
|
||||
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
||||
assert !t.valid?
|
||||
|
@ -1634,13 +1646,13 @@ class ValidatesNumericalityTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_numericality_with_numeric_message
|
||||
Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than {{count}}"
|
||||
Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than %{count}"
|
||||
topic = Topic.new("title" => "numeric test", "approved" => 10)
|
||||
|
||||
assert !topic.valid?
|
||||
assert_equal "smaller than 4", topic.errors.on(:approved)
|
||||
|
||||
Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than {{count}}"
|
||||
Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than %{count}"
|
||||
topic = Topic.new("title" => "numeric test", "approved" => 1)
|
||||
|
||||
assert !topic.valid?
|
||||
|
|
19
vendor/rails/activerecord/test/fixtures/polymorphic_designs.yml
vendored
Normal file
19
vendor/rails/activerecord/test/fixtures/polymorphic_designs.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
awesome_tee_design:
|
||||
id: 1
|
||||
designable_id: 1
|
||||
designable_type: Tee
|
||||
|
||||
sucky_tee_design:
|
||||
id: 2
|
||||
designable_id: 2
|
||||
designable_type: Tee
|
||||
|
||||
awesome_hat_design:
|
||||
id: 3
|
||||
designable_id: 1
|
||||
designable_type: Tie
|
||||
|
||||
sucky_hat_design:
|
||||
id: 4
|
||||
designable_id: 2
|
||||
designable_type: Tie
|
19
vendor/rails/activerecord/test/fixtures/polymorphic_prices.yml
vendored
Normal file
19
vendor/rails/activerecord/test/fixtures/polymorphic_prices.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
awesome_tee_price:
|
||||
id: 1
|
||||
sellable_id: 1
|
||||
sellable_type: Tee
|
||||
|
||||
sucky_tee_price:
|
||||
id: 2
|
||||
sellable_id: 2
|
||||
sellable_type: Tee
|
||||
|
||||
awesome_hat_price:
|
||||
id: 3
|
||||
sellable_id: 1
|
||||
sellable_type: Tie
|
||||
|
||||
sucky_hat_price:
|
||||
id: 4
|
||||
sellable_id: 2
|
||||
sellable_type: Tie
|
4
vendor/rails/activerecord/test/fixtures/tees.yml
vendored
Normal file
4
vendor/rails/activerecord/test/fixtures/tees.yml
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
awesome_tee:
|
||||
id: 1
|
||||
sucky_tee:
|
||||
id: 2
|
4
vendor/rails/activerecord/test/fixtures/ties.yml
vendored
Normal file
4
vendor/rails/activerecord/test/fixtures/ties.yml
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
awesome_tie:
|
||||
id: 1
|
||||
sucky_tie:
|
||||
id: 2
|
|
@ -106,6 +106,8 @@ class Author < ActiveRecord::Base
|
|||
"#{id}-#{name}"
|
||||
end
|
||||
|
||||
validates_presence_of :name
|
||||
|
||||
private
|
||||
def log_before_adding(object)
|
||||
@post_log << "before_adding#{object.id || '<new>'}"
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
require 'models/author'
|
||||
require 'models/event'
|
||||
|
||||
class EventAuthor < ActiveRecord::Base
|
||||
belongs_to :author
|
||||
belongs_to :event
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Pirate < ActiveRecord::Base
|
||||
belongs_to :parrot, :validate => true
|
||||
belongs_to :non_validated_parrot, :class_name => 'Parrot'
|
||||
has_and_belongs_to_many :parrots, :validate => true
|
||||
has_and_belongs_to_many :parrots, :validate => true, :order => 'parrots.id ASC'
|
||||
has_and_belongs_to_many :non_validated_parrots, :class_name => 'Parrot'
|
||||
has_and_belongs_to_many :parrots_with_method_callbacks, :class_name => "Parrot",
|
||||
:before_add => :log_before_add,
|
||||
|
@ -21,7 +21,7 @@ class Pirate < ActiveRecord::Base
|
|||
has_one :ship
|
||||
has_one :update_only_ship, :class_name => 'Ship'
|
||||
has_one :non_validated_ship, :class_name => 'Ship'
|
||||
has_many :birds
|
||||
has_many :birds, :order => 'birds.id ASC'
|
||||
has_many :birds_with_method_callbacks, :class_name => "Bird",
|
||||
:before_add => :log_before_add,
|
||||
:after_add => :log_after_add,
|
||||
|
|
3
vendor/rails/activerecord/test/models/polymorphic_design.rb
vendored
Normal file
3
vendor/rails/activerecord/test/models/polymorphic_design.rb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
class PolymorphicDesign < ActiveRecord::Base
|
||||
belongs_to :designable, :polymorphic => true
|
||||
end
|
3
vendor/rails/activerecord/test/models/polymorphic_price.rb
vendored
Normal file
3
vendor/rails/activerecord/test/models/polymorphic_price.rb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
class PolymorphicPrice < ActiveRecord::Base
|
||||
belongs_to :sellable, :polymorphic => true
|
||||
end
|
|
@ -1,4 +1,5 @@
|
|||
class Post < ActiveRecord::Base
|
||||
named_scope :with_type_self, lambda{{:conditions => ["type=?", self.name]}}
|
||||
named_scope :containing_the_letter_a, :conditions => "body LIKE '%a%'"
|
||||
named_scope :ranked_by_comments, :order => "comments_count DESC"
|
||||
named_scope :limit, lambda {|limit| {:limit => limit} }
|
||||
|
@ -52,6 +53,7 @@ class Post < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
has_many :misc_tags, :through => :taggings, :source => :tag, :conditions => "tags.name = 'Misc'"
|
||||
has_many :funky_tags, :through => :taggings, :source => :tag
|
||||
has_many :super_tags, :through => :taggings
|
||||
has_one :tagging, :as => :taggable
|
||||
|
|
4
vendor/rails/activerecord/test/models/tee.rb
vendored
Normal file
4
vendor/rails/activerecord/test/models/tee.rb
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
class Tee < ActiveRecord::Base
|
||||
has_one :polymorphic_design, :as => :designable
|
||||
has_one :polymorphic_price, :as => :sellable
|
||||
end
|
4
vendor/rails/activerecord/test/models/tie.rb
vendored
Normal file
4
vendor/rails/activerecord/test/models/tie.rb
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
class Tie < ActiveRecord::Base
|
||||
has_one :polymorphic_design, :as => :designable
|
||||
has_one :polymorphic_price, :as => :sellable
|
||||
end
|
|
@ -19,6 +19,13 @@ CREATE PROCEDURE ten() SQL SECURITY INVOKER
|
|||
BEGIN
|
||||
select 10;
|
||||
END
|
||||
SQL
|
||||
|
||||
ActiveRecord::Base.connection.execute <<-SQL
|
||||
CREATE PROCEDURE topics() SQL SECURITY INVOKER
|
||||
BEGIN
|
||||
select * from topics limit 1;
|
||||
END
|
||||
SQL
|
||||
|
||||
end
|
||||
|
|
16
vendor/rails/activerecord/test/schema/schema.rb
vendored
16
vendor/rails/activerecord/test/schema/schema.rb
vendored
|
@ -367,6 +367,16 @@ ActiveRecord::Schema.define do
|
|||
t.column :updated_on, :datetime
|
||||
end
|
||||
|
||||
create_table :polymorphic_designs, :force => true do |t|
|
||||
t.integer :designable_id
|
||||
t.string :designable_type
|
||||
end
|
||||
|
||||
create_table :polymorphic_prices, :force => true do |t|
|
||||
t.integer :sellable_id
|
||||
t.string :sellable_type
|
||||
end
|
||||
|
||||
create_table :posts, :force => true do |t|
|
||||
t.integer :author_id
|
||||
t.string :title, :null => false
|
||||
|
@ -390,6 +400,7 @@ ActiveRecord::Schema.define do
|
|||
create_table :readers, :force => true do |t|
|
||||
t.integer :post_id, :null => false
|
||||
t.integer :person_id, :null => false
|
||||
t.boolean :skimmer, :default => false
|
||||
end
|
||||
|
||||
create_table :shape_expressions, :force => true do |t|
|
||||
|
@ -435,6 +446,8 @@ ActiveRecord::Schema.define do
|
|||
t.datetime :ending
|
||||
end
|
||||
|
||||
create_table :ties, :force => true
|
||||
|
||||
create_table :topics, :force => true do |t|
|
||||
t.string :title
|
||||
t.string :author_name
|
||||
|
@ -448,6 +461,7 @@ ActiveRecord::Schema.define do
|
|||
t.integer :parent_id
|
||||
t.string :parent_title
|
||||
t.string :type
|
||||
t.string :group
|
||||
end
|
||||
|
||||
create_table :taggings, :force => true do |t|
|
||||
|
@ -462,6 +476,8 @@ ActiveRecord::Schema.define do
|
|||
t.column :taggings_count, :integer, :default => 0
|
||||
end
|
||||
|
||||
create_table :tees, :force => true
|
||||
|
||||
create_table :toys, :primary_key => :toy_id ,:force => true do |t|
|
||||
t.string :name
|
||||
t.integer :pet_id, :integer
|
||||
|
|
5
vendor/rails/activeresource/CHANGELOG
vendored
5
vendor/rails/activeresource/CHANGELOG
vendored
|
@ -1,8 +1,5 @@
|
|||
*2.3.9 (September 4, 2010)*
|
||||
*2.3.8 (May 24, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
||||
|
||||
*2.3.7 (May 24, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
|
2
vendor/rails/activeresource/Rakefile
vendored
2
vendor/rails/activeresource/Rakefile
vendored
|
@ -66,7 +66,7 @@ spec = Gem::Specification.new do |s|
|
|||
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
||||
end
|
||||
|
||||
s.add_dependency('activesupport', '= 2.3.8' + PKG_BUILD)
|
||||
s.add_dependency('activesupport', '= 2.3.9' + PKG_BUILD)
|
||||
|
||||
s.require_path = 'lib'
|
||||
s.autorequire = 'active_resource'
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue