1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge branch 'master' of git@github.com:rails/rails

This commit is contained in:
rick 2008-05-13 09:41:10 -07:00
commit 74fd17346f
72 changed files with 292 additions and 140 deletions

View file

@ -1,4 +1,4 @@
*SVN*
*2.1.0 RC1 (May 11th, 2008)*
* Fixed that a return-path header would be ignored #7572 [joost]

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2007 David Heinemeier Hansson
Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 2.0.2' + PKG_BUILD)
s.add_dependency('actionpack', '= 2.0.991' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'

View file

@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2007 David Heinemeier Hansson
# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the

View file

@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
TINY = 2
TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -1,4 +1,8 @@
*SVN*
*2.1.0 RC1 (May 11th, 2008)*
* Fixed that forgery protection can be used without session tracking (Peter Jones) [#139]
* Added session(:on) to turn session management back on in a controller subclass if the superclass turned it off (Peter Jones) [#136]
* Change the request forgery protection to go by Content-Type instead of request.format so that you can't bypass it by POSTing to "#{request.uri}.xml" [rick]
* InstanceTag#default_time_from_options with hash args uses Time.current as default; respects hash settings when time falls in system local spring DST gap [Geoff Buesing]

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2007 David Heinemeier Hansson
Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -76,7 +76,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true
s.requirements << 'none'
s.add_dependency('activesupport', '= 2.0.2' + PKG_BUILD)
s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'action_controller'

View file

@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2007 David Heinemeier Hansson
# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the

View file

@ -37,7 +37,7 @@ class CGI #:nodoc:
@path = nil
else
@name = name['name']
@value = Array(name['value'])
@value = name['value'].kind_of?(String) ? [name['value']] : Array(name['value'])
@domain = name['domain']
@expires = name['expires']
@secure = name['secure'] || false

View file

@ -28,7 +28,6 @@ module ActionController #:nodoc:
base.class_eval do
include InstanceMethods
alias_method_chain :assign_shortcuts, :flash
alias_method_chain :process_cleanup, :flash
alias_method_chain :reset_session, :flash
end
end
@ -166,11 +165,7 @@ module ActionController #:nodoc:
def assign_shortcuts_with_flash(request, response) #:nodoc:
assign_shortcuts_without_flash(request, response)
flash(:refresh)
end
def process_cleanup_with_flash
flash.sweep if @_session
process_cleanup_without_flash
flash.sweep if @_session && !component_request?
end
end
end

View file

@ -105,12 +105,12 @@ module ActionController #:nodoc:
# Sets the token value for the current session. Pass a <tt>:secret</tt> option
# in +protect_from_forgery+ to add a custom salt to the hash.
def form_authenticity_token
@form_authenticity_token ||= if request_forgery_protection_options[:secret]
@form_authenticity_token ||= if !session.respond_to?(:session_id)
raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session. Use #allow_forgery_protection to disable it, or use a valid session."
elsif request_forgery_protection_options[:secret]
authenticity_token_from_session_id
elsif session.respond_to?(:dbman) && session.dbman.respond_to?(:generate_digest)
authenticity_token_from_cookie_session
elsif session.nil?
raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session. Use #allow_forgery_protection to disable it, or use a valid session."
else
raise InvalidAuthenticityToken, "No :secret given to the #protect_from_forgery call. Set that or use a session store capable of generating its own keys (Cookie Session Store)."
end

View file

@ -199,10 +199,8 @@ module ActionController #:nodoc:
private
def perform_action_with_rescue #:nodoc:
perform_action_without_rescue
rescue Exception => exception # errors from action performed
return if rescue_action_with_handler(exception)
rescue_action(exception)
rescue Exception => exception
rescue_action_with_handler(exception) || rescue_action(exception)
end
def rescues_path(template_name)

View file

@ -130,17 +130,20 @@ class CGI::Session::CookieStore
# Marshal a session hash into safe cookie data. Include an integrity hash.
def marshal(session)
data = ActiveSupport::Base64.encode64(Marshal.dump(session)).chop
CGI.escape "#{data}--#{generate_digest(data)}"
"#{data}--#{generate_digest(data)}"
end
# Unmarshal cookie data to a hash and verify its integrity.
def unmarshal(cookie)
if cookie
data, digest = CGI.unescape(cookie).split('--')
unless digest == generate_digest(data)
data, digest = cookie.split('--')
# Do two checks to transparently support old double-escaped data.
unless digest == generate_digest(data) || digest == generate_digest(data = CGI.unescape(data))
delete
raise TamperedWithCookie
end
Marshal.load(ActiveSupport::Base64.decode64(data))
end
end

View file

@ -69,11 +69,16 @@ module ActionController #:nodoc:
# session :off,
# :if => Proc.new { |req| !(req.format.html? || req.format.js?) }
#
# # turn the session back on, useful when it was turned off in the
# # application controller, and you need it on in another controller
# session :on
#
# All session options described for ActionController::Base.process_cgi
# are valid arguments.
def session(*args)
options = args.extract_options!
options[:disabled] = false if args.delete(:on)
options[:disabled] = true if !args.empty?
options[:only] = [*options[:only]].map { |o| o.to_s } if options[:only]
options[:except] = [*options[:except]].map { |o| o.to_s } if options[:except]

View file

@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2007 David Heinemeier Hansson
# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the

View file

@ -2,7 +2,7 @@ module ActionPack #:nodoc:
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
TINY = 2
TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2007 David Heinemeier Hansson
# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the

View file

@ -1,4 +1,4 @@
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:

View file

@ -1,4 +1,4 @@
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.

View file

@ -1,4 +1,4 @@
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
// Justin Palmer (http://encytemedia.com/)
// Mark Pilgrim (http://diveintomark.org/)

View file

@ -48,6 +48,11 @@ module ActionView
# config.action_view.sanitized_allowed_attributes = 'id', 'class', 'style'
# end
#
# Please note that sanitizing user-provided text does not guarantee that the
# resulting markup is valid (conforming to a document type) or even well-formed.
# The output may still contain e.g. unescaped '<', '>', '&' characters and
# confuse browsers.
#
def sanitize(html, options = {})
self.class.white_list_sanitizer.sanitize(html, options)
end

View file

@ -137,4 +137,9 @@ class CookieTest < Test::Unit::TestCase
cookies = CGI::Cookie.parse('return_to=http://rubyonrails.org/search?term=api&scope=all&global=true')
assert_equal({"return_to" => ["http://rubyonrails.org/search?term=api&scope=all&global=true"]}, cookies)
end
def test_cookies_should_not_be_split_on_values_with_newlines
cookies = CGI::Cookie.new("name" => "val", "value" => "this\nis\na\ntest")
assert cookies.size == 1
end
end

View file

@ -50,6 +50,14 @@ class CsrfCookieMonsterController < ActionController::Base
protect_from_forgery :only => :index
end
# sessions are turned off
class SessionOffController < ActionController::Base
protect_from_forgery :secret => 'foobar'
session :off
def rescue_action(e) raise e end
include RequestForgeryProtectionActions
end
class FreeCookieController < CsrfCookieMonsterController
self.allow_forgery_protection = false
@ -287,3 +295,19 @@ class FreeCookieControllerTest < Test::Unit::TestCase
end
end
end
class SessionOffControllerTest < Test::Unit::TestCase
def setup
@controller = SessionOffController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
end
def test_should_raise_correct_exception
@request.session = {} # session(:off) doesn't appear to work with controller tests
assert_raises(ActionController::InvalidAuthenticityToken) do
post :index, :authenticity_token => @token
end
end
end

View file

@ -43,7 +43,9 @@ class CookieStoreTest < Test::Unit::TestCase
{ :empty => ['BAgw--0686dcaccc01040f4bd4f35fe160afe9bc04c330', {}],
:a_one => ['BAh7BiIGYWkG--5689059497d7f122a7119f171aef81dcfd807fec', { 'a' => 1 }],
:typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--9d20154623b9eeea05c62ab819be0e2483238759', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
:flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--bf9785a666d3c4ac09f7fe3353496b437546cfbf', { 'user_id' => 123, 'flash' => {} }] }
:flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA==--bf9785a666d3c4ac09f7fe3353496b437546cfbf', { 'user_id' => 123, 'flash' => {} }],
:double_escaped => [CGI.escape('BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--bf9785a666d3c4ac09f7fe3353496b437546cfbf'), { 'user_id' => 123, 'flash' => {} }] }
end
def setup
@ -101,6 +103,15 @@ class CookieStoreTest < Test::Unit::TestCase
end
end
def test_restores_double_encoded_cookies
set_cookie! cookie_value(:double_escaped)
new_session do |session|
session.dbman.restore
assert_equal session["user_id"], 123
assert_equal session["flash"], {}
end
end
def test_close_doesnt_write_cookie_if_data_is_blank
new_session do |session|
assert_no_cookies session
@ -241,6 +252,7 @@ class CookieStoreWithMD5DigestTest < CookieStoreTest
{ :empty => ['BAgw--0415cc0be9579b14afc22ee2d341aa21', {}],
:a_one => ['BAh7BiIGYWkG--5a0ed962089cc6600ff44168a5d59bc8', { 'a' => 1 }],
:typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--f426763f6ef435b3738b493600db8d64', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
:flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--0af9156650dab044a53a91a4ddec2c51', { 'user_id' => 123, 'flash' => {} }] }
:flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA==--0af9156650dab044a53a91a4ddec2c51', { 'user_id' => 123, 'flash' => {} }],
:double_escaped => [CGI.escape('BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--0af9156650dab044a53a91a4ddec2c51'), { 'user_id' => 123, 'flash' => {} }] }
end
end

View file

@ -13,6 +13,19 @@ class SessionManagementTest < Test::Unit::TestCase
end
end
class SessionOffOnController < ActionController::Base
session :off
session :on, :only => :tell
def show
render :text => "done"
end
def tell
render :text => "done"
end
end
class TestController < ActionController::Base
session :off, :only => :show
session :session_secure => true, :except => :show
@ -100,6 +113,15 @@ class SessionManagementTest < Test::Unit::TestCase
assert_equal false, @request.session_options
end
def test_session_off_then_on_globally
@controller = SessionOffOnController.new
get :show
assert_equal false, @request.session_options
get :tell
assert_instance_of Hash, @request.session_options
assert_equal false, @request.session_options[:disabled]
end
def test_session_off_conditionally
@controller = TestController.new
get :show

View file

@ -12,6 +12,11 @@ class TestTest < Test::Unit::TestCase
render :text => 'ignore me'
end
def set_flash_now
flash.now["test_now"] = ">#{flash["test_now"]}<"
render :text => 'ignore me'
end
def set_session
session['string'] = 'A wonder'
session[:symbol] = 'it works'
@ -145,6 +150,11 @@ XML
assert_equal '>value<', flash['test']
end
def test_process_with_flash_now
process :set_flash_now, nil, nil, { "test_now" => "value_now" }
assert_equal '>value_now<', flash['test_now']
end
def test_process_with_session
process :set_session
assert_equal 'A wonder', session['string'], "A value stored in the session should be available by string key"

View file

@ -1,4 +1,8 @@
*SVN*
*2.1.0 RC1 (May 11th, 2008)*
* Ensure hm:t preloading honours reflection options. Resolves #137. [Frederick Cheung]
* Added protection against duplicate migration names (Aslak Hellesøy) [#112]
* Base#instantiate_time_object: eliminate check for Time.zone, since we can assume this is set if time_zone_aware_attributes is set to true [Geoff Buesing]

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2007 David Heinemeier Hansson
Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -171,7 +171,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.0.2' + PKG_BUILD)
s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD)
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"

View file

@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2007 David Heinemeier Hansson
# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the

View file

@ -31,12 +31,12 @@ module ActiveRecord
private
def preload_one_association(records, association, preload_options={})
reflection = reflections[association]
raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection
# Not all records have the same class, so group then preload.
records.group_by(&:class).each do |klass, records|
reflection = klass.reflections[association]
class_to_reflection = {}
# Not all records have the same class, so group then preload
# group on the reflection itself so that if various subclass share the same association then we do not split them
# unncessarily
records.group_by {|record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, records|
raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection
send("preload_#{reflection.macro}_association", records, reflection, preload_options)
end
end
@ -143,7 +143,8 @@ module ActiveRecord
through_primary_key = through_reflection.primary_key_name
unless through_records.empty?
source = reflection.source_reflection.name
through_records.first.class.preload_associations(through_records, source)
#add conditions from reflection!
through_records.first.class.preload_associations(through_records, source, reflection.options)
through_records.each do |through_record|
add_preloaded_records_to_collection(id_to_record_map[through_record[through_primary_key].to_s],
reflection.name, through_record.send(source))
@ -251,12 +252,12 @@ module ActiveRecord
conditions << append_conditions(options, preload_options)
reflection.klass.find(:all,
:select => (options[:select] || "#{table_name}.*"),
:include => options[:include],
:select => (preload_options[:select] || options[:select] || "#{table_name}.*"),
:include => preload_options[:include] || options[:include],
:conditions => [conditions, ids],
:joins => options[:joins],
:group => options[:group],
:order => options[:order])
:group => preload_options[:group] || options[:group],
:order => preload_options[:order] || options[:order])
end

View file

@ -1910,6 +1910,8 @@ module ActiveRecord #:nodoc:
# { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'"
# "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"
def sanitize_sql_for_conditions(condition)
return nil if condition.blank?
case condition
when Array; sanitize_sql_array(condition)
when Hash; sanitize_sql_hash_for_conditions(condition)
@ -2340,7 +2342,7 @@ module ActiveRecord #:nodoc:
# Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
def attributes(options = nil)
def attributes
self.attribute_names.inject({}) do |attrs, name|
attrs[name] = read_attribute(name)
attrs

View file

@ -69,19 +69,19 @@ module ActiveRecord
changed.inject({}) { |h, attr| h[attr] = attribute_change(attr); h }
end
# Clear changed attributes after they are saved.
# Attempts to +save+ the record and clears changed attributes if successful.
def save_with_dirty(*args) #:nodoc:
save_without_dirty(*args)
ensure
changed_attributes.clear
if status = save_without_dirty(*args)
changed_attributes.clear
end
status
end
# Clear changed attributes after they are saved.
# Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
def save_with_dirty!(*args) #:nodoc:
save_without_dirty!(*args)
ensure
status = save_without_dirty!(*args)
changed_attributes.clear
status
end
private

View file

@ -8,6 +8,12 @@ module ActiveRecord
end
end
class DuplicateMigrationNameError < ActiveRecordError#:nodoc:
def initialize(name)
super("Multiple migrations have the name #{name}")
end
end
class UnknownMigrationVersionError < ActiveRecordError #:nodoc:
def initialize(version)
super("No migration with version number #{version}")
@ -440,6 +446,10 @@ module ActiveRecord
if klasses.detect { |m| m.version == version }
raise DuplicateMigrationVersionError.new(version)
end
if klasses.detect { |m| m.name == name.camelize }
raise DuplicateMigrationNameError.new(name.camelize)
end
load(file)

View file

@ -71,6 +71,18 @@ module ActiveRecord
# end
# end
#
#
# For testing complex named scopes, you can examine the scoping options using the
# <tt>proxy_options</tt> method on the proxy itself.
#
# class Shirt < ActiveRecord::Base
# named_scope :colored, lambda { |color|
# { :conditions => { :color => color } }
# }
# end
#
# expected_options = { :conditions => { :colored => 'red' } }
# assert_equal expected_options, Shirt.colored('red').proxy_options
def named_scope(name, options = {}, &block)
scopes[name] = lambda do |parent_scope, *args|
Scope.new(parent_scope, case options

View file

@ -640,7 +640,7 @@ module ActiveRecord
results = finder_class.with_exclusive_scope do
connection.select_all(
construct_finder_sql(
:select => "#{attr_name}",
:select => "#{connection.quote_column_name(attr_name)}",
:from => "#{finder_class.quoted_table_name}",
:conditions => [condition_sql, *condition_params]
)

View file

@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
TINY = 2
TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -275,6 +275,17 @@ class EagerAssociationTest < ActiveRecord::TestCase
Author.find(:first, :order => 'authors.id').hello_post_comments.sort_by(&:id)
end
def test_eager_with_has_many_through_join_model_with_conditions_on_top_level
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_join_model_with_include
author_comments = Author.find(authors(:david).id, :include => :comments_with_include).comments_with_include.to_a
assert_no_queries do
author_comments.first.post.title
end
end
def test_eager_with_has_many_and_limit
posts = Post.find(:all, :order => 'posts.id asc', :include => [ :author, :comments ], :limit => 2)
assert_equal 2, posts.size
@ -592,4 +603,10 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(comments.body) > 15")
end
end
def test_load_with_sti_sharing_association
assert_queries(2) do #should not do 1 query per subclass
Comment.find :all, :include => :post
end
end
end

View file

@ -48,6 +48,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 2, Firm.find(:first).clients.length
end
def test_find_with_blank_conditions
[[], {}, nil, ""].each do |blank|
assert_equal 2, Firm.find(:first).clients.find(:all, :conditions => blank).size
end
end
def test_find_many_with_merged_options
assert_equal 1, companies(:first_firm).limited_clients.size
assert_equal 1, companies(:first_firm).limited_clients.find(:all).size
@ -851,4 +857,4 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert ! firm.clients.include?(client)
end
end
end

View file

@ -78,7 +78,7 @@ class DirtyTest < ActiveRecord::TestCase
end
def test_association_assignment_changes_foreign_key
pirate = Pirate.create!
pirate = Pirate.create!(:catchphrase => 'jarl')
pirate.parrot = Parrot.create!
assert pirate.changed?
assert_equal %w(parrot_id), pirate.changed
@ -115,6 +115,18 @@ class DirtyTest < ActiveRecord::TestCase
end
end
def test_changed_attributes_should_be_preserved_if_save_failure
pirate = Pirate.new
pirate.parrot_id = 1
assert !pirate.save
check_pirate_after_save_failure(pirate)
pirate = Pirate.new
pirate.parrot_id = 1
assert_raises(ActiveRecord::RecordInvalid) { pirate.save! }
check_pirate_after_save_failure(pirate)
end
private
def with_partial_updates(klass, on = true)
old = klass.partial_updates?
@ -123,4 +135,11 @@ class DirtyTest < ActiveRecord::TestCase
ensure
klass.partial_updates = old
end
def check_pirate_after_save_failure(pirate)
assert pirate.changed?
assert pirate.parrot_id_changed?
assert_equal %w(parrot_id), pirate.changed
assert_nil pirate.parrot_id_was
end
end

View file

@ -984,6 +984,12 @@ if ActiveRecord::Base.connection.supports_migrations?
end
end
def test_migrator_with_duplicate_names
assert_raises(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do
ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/duplicate_names", nil)
end
end
def test_migrator_with_missing_version_numbers
assert_raise(ActiveRecord::UnknownMigrationVersionError) do
ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/missing", 500)

View file

@ -112,4 +112,10 @@ class NamedScopeTest < ActiveRecord::TestCase
assert_equal Topic.find(:all, scope), Topic.scoped(scope)
end
def test_proxy_options
expected_proxy_options = { :conditions => { :approved => true } }
assert_equal expected_proxy_options, Topic.approved.proxy_options
end
end

View file

@ -5,6 +5,7 @@ require 'models/reply'
require 'models/person'
require 'models/developer'
require 'models/warehouse_thing'
require 'models/guid'
# The following methods in Topic are used in test_conditional_validation_*
class Topic
@ -493,6 +494,13 @@ class ValidationsTest < ActiveRecord::TestCase
end
end
def test_validate_uniqueness_with_columns_which_are_sql_keywords
Guid.validates_uniqueness_of :key
g = Guid.new
g.key = "foo"
assert_nothing_raised { !g.valid? }
end
def test_validate_straight_inheritance_uniqueness
w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork")
assert w1.valid?, "Saving w1"

View file

@ -0,0 +1,7 @@
class Chunky < ActiveRecord::Migration
def self.up
end
def self.down
end
end

View file

@ -0,0 +1,7 @@
class Chunky < ActiveRecord::Migration
def self.up
end
def self.down
end
end

View file

@ -17,6 +17,10 @@ class Author < ActiveRecord::Base
end
has_many :comments, :through => :posts
has_many :comments_containing_the_letter_e, :through => :posts, :source => :comments
has_many :comments_with_order_and_conditions, :through => :posts, :source => :comments, :order => 'comments.body', :conditions => "comments.body like 'Thank%'"
has_many :comments_with_include, :through => :posts, :source => :comments, :include => :post
has_many :comments_desc, :through => :posts, :source => :comments, :order => 'comments.id DESC'
has_many :limited_comments, :through => :posts, :source => :comments, :limit => 1
has_many :funky_comments, :through => :posts, :source => :comments

View file

@ -0,0 +1,2 @@
class Guid < ActiveRecord::Base
end

View file

@ -4,4 +4,6 @@ class Pirate < ActiveRecord::Base
has_many :treasures, :as => :looter
has_many :treasure_estimates, :through => :treasures, :source => :price_estimates
validates_presence_of :catchphrase
end

View file

@ -403,6 +403,10 @@ ActiveRecord::Schema.define do
create_table(t, :force => true) { }
end
create_table :guids, :force => true do |t|
t.column :key, :string
end
except 'SQLite' do
# fk_test_has_fk should be before fk_test_has_pk
create_table :fk_test_has_fk, :force => true do |t|

View file

@ -1,4 +1,4 @@
*SVN*
*2.1.0 RC1 (May 11th, 2008)*
* Fixed response logging to use length instead of the entire thing (seangeo) [#27]

View file

@ -64,7 +64,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.0.2' + PKG_BUILD)
s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'active_resource'

View file

@ -2,7 +2,7 @@ module ActiveResource
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
TINY = 2
TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -1,4 +1,6 @@
*SVN*
*2.1.0 RC1 (May 11th, 2008)*
* Remove unused JSON::RESERVED_WORDS, JSON.valid_identifier? and JSON.reserved_word? methods. Resolves #164. [Cheah Chu Yeow]
* Adding Date.current, which returns Time.zone.today if config.time_zone is set; otherwise returns Date.today [Geoff Buesing]

View file

@ -1,4 +1,4 @@
Copyright (c) 2005-2007 David Heinemeier Hansson
Copyright (c) 2005-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -128,7 +128,7 @@ class Class # :nodoc:
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
else
new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
memo.update(key => (value.dup rescue value))
memo.update(key => value.duplicable? ? value.dup : value)
end
end

View file

@ -176,19 +176,6 @@ module ActiveSupport
end
end
class DeprecatedInstanceVariable < Delegator #:nodoc:
def initialize(value, method)
super(value)
@method = method
@value = value
end
def __getobj__
ActiveSupport::Deprecation.warn("Instance variable @#{@method} is deprecated! Call instance method #{@method} instead.")
@value
end
end
end
end

View file

@ -1,5 +1,3 @@
module ActiveSupport
# If true, use ISO 8601 format for dates and times. Otherwise, fall back to the ActiveSupport legacy format.
mattr_accessor :use_standard_json_time_format
@ -19,33 +17,6 @@ module ActiveSupport
@escape_html_entities_in_json = value
end
end
module JSON
RESERVED_WORDS = %w(
abstract delete goto private transient
boolean do if protected try
break double implements public typeof
byte else import return var
case enum in short void
catch export instanceof static volatile
char extends int super while
class final interface switch with
const finally long synchronized
continue float native this
debugger for new throw
default function package throws
) #:nodoc:
class << self
def valid_identifier?(key) #:nodoc:
key.to_s =~ /^[[:alpha:]_$][[:alnum:]_$]*$/ && !reserved_word?(key)
end
def reserved_word?(key) #:nodoc:
RESERVED_WORDS.include?(key.to_s)
end
end
end
end
require 'active_support/json/encoding'

View file

@ -2,7 +2,7 @@ module ActiveSupport
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
TINY = 2
TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -149,13 +149,3 @@ class DeprecationTest < Test::Unit::TestCase
assert_nil @last_message
end
end
class DeprecatedIvarTest < Test::Unit::TestCase
def test_deprecated_ivar
@action = ActiveSupport::Deprecation::DeprecatedInstanceVariable.new("fubar", :foobar)
assert_deprecated(/Instance variable @foobar is deprecated! Call instance method foobar instead/) { assert_equal "fubar", @action }
end
end

View file

@ -1,7 +1,7 @@
#!/usr/bin/env ruby
unless ARGV.first == "no_build"
build_number = build_number = `svn log -q -rhead http://dev.rubyonrails.org/svn/rails`.scan(/r([0-9]*)/).first.first.to_i
build_number = Time.now.strftime("%Y%m%d%H%M%S").to_i
end
%w( activeresource actionmailer actionpack activerecord railties activesupport ).each do |pkg|

View file

@ -1,4 +1,4 @@
*SVN*
*2.1.0 RC1 (May 11th, 2008)*
* script/dbconsole fires up the command-line database client. #102 [Steve Purcell]

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2007 David Heinemeier Hansson
Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -255,7 +255,7 @@ task :generate_rails_framework_doc do
end
task :generate_app_doc do
File.cp "doc/README_FOR_APP", "#{PKG_DESTINATION}/doc/README_FOR_APP"
cp "doc/README_FOR_APP", "#{PKG_DESTINATION}/doc/README_FOR_APP"
system %{cd #{PKG_DESTINATION}; rake doc:app}
end
@ -303,12 +303,12 @@ spec = Gem::Specification.new do |s|
on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.
EOF
s.add_dependency('rake', '>= 0.7.2')
s.add_dependency('activesupport', '= 2.0.2' + PKG_BUILD)
s.add_dependency('activerecord', '= 2.0.2' + PKG_BUILD)
s.add_dependency('actionpack', '= 2.0.2' + PKG_BUILD)
s.add_dependency('actionmailer', '= 2.0.2' + PKG_BUILD)
s.add_dependency('activeresource', '= 2.0.2' + PKG_BUILD)
s.add_dependency('rake', '>= 0.8.1')
s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD)
s.add_dependency('activerecord', '= 2.0.991' + PKG_BUILD)
s.add_dependency('actionpack', '= 2.0.991' + PKG_BUILD)
s.add_dependency('actionmailer', '= 2.0.991' + PKG_BUILD)
s.add_dependency('activeresource', '= 2.0.991' + PKG_BUILD)
s.rdoc_options << '--exclude' << '.'
s.has_rdoc = false

View file

@ -1,4 +1,4 @@
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:

View file

@ -1,4 +1,4 @@
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.

View file

@ -1,4 +1,4 @@
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
// Justin Palmer (http://encytemedia.com/)
// Mark Pilgrim (http://diveintomark.org/)

View file

@ -1,3 +1,4 @@
require 'erb'
require 'yaml'
require 'optparse'
@ -8,7 +9,7 @@ OptionParser.new do |opt|
end
env = ARGV.first || ENV['RAILS_ENV'] || 'development'
unless config = YAML.load_file(RAILS_ROOT + "/config/database.yml")[env]
unless config = YAML::load(ERB.new(IO.read(RAILS_ROOT + "/config/database.yml")).result)[env]
abort "No database is configured for the environment '#{env}'"
end

View file

@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2007 David Heinemeier Hansson
# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the

View file

@ -2,7 +2,7 @@ module Rails
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
TINY = 2
TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -34,7 +34,7 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
m.class_collisions(controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper")
m.class_collisions(class_path, "#{class_name}")
# Controller, helper, views, and test directories.
# Controller, helper, views, test and stylesheets directories.
m.directory(File.join('app/models', class_path))
m.directory(File.join('app/controllers', controller_class_path))
m.directory(File.join('app/helpers', controller_class_path))
@ -42,6 +42,7 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
m.directory(File.join('app/views/layouts', controller_class_path))
m.directory(File.join('test/functional', controller_class_path))
m.directory(File.join('test/unit', class_path))
m.directory(File.join('public/stylesheets', class_path))
for action in scaffold_views
m.template(

View file

@ -45,7 +45,7 @@ namespace :db do
when 'postgresql'
@encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
begin
ActiveRecord::Base.establish_connection(config.merge('database' => 'template1'))
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres'))
ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
ActiveRecord::Base.establish_connection(config)
rescue
@ -368,7 +368,7 @@ def drop_database(config)
when /^sqlite/
FileUtils.rm(File.join(RAILS_ROOT, config['database']))
when 'postgresql'
ActiveRecord::Base.establish_connection(config.merge('database' => 'template1'))
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres'))
ActiveRecord::Base.connection.drop_database config['database']
end
end