diff options
10 files changed, 79 insertions, 33 deletions
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index fd2970b8e2..36a0a20066 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -194,7 +194,7 @@ module ActionView #:nodoc: end def initialize(context = nil, assigns = {}, controller = nil, formats = nil) #:nodoc: - @_config = {} + @_config = ActiveSupport::InheritableOptions.new # Handle all these for backwards compatibility. # TODO Provide a new API for AV::Base and deprecate this one. diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb index f463675a2e..a75f1bc981 100644 --- a/actionpack/test/template/test_case_test.rb +++ b/actionpack/test/template/test_case_test.rb @@ -45,6 +45,10 @@ module ActionView assert_same _view, view end + test "retrieve non existing config values" do + assert_equal nil, ActionView::Base.new.config.something_odd + end + test "works without testing a helper module" do assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy')) end diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb index d7632b2ea9..30fc44b4c2 100644 --- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb @@ -7,24 +7,22 @@ module ActiveRecord::Associations::Builder def build reflection = super check_validity(reflection) - define_after_destroy_method + define_destroy_hook reflection end private - def define_after_destroy_method + def define_destroy_hook name = self.name - model.send(:class_eval, <<-eoruby, __FILE__, __LINE__ + 1) - def #{after_destroy_method_name} - association(#{name.to_sym.inspect}).delete_all - end - eoruby - model.after_destroy after_destroy_method_name - end - - def after_destroy_method_name - "has_and_belongs_to_many_after_destroy_for_#{name}" + model.send(:include, Module.new { + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def destroy_associations + association(#{name.to_sym.inspect}).delete_all + super + end + RUBY + }) end # TODO: These checks should probably be moved into the Reflection, and we should not be diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb index 6b010064d5..a1a921bcb4 100644 --- a/activerecord/lib/active_record/associations/singular_association.rb +++ b/activerecord/lib/active_record/associations/singular_association.rb @@ -18,11 +18,11 @@ module ActiveRecord end def create(attributes = {}, options = {}, &block) - build(attributes, options, &block).tap { |record| record.save } + create_record(attributes, options, &block) end def create!(attributes = {}, options = {}, &block) - build(attributes, options, &block).tap { |record| record.save! } + create_record(attributes, options, true, &block) end def build(attributes = {}, options = {}) @@ -50,6 +50,15 @@ module ActiveRecord def set_new_record(record) replace(record) end + + def create_record(attributes, options, raise_error = false) + record = build_record(attributes, options) + yield(record) if block_given? + saved = record.save + set_new_record(record) + raise RecordInvalid.new(record) if !saved && raise_error + record + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 29dd0a9ea3..a84f73c73f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -670,7 +670,7 @@ module ActiveRecord # If the schema is not specified as part of +name+ then it will only find tables within # the current schema search path (regardless of permissions to access tables in other schemas) def table_exists?(name) - schema, table = extract_schema_and_table(name.to_s) + schema, table = Utils.extract_schema_and_table(name.to_s) return false unless table binds = [[nil, table]] @@ -947,6 +947,23 @@ module ActiveRecord "DISTINCT #{columns}, #{order_columns * ', '}" end + module Utils + # Returns an array of <tt>[schema_name, table_name]</tt> extracted from +name+. + # +schema_name+ is nil if not specified in +name+. + # +schema_name+ and +table_name+ exclude surrounding quotes (regardless of whether provided in +name+) + # +name+ supports the range of schema/table references understood by PostgreSQL, for example: + # + # * <tt>table_name</tt> + # * <tt>"table.name"</tt> + # * <tt>schema_name.table_name</tt> + # * <tt>schema_name."table.name"</tt> + # * <tt>"schema.name"."table name"</tt> + def self.extract_schema_and_table(name) + table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse + [schema, table] + end + end + protected # Returns the version of the connected PostgreSQL server. def postgresql_version @@ -1085,21 +1102,6 @@ module ActiveRecord end end - # Returns an array of <tt>[schema_name, table_name]</tt> extracted from +name+. - # +schema_name+ is nil if not specified in +name+. - # +schema_name+ and +table_name+ exclude surrounding quotes (regardless of whether provided in +name+) - # +name+ supports the range of schema/table references understood by PostgreSQL, for example: - # - # * <tt>table_name</tt> - # * <tt>"table.name"</tt> - # * <tt>schema_name.table_name</tt> - # * <tt>schema_name."table.name"</tt> - # * <tt>"schema.name"."table name"</tt> - def extract_schema_and_table(name) - table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse - [schema, table] - end - def extract_table_ref_from_insert_sql(sql) sql[/into\s+([^\(]*).*values\s*\(/i] $1.strip if $1 diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index f425118f59..d9cd7987b0 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -79,6 +79,8 @@ module ActiveRecord # Deletes the record in the database and freezes this instance to reflect # that no changes should be made (since they can't be persisted). def destroy + destroy_associations + if persisted? IdentityMap.remove(self) if IdentityMap.enabled? pk = self.class.primary_key @@ -284,6 +286,11 @@ module ActiveRecord end private + + # A hook to be overriden by association modules. + def destroy_associations + end + def create_or_update raise ReadOnlyRecord if readonly? result = new_record? ? create : update diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 27e7b1a1c3..3a7f1badf0 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -229,8 +229,8 @@ class SchemaTest < ActiveRecord::TestCase %("schema"."table_name") => %w{schema table_name}, %("even spaces".table) => ['even spaces','table'], %(schema."table.name") => ['schema', 'table.name'] - }.each do |given,expect| - assert_equal expect, @connection.send(:extract_schema_and_table, given) + }.each do |given, expect| + assert_equal expect, ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::Utils.extract_schema_and_table(given) end end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 7338513b41..4190f6d76d 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -667,4 +667,18 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase firm = client.create_firm!{ |f| f.name = 'Agency Company' } assert_equal 'Agency Company', firm.name end + + def test_should_set_foreign_key_on_create_association + client = Client.create! :name => "fuu" + + firm = client.create_firm :name => "baa" + assert_equal firm.id, client.client_of + end + + def test_should_set_foreign_key_on_create_association! + client = Client.create! :name => "fuu" + + firm = client.create_firm! :name => "baa" + assert_equal firm.id, client.client_of + end end diff --git a/activerecord/test/cases/habtm_destroy_order_test.rb b/activerecord/test/cases/habtm_destroy_order_test.rb index f2b91d977e..2ce0de360e 100644 --- a/activerecord/test/cases/habtm_destroy_order_test.rb +++ b/activerecord/test/cases/habtm_destroy_order_test.rb @@ -16,6 +16,16 @@ class HabtmDestroyOrderTest < ActiveRecord::TestCase assert !sicp.destroyed? end + test 'should not raise error if have foreign key in the join table' do + student = Student.new(:name => "Ben Bitdiddle") + lesson = Lesson.new(:name => "SICP") + lesson.students << student + lesson.save! + assert_nothing_raised do + student.destroy + end + end + test "not destroying a student with lessons leaves student<=>lesson association intact" do # test a normal before_destroy doesn't destroy the habtm joins begin diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 8428383d09..e6cd274586 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -721,6 +721,8 @@ ActiveRecord::Schema.define do end execute "ALTER TABLE fk_test_has_fk ADD CONSTRAINT fk_name FOREIGN KEY (#{quote_column_name 'fk_id'}) REFERENCES #{quote_table_name 'fk_test_has_pk'} (#{quote_column_name 'id'})" + + execute "ALTER TABLE lessons_students ADD CONSTRAINT student_id_fk FOREIGN KEY (#{quote_column_name 'student_id'}) REFERENCES #{quote_table_name 'students'} (#{quote_column_name 'id'})" end end |