From aef47dcf937a5c9f150c50b73cffd9fa9eb64915 Mon Sep 17 00:00:00 2001 From: Tim Harper Date: Tue, 13 May 2008 19:17:40 -0600 Subject: [PATCH 1/7] belongs_to polymorphic association assignments update the foreign_id and foreign_type fields regardless of whether the record being assigned is new or not. fixes the following scenarios: * I have validates_inclusion_of on the type field for a polymorphic belongs_to association. I assign a new record to the model's polymorphic relationship of the proper type. validation fails because the type field has not been updated. * I replace the value for a ppolymorphic association to a new record of another class. The type field still says its the previous class, and the id field points to the previous record as well. --- .../belongs_to_polymorphic_association.rb | 6 ++-- .../belongs_to_associations_test.rb | 29 ++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index df4ae38f38..d8146daa54 100755 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -7,10 +7,8 @@ module ActiveRecord else @target = (AssociationProxy === record ? record.target : record) - unless record.new_record? - @owner[@reflection.primary_key_name] = record.id - @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s - end + @owner[@reflection.primary_key_name] = record.id + @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s @updated = true end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 3073eae355..e0da8bfb7a 100755 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -12,6 +12,8 @@ require 'models/author' require 'models/tag' require 'models/tagging' require 'models/comment' +require 'models/sponsor' +require 'models/member' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -381,5 +383,30 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! } assert companies(:first_client).readonly_firm.readonly? end - + + def test_polymorphic_assignment_foreign_type_field_updating + # should update when assigning a saved record + sponsor = Sponsor.new + member = Member.create + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + + # should update when assigning a new record + sponsor = Sponsor.new + member = Member.new + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + end + + def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records + sponsor = Sponsor.new + saved_member = Member.create + new_member = Member.new + + sponsor.sponsorable = saved_member + assert_equal saved_member.id, sponsor.sponsorable_id + + sponsor.sponsorable = new_member + assert_equal nil, sponsor.sponsorable_id + end end From 0580b31b36c0f7dd1a0f8bdd1b1806e3bd65b22d Mon Sep 17 00:00:00 2001 From: Tim Harper Date: Tue, 13 May 2008 19:17:40 -0600 Subject: [PATCH 2/7] belongs_to polymorphic association assignments update the foreign_id and foreign_type fields regardless of whether the record being assigned is new or not. fixes the following scenarios: * I have validates_inclusion_of on the type field for a polymorphic belongs_to association. I assign a new record to the model's polymorphic relationship of the proper type. validation fails because the type field has not been updated. * I replace the value for a ppolymorphic association to a new record of another class. The type field still says its the previous class, and the id field points to the previous record as well. [#191 state:closed] --- .../belongs_to_polymorphic_association.rb | 6 ++-- .../belongs_to_associations_test.rb | 29 ++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index df4ae38f38..d8146daa54 100755 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -7,10 +7,8 @@ module ActiveRecord else @target = (AssociationProxy === record ? record.target : record) - unless record.new_record? - @owner[@reflection.primary_key_name] = record.id - @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s - end + @owner[@reflection.primary_key_name] = record.id + @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s @updated = true end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 3073eae355..e0da8bfb7a 100755 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -12,6 +12,8 @@ require 'models/author' require 'models/tag' require 'models/tagging' require 'models/comment' +require 'models/sponsor' +require 'models/member' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -381,5 +383,30 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! } assert companies(:first_client).readonly_firm.readonly? end - + + def test_polymorphic_assignment_foreign_type_field_updating + # should update when assigning a saved record + sponsor = Sponsor.new + member = Member.create + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + + # should update when assigning a new record + sponsor = Sponsor.new + member = Member.new + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + end + + def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records + sponsor = Sponsor.new + saved_member = Member.create + new_member = Member.new + + sponsor.sponsorable = saved_member + assert_equal saved_member.id, sponsor.sponsorable_id + + sponsor.sponsorable = new_member + assert_equal nil, sponsor.sponsorable_id + end end From 77e45352e7e947f1df1bfb8fe7d9e4e133224dd9 Mon Sep 17 00:00:00 2001 From: Tom Ward Date: Sat, 31 May 2008 13:33:38 -0700 Subject: [PATCH 3/7] Fixed Dependencies so load errors are not masked behind a 'Expected x.rb to define X' message when mechanism is not set to :load [#87 state:resolved] Signed-off-by: Joshua Peek --- .../lib/active_support/dependencies.rb | 19 +++++++++--------- activesupport/test/dependencies_test.rb | 20 +++++++++++++------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 25225d5615..da2ece610a 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -82,9 +82,10 @@ module Dependencies #:nodoc: # infinite loop with mutual dependencies. loaded << expanded - if load? - log "loading #{file_name}" - begin + begin + if load? + log "loading #{file_name}" + # Enable warnings iff this file has not been loaded before and # warnings_on_first_load is set. load_args = ["#{file_name}.rb"] @@ -95,13 +96,13 @@ module Dependencies #:nodoc: else enable_warnings { result = load_file(*load_args) } end - rescue Exception - loaded.delete expanded - raise + else + log "requiring #{file_name}" + result = require file_name end - else - log "requiring #{file_name}" - result = require file_name + rescue Exception + loaded.delete expanded + raise end # Record history *after* loading so first load gets warnings. diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 1e19e12da9..0309ab6858 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -673,7 +673,7 @@ class DependenciesTest < Test::Unit::TestCase assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!" end end - + ensure Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) } end @@ -686,11 +686,20 @@ class DependenciesTest < Test::Unit::TestCase assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!" end end - + ensure Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) } end + def test_autoload_doesnt_shadow_error_when_mechanism_not_set_to_load + with_loading 'autoloading_fixtures' do + Dependencies.mechanism = :require + 2.times do + assert_raise(NameError) {"RaisesNameError".constantize} + end + end + end + def test_autoload_doesnt_shadow_name_error with_loading 'autoloading_fixtures' do assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it hasn't been referenced yet!" @@ -714,7 +723,7 @@ class DependenciesTest < Test::Unit::TestCase ensure Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) } end - + def test_remove_constant_handles_double_colon_at_start Object.const_set 'DeleteMe', Module.new DeleteMe.const_set 'OrMe', Module.new @@ -724,7 +733,7 @@ class DependenciesTest < Test::Unit::TestCase Dependencies.remove_constant "::DeleteMe" assert ! defined?(DeleteMe) end - + def test_load_once_constants_should_not_be_unloaded with_loading 'autoloading_fixtures' do Dependencies.load_once_paths = Dependencies.load_paths @@ -737,7 +746,7 @@ class DependenciesTest < Test::Unit::TestCase Dependencies.load_once_paths = [] Object.class_eval { remove_const :A if const_defined?(:A) } end - + def test_load_once_paths_should_behave_when_recursively_loading with_loading 'dependencies', 'autoloading_fixtures' do Dependencies.load_once_paths = [Dependencies.load_paths.last] @@ -753,5 +762,4 @@ class DependenciesTest < Test::Unit::TestCase ensure Dependencies.load_once_paths = [] end - end From 4e4bcb4c6b08ed392cd5576dcfc252ef574a1b88 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 31 May 2008 14:54:17 -0700 Subject: [PATCH 4/7] Ruby 1.8.7 compat: TimeWithZone# and Chars#respond_to? pass along the include_private argument --- activesupport/lib/active_support/multibyte/chars.rb | 12 +++++++----- activesupport/lib/active_support/time_with_zone.rb | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index ee716de39e..185d03020c 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -40,13 +40,15 @@ module ActiveSupport::Multibyte #:nodoc: # core dumps. Don't go there. @string end - + # Make duck-typing with String possible - def respond_to?(method) - super || @string.respond_to?(method) || handler.respond_to?(method) || - (method.to_s =~ /(.*)!/ && handler.respond_to?($1)) || false + def respond_to?(method, include_priv = false) + super || @string.respond_to?(method, include_priv) || + handler.respond_to?(method, include_priv) || + (method.to_s =~ /(.*)!/ && handler.respond_to?($1, include_priv)) || + false end - + # Create a new Chars instance. def initialize(str) @string = str.respond_to?(:string) ? str.string : str diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index ece95eeae9..bfc5b16039 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -248,14 +248,14 @@ module ActiveSupport def marshal_load(variables) initialize(variables[0], ::Time.send!(:get_zone, variables[1]), variables[2]) end - + # Ensure proxy class responds to all methods that underlying time instance responds to. - def respond_to?(sym) + def respond_to?(sym, include_priv = false) # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime return false if sym.to_s == 'acts_like_date?' - super || time.respond_to?(sym) + super || time.respond_to?(sym, include_priv) end - + # Send the missing method to +time+ instance, and wrap result in a new TimeWithZone with the existing +time_zone+. def method_missing(sym, *args, &block) result = time.__send__(sym, *args, &block) From 0abf0da0016abc455145810d7060a10e0b56b0b6 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Sat, 31 May 2008 14:58:34 -0700 Subject: [PATCH 5/7] Don't provide the password with dbconsole unless explicitly opted in. Some operating system configurations allow other users to view your process list or environmental variables. This option should not be used on shared hosts. http://dev.mysql.com/doc/refman/5.0/en/password-security.html http://www.postgresql.org/docs/8.3/static/libpq-envars.html --- railties/lib/commands/dbconsole.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/railties/lib/commands/dbconsole.rb b/railties/lib/commands/dbconsole.rb index b81997aa59..17acb7b68f 100644 --- a/railties/lib/commands/dbconsole.rb +++ b/railties/lib/commands/dbconsole.rb @@ -2,8 +2,13 @@ require 'erb' require 'yaml' require 'optparse' +include_password = false + OptionParser.new do |opt| - opt.banner = "Usage: dbconsole [environment]" + opt.banner = "Usage: dbconsole [options] [environment]" + opt.on("-p", "--include-password", "Automatically provide the database from database.yml") do |v| + include_password = true + end opt.parse!(ARGV) abort opt.to_s unless (0..1).include?(ARGV.size) end @@ -31,10 +36,13 @@ when "mysql" 'port' => '--port', 'socket' => '--socket', 'username' => '--user', - 'password' => '--password', 'encoding' => '--default-character-set' }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact + if config['password'] && include_password + args << "--password=#{config['password']}" + end + args << config['database'] exec(find_cmd('mysql5', 'mysql'), *args) @@ -43,7 +51,7 @@ when "postgresql" ENV['PGUSER'] = config["username"] if config["username"] ENV['PGHOST'] = config["host"] if config["host"] ENV['PGPORT'] = config["port"].to_s if config["port"] - ENV['PGPASSWORD'] = config["password"].to_s if config["password"] + ENV['PGPASSWORD'] = config["password"].to_s if config["password"] && include_password exec(find_cmd('psql'), config["database"]) when "sqlite" From 3a9775076fc4f99f8d7ad9a554a9ef8798c8fad7 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 31 May 2008 15:32:51 -0700 Subject: [PATCH 6/7] Removed suggestion for turning off partial updates. --- railties/environments/environment.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/railties/environments/environment.rb b/railties/environments/environment.rb index 468fa45ef6..a85ade371b 100644 --- a/railties/environments/environment.rb +++ b/railties/environments/environment.rb @@ -64,7 +64,4 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector - - # Make ActiveRecord only save the attributes that have changed since the record was loaded. - # config.active_record.partial_updates = true -end \ No newline at end of file +end From 7391f7728d96c2ec0113de57f3316c191043ad2c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 31 May 2008 15:31:04 -0700 Subject: [PATCH 7/7] Ruby 1.8.7 compat: work around broken DelegateClass#respond_to? --- actionpack/lib/action_controller/cgi_ext/cookie.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/actionpack/lib/action_controller/cgi_ext/cookie.rb b/actionpack/lib/action_controller/cgi_ext/cookie.rb index ef033fb4f3..009ddd1c64 100644 --- a/actionpack/lib/action_controller/cgi_ext/cookie.rb +++ b/actionpack/lib/action_controller/cgi_ext/cookie.rb @@ -78,6 +78,12 @@ class CGI #:nodoc: buf end + # FIXME: work around broken 1.8.7 DelegateClass#respond_to? + def respond_to?(method, include_private = false) + return true if super(method) + return __getobj__.respond_to?(method, include_private) + end + # Parses a raw cookie string into a hash of cookie-name => cookie-object # pairs. #