From 3ee4e009185173aab78f6503ee45e3ef4482874e Mon Sep 17 00:00:00 2001 From: lukeludwig Date: Fri, 16 Jan 2009 13:04:19 -0600 Subject: Cache columns for has_and_belongs_to_many associations This avoids repeatedly calling SHOW COLUMNS when the association is queried [#1738 state:committed] --- .../associations/has_and_belongs_to_many_association.rb | 12 +++++++++--- activerecord/lib/active_record/reflection.rb | 8 ++++++++ .../has_and_belongs_to_many_associations_test.rb | 11 +++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb index 3d689098b5..a5cc3bf091 100644 --- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb +++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb @@ -9,6 +9,14 @@ module ActiveRecord create_record(attributes) { |record| insert_record(record, true) } end + def columns + @reflection.columns(@reflection.options[:join_table], "#{@reflection.options[:join_table]} Columns") + end + + def reset_column_information + @reflection.reset_column_information + end + protected def construct_find_options!(options) options[:joins] = @join_sql @@ -32,8 +40,6 @@ module ActiveRecord if @reflection.options[:insert_sql] @owner.connection.insert(interpolate_sql(@reflection.options[:insert_sql], record)) else - columns = @owner.connection.columns(@reflection.options[:join_table], "#{@reflection.options[:join_table]} Columns") - attributes = columns.inject({}) do |attrs, column| case column.name.to_s when @reflection.primary_key_name.to_s @@ -103,7 +109,7 @@ module ActiveRecord # clause has been explicitly defined. Otherwise you can get broken records back, if, for example, the join column also has # an id column. This will then overwrite the id column of the records coming back. def finding_with_ambiguous_select?(select_clause) - !select_clause && @owner.connection.columns(@reflection.options[:join_table], "Join Table Columns").size != 2 + !select_clause && columns.size != 2 end private diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index dbff4f24d6..1937abdc83 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -198,6 +198,14 @@ module ActiveRecord end end + def columns(tbl_name, log_msg) + @columns ||= klass.connection.columns(tbl_name, log_msg) + end + + def reset_column_information + @columns = nil + end + def check_validity! end diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 2f08e09d43..ee03d5d944 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -775,4 +775,15 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end end end + + def test_caching_of_columns + david = Developer.find(1) + # clear cache possibly created by other tests + david.projects.reset_column_information + assert_queries(1) { david.projects.columns; david.projects.columns } + # and again to verify that reset_column_information clears the cache correctly + david.projects.reset_column_information + assert_queries(1) { david.projects.columns; david.projects.columns } + end + end -- cgit v1.2.3