From e94e53f9cd70bee69759661e9771da3fe0ee9554 Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Mon, 9 Jun 2008 11:30:48 -0400 Subject: fix eager loading with dynamic finders --- activerecord/lib/active_record/associations.rb | 2 +- .../active_record/associations/has_and_belongs_to_many_association.rb | 1 + activerecord/lib/active_record/associations/has_many_association.rb | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index a3d1bbbada..f32b217326 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1506,7 +1506,7 @@ module ActiveRecord end def order_tables(options) - order = options[:order] + order = [options[:order], scope(:find, :order) ].join(", ") return [] unless order && order.is_a?(String) order.scan(/([\.\w]+).?\./).flatten end 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 4fa8e9d0a8..918404eac6 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 @@ -87,6 +87,7 @@ module ActiveRecord :joins => @join_sql, :readonly => false, :order => @reflection.options[:order], + :include => @reflection.options[:include], :limit => @reflection.options[:limit] } } end diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index f584a97cbb..295beb2966 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -100,7 +100,7 @@ module ActiveRecord create_scoping = {} set_belongs_to_association_for(create_scoping) { - :find => { :conditions => @finder_sql, :readonly => false, :order => @reflection.options[:order], :limit => @reflection.options[:limit] }, + :find => { :conditions => @finder_sql, :readonly => false, :order => @reflection.options[:order], :limit => @reflection.options[:limit], :include => @reflection.options[:include]}, :create => create_scoping } end -- cgit v1.2.3 From 2e1b56c93745bf0513e449e95830edd390abfaf2 Mon Sep 17 00:00:00 2001 From: Diego Algorta Date: Sat, 21 Jun 2008 20:18:30 -0300 Subject: MySQL: rename_column preserves default values. [#466 state:resolved] --- .../lib/active_record/connection_adapters/mysql_adapter.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 93aafaaad1..8805c79c5b 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -450,8 +450,16 @@ module ActiveRecord end def rename_column(table_name, column_name, new_column_name) #:nodoc: + options = {} + if column = columns(table_name).find { |c| c.name == column_name.to_s } + options[:default] = column.default + else + raise ActiveRecordError, "No such column: #{table_name}.#{column_name}" + end current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] - execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" + rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" + add_column_options!(rename_column_sql, options) + execute(rename_column_sql) end # Maps logical Rails types to MySQL-specific data types. -- cgit v1.2.3 From 509374ebe2dba0dc2ea7e44d67a6f8d530d12fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Mon, 12 May 2008 17:58:03 +0300 Subject: Named bind variables can now be used with postgresql-style typecasts For example :conditions => ['stringcol::integer = :var', { :var => 10 }] will no longer raise an exception about ':integer' having a missing value. --- activerecord/lib/active_record/base.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 8fca34e524..8d5ea271a7 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2055,9 +2055,10 @@ module ActiveRecord #:nodoc: end def replace_named_bind_variables(statement, bind_vars) #:nodoc: - statement.gsub(/:([a-zA-Z]\w*)/) do - match = $1.to_sym - if bind_vars.include?(match) + statement.gsub(/(:?):([a-zA-Z]\w*)/) do + if $1 == ':' # skip postgresql casts + $& # return the whole match + elsif bind_vars.include?(match = $2.to_sym) quote_bound_value(bind_vars[match]) else raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}" -- cgit v1.2.3 From 1afae84ab2656cd58a861ab4a4b1745d80088d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Fri, 13 Jun 2008 23:39:10 +0300 Subject: Fixed that scopes defined with a string name could not be composed --- activerecord/lib/active_record/named_scope.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index b0c8a8b815..eac61e9e43 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -82,6 +82,7 @@ module ActiveRecord # expected_options = { :conditions => { :colored => 'red' } } # 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 -- cgit v1.2.3 From f94600bdaf7d73971ad9a53148b0844c2efb901d Mon Sep 17 00:00:00 2001 From: Michael Raidel Date: Fri, 13 Jun 2008 16:14:07 +0200 Subject: ActiveRecord::Migrator#run records version-state after migrating. [#369 state:resolved] --- activerecord/lib/active_record/migration.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index b47b01e99a..e095b3c766 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -399,7 +399,10 @@ module ActiveRecord def run target = migrations.detect { |m| m.version == @target_version } raise UnknownMigrationVersionError.new(@target_version) if target.nil? - target.migrate(@direction) + unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i)) + target.migrate(@direction) + record_version_state_after_migrating(target.version) + end end def migrate -- cgit v1.2.3 From 3532eaf92a96b87fb422625142ff0efa1cac17ab Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 16 Jun 2008 17:45:50 -0500 Subject: Only use DROP ... IF EXISTS for PostgreSQL 8.2 or later. [#400 state:resolved] --- .../active_record/connection_adapters/postgresql_adapter.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 294f4c1929..d0585d52ac 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -553,7 +553,15 @@ module ActiveRecord # Example: # drop_database 'matt_development' def drop_database(name) #:nodoc: - execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}" + if postgresql_version >= 80200 + execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}" + else + begin + execute "DROP DATABASE #{quote_table_name(name)}" + rescue ActiveRecord::StatementInvalid + @logger.warn "#{name} database doesn't exist." if @logger + end + end end -- cgit v1.2.3 From a210f503619dd27dc9575bcae1df596fd2387563 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 22 Jun 2008 18:50:19 -0700 Subject: Oops, already had a postgresql_version method! --- .../lib/active_record/connection_adapters/postgresql_adapter.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index d0585d52ac..5641b5cca5 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -324,12 +324,7 @@ module ActiveRecord end def supports_insert_with_returning? - unless defined? @supports_insert_with_returning - @supports_insert_with_returning = - @connection.respond_to?(:server_version) && - @connection.server_version >= 80200 - end - @supports_insert_with_returning + postgresql_version >= 80200 end # Returns the configured supported identifier length supported by PostgreSQL, -- cgit v1.2.3 From 0fd3e4cd2b2b1b31304a922dc65284d5363f78b6 Mon Sep 17 00:00:00 2001 From: Mark Catley Date: Sat, 21 Jun 2008 23:41:30 +1200 Subject: Fix column collision with named_scope and :joins. [#46 state:resolved] --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 8d5ea271a7..e6ab87e8fc 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1479,7 +1479,7 @@ module ActiveRecord #:nodoc: def construct_finder_sql(options) scope = scope(:find) - sql = "SELECT #{options[:select] || (scope && scope[:select]) || (options[:joins] && quoted_table_name + '.*') || '*'} " + sql = "SELECT #{options[:select] || (scope && scope[:select]) || ((options[:joins] || (scope && scope[:joins])) && quoted_table_name + '.*') || '*'} " sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} " add_joins!(sql, options, scope) -- cgit v1.2.3 From 3610997ba32128921115bedb89c322a7bcbe161a Mon Sep 17 00:00:00 2001 From: Daniel Morrison Date: Sun, 15 Jun 2008 16:25:59 -0400 Subject: Partial updates don't update lock_version if nothing changed. [#426 state:resolved] --- activerecord/lib/active_record/locking/optimistic.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index c66034d18b..ff9899d032 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -68,6 +68,7 @@ module ActiveRecord def update_with_lock(attribute_names = @attributes.keys) #:nodoc: return update_without_lock(attribute_names) unless locking_enabled? + return 0 if attribute_names.empty? lock_col = self.class.locking_column previous_value = send(lock_col).to_i -- cgit v1.2.3 From baddea95e183b3bef290ec433f917ee8cd806934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Sun, 15 Jun 2008 05:55:56 +0300 Subject: Always treat integer :limit as byte length. [#420 state:resolved] --- .../connection_adapters/mysql_adapter.rb | 21 +++++++++++---------- .../connection_adapters/postgresql_adapter.rb | 16 ++++++++++------ 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 8805c79c5b..ed1f08ac4f 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -99,7 +99,8 @@ module ActiveRecord end def extract_limit(sql_type) - if sql_type =~ /blob|text/i + case sql_type + when /blob|text/i case sql_type when /tiny/i 255 @@ -110,6 +111,10 @@ module ActiveRecord else super # we could return 65535 here, but we leave it undecorated by default end + when /^int/i; 4 + when /^bigint/i; 8 + when /^smallint/i; 2 + when /^mediumint/i; 3 else super end @@ -168,7 +173,7 @@ module ActiveRecord :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze, :string => { :name => "varchar", :limit => 255 }, :text => { :name => "text" }, - :integer => { :name => "int"}, + :integer => { :name => "int", :limit => 4 }, :float => { :name => "float" }, :decimal => { :name => "decimal" }, :datetime => { :name => "datetime" }, @@ -467,14 +472,10 @@ module ActiveRecord return super unless type.to_s == 'integer' case limit - when 0..3 - "smallint(#{limit})" - when 4..8 - "int(#{limit})" - when 9..20 - "bigint(#{limit})" - else - 'int(11)' + when 1..2; 'smallint' + when 3; 'mediumint' + when 4, nil; 'int(11)' + when 5..8; 'bigint' 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 5641b5cca5..361d177967 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -47,6 +47,12 @@ module ActiveRecord end private + def extract_limit(sql_type) + return 8 if sql_type =~ /^bigint/i + return 2 if sql_type =~ /^smallint/i + super + end + # Extracts the scale from PostgreSQL-specific data types. def extract_scale(sql_type) # Money type has a fixed scale of 2. @@ -785,12 +791,10 @@ module ActiveRecord def type_to_sql(type, limit = nil, precision = nil, scale = nil) return super unless type.to_s == 'integer' - if limit.nil? || limit == 4 - 'integer' - elsif limit < 4 - 'smallint' - else - 'bigint' + case limit + when 1..2; 'smallint' + when 3..4, nil; 'integer' + when 5..8; 'bigint' end end -- cgit v1.2.3 From 290e1e2fc53d80165cc876491ec0cbe18be376cf Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 23 Jun 2008 18:16:03 -0700 Subject: Treat any limit > 4 as bigint --- .../lib/active_record/connection_adapters/mysql_adapter.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index ed1f08ac4f..dd54950790 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -111,10 +111,11 @@ module ActiveRecord else super # we could return 65535 here, but we leave it undecorated by default end - when /^int/i; 4 when /^bigint/i; 8 - when /^smallint/i; 2 + when /^int/i; 4 when /^mediumint/i; 3 + when /^smallint/i; 2 + when /^tinyint/i; 1 else super end @@ -472,10 +473,11 @@ module ActiveRecord return super unless type.to_s == 'integer' case limit - when 1..2; 'smallint' - when 3; 'mediumint' - when 4, nil; 'int(11)' - when 5..8; 'bigint' + when 1; 'tinyint' + when 2; 'smallint' + when 3; 'mediumint' + when 4, nil; 'int(11)' + else; 'bigint' end end -- cgit v1.2.3 From 071fe79279e89e650acce6613f13027527d01650 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 24 Jun 2008 22:07:09 -0700 Subject: Include cache key in ModelName --- activerecord/lib/active_record/base.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index e6ab87e8fc..021aaf4ca1 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2170,11 +2170,11 @@ module ActiveRecord #:nodoc: def cache_key case when new_record? - "#{self.class.name.tableize}/new" - when self[:updated_at] - "#{self.class.name.tableize}/#{id}-#{updated_at.to_s(:number)}" + "#{self.class.model_name.cache_key}/new" + when timestamp = self[:updated_at] + "#{self.class.model_name.cache_key}/#{id}-#{timestamp.to_s(:number)}" else - "#{self.class.name.tableize}/#{id}" + "#{self.class.model_name.cache_key}/#{id}" end end -- cgit v1.2.3 From c39726057714970f8e39d27bd0cb49fa4d6bc383 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 25 Jun 2008 00:42:38 -0700 Subject: Performance: minor Column#text? and #number? speedups --- .../active_record/connection_adapters/abstract/schema_definitions.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index f968b9b173..02e444d4e8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -30,11 +30,11 @@ module ActiveRecord end def text? - [:string, :text].include? type + type == :string || type == :text end def number? - [:float, :integer, :decimal].include? type + type == :integer || type == :float || type == :decimal end # Returns the Ruby class that corresponds to the abstract data type. -- cgit v1.2.3 From 0b12da44aa35b643b17ab1b61634ff952993e357 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Wed, 4 Jun 2008 13:58:58 -0700 Subject: Extract owner_quoted_id so it can be overridden. [#292 state:committed] --- activerecord/lib/active_record/associations/association_proxy.rb | 4 ++++ .../associations/has_and_belongs_to_many_association.rb | 6 +++--- activerecord/lib/active_record/associations/has_many_association.rb | 6 +++--- .../lib/active_record/associations/has_many_through_association.rb | 6 +++--- activerecord/lib/active_record/associations/has_one_association.rb | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 11c64243a2..b4908eec9d 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -219,6 +219,10 @@ module ActiveRecord def flatten_deeper(array) array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten end + + def owner_quoted_id + @owner.quoted_id + end end end end 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 918404eac6..d516d54151 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 @@ -37,7 +37,7 @@ module ActiveRecord attributes = columns.inject({}) do |attrs, column| case column.name.to_s when @reflection.primary_key_name.to_s - attrs[column.name] = @owner.quoted_id + attrs[column.name] = owner_quoted_id when @reflection.association_foreign_key.to_s attrs[column.name] = record.quoted_id else @@ -64,7 +64,7 @@ module ActiveRecord records.each { |record| @owner.connection.delete(interpolate_sql(sql, record)) } else ids = quoted_record_ids(records) - sql = "DELETE FROM #{@owner.connection.quote_table_name @reflection.options[:join_table]} WHERE #{@reflection.primary_key_name} = #{@owner.quoted_id} AND #{@reflection.association_foreign_key} IN (#{ids})" + sql = "DELETE FROM #{@owner.connection.quote_table_name @reflection.options[:join_table]} WHERE #{@reflection.primary_key_name} = #{owner_quoted_id} AND #{@reflection.association_foreign_key} IN (#{ids})" @owner.connection.delete(sql) end end @@ -75,7 +75,7 @@ module ActiveRecord if @reflection.options[:finder_sql] @finder_sql = @reflection.options[:finder_sql] else - @finder_sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{@owner.quoted_id} " + @finder_sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{owner_quoted_id} " @finder_sql << " AND (#{conditions})" if conditions end diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 295beb2966..37440aa84d 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -60,7 +60,7 @@ module ActiveRecord ids = quoted_record_ids(records) @reflection.klass.update_all( "#{@reflection.primary_key_name} = NULL", - "#{@reflection.primary_key_name} = #{@owner.quoted_id} AND #{@reflection.klass.primary_key} IN (#{ids})" + "#{@reflection.primary_key_name} = #{owner_quoted_id} AND #{@reflection.klass.primary_key} IN (#{ids})" ) end end @@ -76,12 +76,12 @@ module ActiveRecord when @reflection.options[:as] @finder_sql = - "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " + + "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " + "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}" @finder_sql << " AND (#{conditions})" if conditions else - @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{@owner.quoted_id}" + @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}" @finder_sql << " AND (#{conditions})" if conditions end diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 52ced36d16..e1bfff5923 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -107,12 +107,12 @@ module ActiveRecord # Associate attributes pointing to owner, quoted. def construct_quoted_owner_attributes(reflection) if as = reflection.options[:as] - { "#{as}_id" => @owner.quoted_id, + { "#{as}_id" => owner_quoted_id, "#{as}_type" => reflection.klass.quote_value( @owner.class.base_class.name.to_s, reflection.klass.columns_hash["#{as}_type"]) } else - { reflection.primary_key_name => @owner.quoted_id } + { reflection.primary_key_name => owner_quoted_id } end end @@ -183,7 +183,7 @@ module ActiveRecord when @reflection.options[:finder_sql] @finder_sql = interpolate_sql(@reflection.options[:finder_sql]) - @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{@owner.quoted_id}" + @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}" @finder_sql << " AND (#{conditions})" if conditions else @finder_sql = construct_conditions diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index c2b3503e0d..25a268e95c 100755 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -63,10 +63,10 @@ module ActiveRecord case when @reflection.options[:as] @finder_sql = - "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " + + "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " + "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}" else - @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{@owner.quoted_id}" + @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}" end @finder_sql << " AND (#{conditions})" if conditions end -- cgit v1.2.3 From 5ca7d01ecaa5e97f724169c0177027d0d85066da Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 27 Jun 2008 02:47:30 +0100 Subject: Cache sanitized conditions in reflection object for associations --- activerecord/lib/active_record/associations/association_proxy.rb | 2 +- activerecord/lib/active_record/reflection.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index b4908eec9d..77fc827e11 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -85,7 +85,7 @@ module ActiveRecord end def conditions - @conditions ||= interpolate_sql(sanitize_sql(@reflection.options[:conditions])) if @reflection.options[:conditions] + @conditions ||= interpolate_sql(@reflection.sanitized_conditions) if @reflection.sanitized_conditions end alias :sql_conditions :conditions diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 8614ef8751..3f74c03714 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -112,6 +112,10 @@ module ActiveRecord name == other_aggregation.name && other_aggregation.options && active_record == other_aggregation.active_record end + def sanitized_conditions #:nodoc: + @sanitized_conditions ||= klass.send(:sanitize_sql, options[:conditions]) if options[:conditions] + end + private def derive_class_name name.to_s.camelize -- cgit v1.2.3 From b2b761166d28c1aba9165da76fba28027171fd2d Mon Sep 17 00:00:00 2001 From: Jan De Poorter Date: Wed, 25 Jun 2008 12:42:33 +0200 Subject: Make sure associated has_many/habtm objects get saved even when :validate => false is used. [#486 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/associations.rb | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index db99b7165d..4b7154043f 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -711,7 +711,8 @@ module ActiveRecord configure_dependency_for_has_many(reflection) - add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false + add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false + add_multiple_associated_save_callbacks(reflection.name) add_association_callbacks(reflection.name, reflection.options) if options[:through] @@ -801,7 +802,7 @@ module ActiveRecord end after_save method_name - add_single_associated_save_callbacks(reflection.name) if options[:validate] == true + add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true association_accessor_methods(reflection, HasOneAssociation) association_constructor_method(:build, reflection, HasOneAssociation) association_constructor_method(:create, reflection, HasOneAssociation) @@ -940,7 +941,7 @@ module ActiveRecord ) end - add_single_associated_save_callbacks(reflection.name) if options[:validate] == true + add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true configure_dependency_for_belongs_to(reflection) end @@ -1043,7 +1044,8 @@ module ActiveRecord def has_and_belongs_to_many(association_id, options = {}, &extension) reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension) - add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false + add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false + add_multiple_associated_save_callbacks(reflection.name) collection_accessor_methods(reflection, HasAndBelongsToManyAssociation) # Don't use a before_destroy callback since users' before_destroy @@ -1163,7 +1165,7 @@ module ActiveRecord end end - def add_single_associated_save_callbacks(association_name) + def add_single_associated_validation_callbacks(association_name) method_name = "validate_associated_records_for_#{association_name}".to_sym define_method(method_name) do association = instance_variable_get("@#{association_name}") @@ -1175,7 +1177,7 @@ module ActiveRecord validate method_name end - def add_multiple_associated_save_callbacks(association_name) + def add_multiple_associated_validation_callbacks(association_name) method_name = "validate_associated_records_for_#{association_name}".to_sym ivar = "@#{association_name}" @@ -1196,6 +1198,10 @@ module ActiveRecord end validate method_name + end + + def add_multiple_associated_save_callbacks(association_name) + ivar = "@#{association_name}" method_name = "before_save_associated_records_for_#{association_name}".to_sym define_method(method_name) do @@ -1217,7 +1223,6 @@ module ActiveRecord else [] end - records_to_save.each { |record| association.send(:insert_record, record) } unless records_to_save.blank? # reconstruct the SQL queries now that we know the owner's id -- cgit v1.2.3 From 4498aad4acda002b8f213f13c4acd52cba04d224 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 27 Jun 2008 01:06:33 -0700 Subject: MySQL: treat integer with :limit => 11 as a display width, not byte size, for backward-compatibility. --- .../connection_adapters/abstract/schema_definitions.rb | 3 +-- .../lib/active_record/connection_adapters/mysql_adapter.rb | 11 ++++++----- .../active_record/connection_adapters/postgresql_adapter.rb | 12 ++++++++---- 3 files changed, 15 insertions(+), 11 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 02e444d4e8..2c03de0f17 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -304,8 +304,7 @@ module ActiveRecord # # Available options are (none of these exists by default): # * :limit - - # Requests a maximum column length (:string, :text, - # :binary or :integer columns only) + # Requests a maximum column length. This is number of characters for :string and :text columns and number of bytes for :binary and :integer columns. # * :default - # The column's default value. Use nil for NULL. # * :null - diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index dd54950790..c5962764f5 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -473,11 +473,12 @@ module ActiveRecord return super unless type.to_s == 'integer' case limit - when 1; 'tinyint' - when 2; 'smallint' - when 3; 'mediumint' - when 4, nil; 'int(11)' - else; 'bigint' + when 1; 'tinyint' + when 2; 'smallint' + when 3; 'mediumint' + when nil, 4, 11; 'int(11)' # compatibility with MySQL default + when 5..8; 'bigint' + else raise(ActiveRecordError, "No integer type has byte size #{limit}") 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 361d177967..2e2d50ccf4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -48,9 +48,12 @@ module ActiveRecord private def extract_limit(sql_type) - return 8 if sql_type =~ /^bigint/i - return 2 if sql_type =~ /^smallint/i - super + case sql_type + when /^integer/i; 4 + when /^bigint/i; 8 + when /^smallint/i; 2 + else super + end end # Extracts the scale from PostgreSQL-specific data types. @@ -795,9 +798,10 @@ module ActiveRecord when 1..2; 'smallint' when 3..4, nil; 'integer' when 5..8; 'bigint' + else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.") end end - + # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. # # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and -- cgit v1.2.3 From cd994eff9a343df376bfaec59de5b24a2ab51256 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 28 Jun 2008 01:27:25 +0100 Subject: Allow conditions on multiple tables to be specified using hash. Examples: User.all :joins => :items, :conditions => { :age => 10, :items => { :color => 'black' } } Item.first :conditions => { :items => { :color => 'red' } } Note : Hash key in :conditions is referring to the actual table name or the alias defined in query. --- activerecord/lib/active_record/base.rb | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 021aaf4ca1..962c2b36d9 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1999,24 +1999,28 @@ module ActiveRecord #:nodoc: # # => "age BETWEEN 13 AND 18" # { 'other_records.id' => 7 } # # => "`other_records`.`id` = 7" + # { :other_records => { :id => 7 } } + # # => "`other_records`.`id` = 7" # And for value objects on a composed_of relationship: # { :address => Address.new("123 abc st.", "chicago") } # # => "address_street='123 abc st.' and address_city='chicago'" - def sanitize_sql_hash_for_conditions(attrs) + def sanitize_sql_hash_for_conditions(attrs, table_name = quoted_table_name) attrs = expand_hash_conditions_for_aggregates(attrs) conditions = attrs.map do |attr, value| - attr = attr.to_s + unless value.is_a?(Hash) + attr = attr.to_s + + # Extract table name from qualified attribute names. + if attr.include?('.') + table_name, attr = attr.split('.', 2) + table_name = connection.quote_table_name(table_name) + end - # Extract table name from qualified attribute names. - if attr.include?('.') - table_name, attr = attr.split('.', 2) - table_name = connection.quote_table_name(table_name) + "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}" else - table_name = quoted_table_name + sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s)) end - - "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}" end.join(' AND ') replace_bind_variables(conditions, expand_range_bind_variables(attrs.values)) @@ -2070,6 +2074,8 @@ module ActiveRecord #:nodoc: expanded = [] bind_vars.each do |var| + next if var.is_a?(Hash) + if var.is_a?(Range) expanded << var.first expanded << var.last -- cgit v1.2.3 From 1415df8f49a19d469b9e2c15785db32eb312c000 Mon Sep 17 00:00:00 2001 From: Tim Chater Date: Tue, 17 Jun 2008 13:54:03 +0100 Subject: Dirty: recognize when an integer changes from zero to blank. [#433 state:resolved] --- activerecord/lib/active_record/dirty.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index b32e17e990..a7d767486c 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -142,9 +142,11 @@ module ActiveRecord def field_changed?(attr, old, value) if column = column_for_attribute(attr) - if column.type == :integer && column.null && old.nil? + if column.type == :integer && column.null && (old.nil? || old == 0) # For nullable integer columns, NULL gets stored in database for blank (i.e. '') values. # Hence we don't record it as a change if the value changes from nil to ''. + # If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll + # be typecast back to 0 (''.to_i => 0) value = nil if value.blank? else value = column.type_cast(value) -- cgit v1.2.3 From 474d42538269a141687c7c66bef6575b4682b15d Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 2 Jul 2008 03:17:33 +0100 Subject: Ensure AssociationCollection#size considers all unsaved record. [#305 state:resolved] [sds] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/associations/association_collection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 52d2a9864e..bbd8af7e76 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -187,7 +187,7 @@ module ActiveRecord if @owner.new_record? || (loaded? && !@reflection.options[:uniq]) @target.size elsif !loaded? && !@reflection.options[:uniq] && @target.is_a?(Array) - unsaved_records = Array(@target.detect { |r| r.new_record? }) + unsaved_records = @target.select { |r| r.new_record? } unsaved_records.size + count_records else count_records -- cgit v1.2.3 From d20e8dd2207a848e2712c19ad38d6abb6f98ca07 Mon Sep 17 00:00:00 2001 From: Lucas Carlson Date: Wed, 2 Jul 2008 16:54:31 -0700 Subject: Changing order of equality because comparing certain objects with false raises an error. >> require 'md5' => true >> MD5.new("Asds") == false TypeError: can't convert false into String from (irb):2:in `==' from (irb):2 >> false == MD5.new("Asds") => false --- activerecord/lib/active_record/callbacks.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 4edc209c65..1e385fb128 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -262,7 +262,7 @@ module ActiveRecord def valid_with_callbacks? #:nodoc: return false if callback(:before_validation) == false if new_record? then result = callback(:before_validation_on_create) else result = callback(:before_validation_on_update) end - return false if result == false + return false if false == result result = valid_without_callbacks? @@ -293,7 +293,7 @@ module ActiveRecord private def callback(method) - result = run_callbacks(method) { |result, object| result == false } + result = run_callbacks(method) { |result, object| false == result } if result != false && respond_to_without_attributes?(method) result = send(method) -- cgit v1.2.3 From 87fbcaa6229e9073095fb8d77c7a536c9466fbce Mon Sep 17 00:00:00 2001 From: David Lowenfels Date: Sat, 28 Jun 2008 17:41:12 -0700 Subject: Add :tokenizer option to validates_length_of. [#507 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/validations.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index c4e370d017..741649f764 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -479,8 +479,9 @@ module ActiveRecord # 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 %d character" - # validates_length_of :smurf_leader, :is=>4, :message=>"papa is spelled with %d characters... don't play me." + # validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least %d character" + # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with %d characters... don't play me." + # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least %d words."), :tokenizer => lambda {|str| str.scan(/\w+/) } # end # # Configuration options: @@ -491,7 +492,6 @@ module ActiveRecord # * :in - A synonym(or alias) for :within. # * :allow_nil - Attribute may be +nil+; skip validation. # * :allow_blank - Attribute may be blank; skip validation. - # # * :too_long - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)"). # * :too_short - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)"). # * :wrong_length - The error message if using the :is method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)"). @@ -503,12 +503,16 @@ module ActiveRecord # * :unless - Specifies a method, proc or string to call to determine if the validation should # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. + # * :tokenizer - Specifies how to split up the attribute string. (e.g. :tokenizer => lambda {|str| str.scan(/\w+/)} to + # count words as in above example.) + # Defaults to lambda{ |value| value.split(//) } which counts individual characters. def validates_length_of(*attrs) # Merge given options with defaults. options = { :too_long => ActiveRecord::Errors.default_error_messages[:too_long], :too_short => ActiveRecord::Errors.default_error_messages[:too_short], - :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length] + :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length], + :tokenizer => lambda {|value| value.split(//)} }.merge(DEFAULT_VALIDATION_OPTIONS) options.update(attrs.extract_options!.symbolize_keys) @@ -535,7 +539,7 @@ module ActiveRecord too_long = options[:too_long] % option_value.end validates_each(attrs, options) do |record, attr, value| - value = value.split(//) if value.kind_of?(String) + value = options[:tokenizer].call(value) if value.kind_of?(String) if value.nil? or value.size < option_value.begin record.errors.add(attr, too_short) elsif value.size > option_value.end @@ -552,7 +556,7 @@ module ActiveRecord message = (options[:message] || options[message_options[option]]) % option_value validates_each(attrs, options) do |record, attr, value| - value = value.split(//) if value.kind_of?(String) + value = options[:tokenizer].call(value) if value.kind_of?(String) record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] end end -- cgit v1.2.3 From 3351d2997017465047b2c3dc63dc31e2362368af Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Sat, 31 May 2008 23:19:40 -0700 Subject: Add has_many :primary_key option to allow setting the primary key on a has many association Signed-off-by: Michael Koziarski --- activerecord/lib/active_record/associations.rb | 5 +++-- .../lib/active_record/associations/has_many_association.rb | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 4b7154043f..c5e8207f14 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -663,6 +663,7 @@ module ActiveRecord # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+ association will use "person_id" # as the default :foreign_key. + # * :primary_key - Specify the method that returns the primary key used for the association. By default this is +id+. # * :dependent - If set to :destroy all the associated objects are destroyed # alongside this object by calling their +destroy+ method. If set to :delete_all all associated # objects are deleted *without* calling their +destroy+ method. If set to :nullify all associated @@ -678,7 +679,7 @@ module ActiveRecord # * :limit - An integer determining the limit on the number of rows that should be returned. # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. # * :select - By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join - # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will rise an error. + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :as - Specifies a polymorphic interface (See belongs_to). # * :through - Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key # are ignored, as the association uses the source reflection. You can only use a :through query through a belongs_to @@ -1347,7 +1348,7 @@ module ActiveRecord def create_has_many_reflection(association_id, options, &extension) options.assert_valid_keys( - :class_name, :table_name, :foreign_key, + :class_name, :table_name, :foreign_key, :primary_key, :dependent, :select, :conditions, :include, :order, :group, :limit, :offset, :as, :through, :source, :source_type, diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 37440aa84d..cb58f0be15 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -19,6 +19,14 @@ module ActiveRecord end protected + def owner_quoted_id + if @reflection.options[:primary_key] + quote_value(@owner.send(@reflection.options[:primary_key])) + else + @owner.quoted_id + end + end + def count_records count = if has_cached_counter? @owner.send(:read_attribute, cached_counter_attribute_name) -- cgit v1.2.3 From afa0c7f728a8896c9ee9d932033e08a4c99dfd50 Mon Sep 17 00:00:00 2001 From: Brad Greenlee Date: Mon, 2 Jun 2008 22:04:46 -0700 Subject: Add support for :primary_key option to has_one as well as has_many so that a key other than the default primary key can be used for the association Signed-off-by: Michael Koziarski --- activerecord/lib/active_record/associations.rb | 3 ++- .../lib/active_record/associations/has_one_association.rb | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index c5e8207f14..856d872bce 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -759,6 +759,7 @@ module ActiveRecord # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association will use "person_id" # as the default :foreign_key. + # * :primary_key - Specify the method that returns the primary key used for the association. By default this is +id+. # * :include - Specify second-order associations that should be eager loaded when this object is loaded. # * :as - Specifies a polymorphic interface (See belongs_to). # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join @@ -1366,7 +1367,7 @@ module ActiveRecord def create_has_one_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate, :primary_key ) create_reflection(:has_one, association_id, options, self) diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 25a268e95c..fdc0fa52c9 100755 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -47,7 +47,16 @@ module ActiveRecord return (obj.nil? ? nil : self) end end - + + protected + def owner_quoted_id + if @reflection.options[:primary_key] + quote_value(@owner.send(@reflection.options[:primary_key])) + else + @owner.quoted_id + end + end + private def find_target @reflection.klass.find(:first, -- cgit v1.2.3 From 124d1016fa212c008e33853912493fa9ac15d086 Mon Sep 17 00:00:00 2001 From: Chris Cherry Date: Thu, 5 Jun 2008 23:26:35 -0700 Subject: Allow Infinity (1.0/0.0) to pass validates_numericality_of. [#354 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/validations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 741649f764..1035308aa5 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -854,7 +854,7 @@ module ActiveRecord raw_value = raw_value.to_i else begin - raw_value = Kernel.Float(raw_value.to_s) + raw_value = Kernel.Float(raw_value) rescue ArgumentError, TypeError record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number]) next -- cgit v1.2.3 From 84af99e78dbf65b7faa92313acf8457cb0c2b510 Mon Sep 17 00:00:00 2001 From: Daniel Guettler Date: Wed, 9 Jul 2008 14:08:04 +0100 Subject: Ensure NamedScope#build/create/create!/new works as expected when named scope has hash conditions. [Daniel Guettler, Pratik Naik] [#419 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/named_scope.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index eac61e9e43..080e3d0f5e 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -150,7 +150,8 @@ module ActiveRecord if scopes.include?(method) scopes[method].call(self, *args) else - with_scope :find => proxy_options do + with_scope :find => proxy_options, :create => proxy_options[:conditions].is_a?(Hash) ? proxy_options[:conditions] : {} do + method = :new if method == :build proxy_scope.send(method, *args, &block) end end -- cgit v1.2.3 From 11252e35b1756b025d8778c151f9f9a24057d1b1 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 8 Jul 2008 17:32:06 -0700 Subject: Boolean type casting creates fewer objects --- .../active_record/connection_adapters/abstract/schema_definitions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 2c03de0f17..d4c8a80448 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -138,7 +138,7 @@ module ActiveRecord if value == true || value == false value else - %w(true t 1).include?(value.to_s.downcase) + !(value.to_s !~ /\A(?:1|t|true)\Z/i) end end -- cgit v1.2.3 From ce4a1bb8538bd7cc5ee3cbf1156dc587482a7839 Mon Sep 17 00:00:00 2001 From: Cheah Chu Yeow Date: Thu, 26 Jun 2008 10:21:53 +0800 Subject: Remove some Symbol#to_proc usage in runtime code. [#484 state:resolved] --- activerecord/lib/active_record/associations.rb | 4 ++-- activerecord/lib/active_record/associations/association_collection.rb | 2 +- activerecord/lib/active_record/associations/has_many_association.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 856d872bce..6931744058 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1145,7 +1145,7 @@ module ActiveRecord end define_method("#{reflection.name.to_s.singularize}_ids") do - send(reflection.name).map(&:id) + send(reflection.name).map { |record| record.id } end end @@ -1490,7 +1490,7 @@ module ActiveRecord sql << " FROM #{connection.quote_table_name table_name} " if is_distinct - sql << distinct_join_associations.collect(&:association_join).join + sql << distinct_join_associations.collect { |assoc| assoc.association_join }.join add_joins!(sql, options, scope) end diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index bbd8af7e76..eb39714909 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -14,7 +14,7 @@ module ActiveRecord # If using a custom finder_sql, scan the entire collection. if @reflection.options[:finder_sql] expects_array = args.first.kind_of?(Array) - ids = args.flatten.compact.uniq.map(&:to_i) + ids = args.flatten.compact.uniq.map { |arg| arg.to_i } if ids.size == 1 id = ids.first diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index cb58f0be15..e6fa15c173 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -61,9 +61,9 @@ module ActiveRecord def delete_records(records) case @reflection.options[:dependent] when :destroy - records.each(&:destroy) + records.each { |r| r.destroy } when :delete_all - @reflection.klass.delete(records.map(&:id)) + @reflection.klass.delete(records.map { |record| record.id }) else ids = quoted_record_ids(records) @reflection.klass.update_all( -- cgit v1.2.3 From 5e2e1ed9ffc481a91596d8c3fd9a68d7977e75ca Mon Sep 17 00:00:00 2001 From: Micah Wedemeyer Date: Fri, 11 Jul 2008 23:50:55 +0100 Subject: Ensure MysqlAdapter allows SSL connection when only sslca is supplied. [#253 state:resolved] Signed-off-by: Pratik Naik --- .../lib/active_record/connection_adapters/mysql_adapter.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index c5962764f5..4b13ac8be0 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -69,7 +69,7 @@ module ActiveRecord MysqlCompat.define_all_hashes_method! mysql = Mysql.init - mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey] + mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslca] || config[:sslkey] ConnectionAdapters::MysqlAdapter.new(mysql, logger, [host, username, password, database, port, socket], config) end @@ -145,6 +145,7 @@ module ActiveRecord # * :password - Defaults to nothing. # * :database - The name of the database. No default, must be provided. # * :encoding - (Optional) Sets the client encoding by executing "SET NAMES " after connection. + # * :sslca - Necessary to use MySQL with an SSL connection. # * :sslkey - Necessary to use MySQL with an SSL connection. # * :sslcert - Necessary to use MySQL with an SSL connection. # * :sslcapath - Necessary to use MySQL with an SSL connection. @@ -507,7 +508,9 @@ module ActiveRecord @connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil end - @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) if @config[:sslkey] + if @config[:sslca] || @config[:sslkey] + @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) + end @connection.real_connect(*@connection_options) -- cgit v1.2.3 From d72c66532f959846cdc2d7fb1dc1ef6ba87bdcb1 Mon Sep 17 00:00:00 2001 From: Rhett Sutphin Date: Mon, 14 Jul 2008 02:01:52 +0100 Subject: Make fixture accessors work when fixture name is not same as the table name. [#124 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/fixtures.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index e19614e31f..17fb9355c4 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -541,10 +541,11 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) label.to_s.hash.abs end - attr_reader :table_name + attr_reader :table_name, :name def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE) @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter + @name = table_name # preserve fixture base name @class_name = class_name || (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize) @table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}" @@ -963,9 +964,9 @@ module Test #:nodoc: fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names) unless fixtures.nil? if fixtures.instance_of?(Fixtures) - @loaded_fixtures[fixtures.table_name] = fixtures + @loaded_fixtures[fixtures.name] = fixtures else - fixtures.each { |f| @loaded_fixtures[f.table_name] = f } + fixtures.each { |f| @loaded_fixtures[f.name] = f } end end end -- cgit v1.2.3 From c6f397c5cecf183680c191dd2128c0a96c5b9399 Mon Sep 17 00:00:00 2001 From: Jason Dew Date: Fri, 27 Jun 2008 12:25:26 -0400 Subject: Add block syntax to HasManyAssociation#build. [#502 state:resolve] Signed-off-by: Pratik Naik --- .../lib/active_record/associations/association_collection.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index eb39714909..04be59e89d 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -78,11 +78,14 @@ module ActiveRecord @loaded = false end - def build(attributes = {}) + def build(attributes = {}, &block) if attributes.is_a?(Array) - attributes.collect { |attr| build(attr) } + attributes.collect { |attr| build(attr, &block) } else - build_record(attributes) { |record| set_belongs_to_association_for(record) } + build_record(attributes) do |record| + block.call(record) if block_given? + set_belongs_to_association_for(record) + end end end -- cgit v1.2.3 From e0750d6a5c7f621e4ca12205137c0b135cab444a Mon Sep 17 00:00:00 2001 From: David Dollar Date: Sun, 13 Jul 2008 21:13:50 -0400 Subject: Add :accessible option to Associations for allowing mass assignments using hash. [#474 state:resolved] Allows nested Hashes (i.e. from nested forms) to hydrate the appropriate ActiveRecord models. class Post < ActiveRecord::Base belongs_to :author, :accessible => true has_many :comments, :accessible => true end post = Post.create({ :title => 'Accessible Attributes', :author => { :name => 'David Dollar' }, :comments => [ { :body => 'First Post!' }, { :body => 'Nested Hashes are great!' } ] }) post.comments << { :body => 'Another Comment' } Signed-off-by: Pratik Naik --- activerecord/lib/active_record/associations.rb | 14 ++++++++++---- .../active_record/associations/association_collection.rb | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 6931744058..d43e07ab4e 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -692,6 +692,7 @@ module ActiveRecord # * :uniq - If true, duplicates will be omitted from the collection. Useful in conjunction with :through. # * :readonly - If true, all the associated objects are readonly through the association. # * :validate - If false, don't validate the associated objects when saving the parent object. true by default. + # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # has_many :comments, :order => "posted_on" @@ -774,6 +775,7 @@ module ActiveRecord # association is a polymorphic +belongs_to+. # * :readonly - If true, the associated object is readonly through the association. # * :validate - If false, don't validate the associated object when saving the parent object. +false+ by default. + # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # has_one :credit_card, :dependent => :destroy # destroys the associated credit card @@ -863,6 +865,7 @@ module ActiveRecord # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). # * :readonly - If true, the associated object is readonly through the association. # * :validate - If false, don't validate the associated objects when saving the parent object. +false+ by default. + # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # belongs_to :firm, :foreign_key => "client_of" @@ -1034,6 +1037,7 @@ module ActiveRecord # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :readonly - If true, all the associated objects are readonly through the association. # * :validate - If false, don't validate the associated objects when saving the parent object. +true+ by default. + # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # has_and_belongs_to_many :projects @@ -1109,6 +1113,8 @@ module ActiveRecord association = association_proxy_class.new(self, reflection) end + new_value = reflection.klass.new(new_value) if reflection.options[:accessible] && new_value.is_a?(Hash) + if association_proxy_class == HasOneThroughAssociation association.create_through_record(new_value) self.send(reflection.name, new_value) @@ -1357,7 +1363,7 @@ module ActiveRecord :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove, :extend, :readonly, - :validate + :validate, :accessible ) options[:extend] = create_extension_modules(association_id, extension, options[:extend]) @@ -1367,7 +1373,7 @@ module ActiveRecord def create_has_one_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate, :primary_key + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate, :primary_key, :accessible ) create_reflection(:has_one, association_id, options, self) @@ -1383,7 +1389,7 @@ module ActiveRecord def create_belongs_to_reflection(association_id, options) options.assert_valid_keys( :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent, - :counter_cache, :extend, :polymorphic, :readonly, :validate + :counter_cache, :extend, :polymorphic, :readonly, :validate, :accessible ) reflection = create_reflection(:belongs_to, association_id, options, self) @@ -1403,7 +1409,7 @@ module ActiveRecord :finder_sql, :delete_sql, :insert_sql, :before_add, :after_add, :before_remove, :after_remove, :extend, :readonly, - :validate + :validate, :accessible ) options[:extend] = create_extension_modules(association_id, extension, options[:extend]) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 04be59e89d..a28be9eed1 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -97,6 +97,8 @@ module ActiveRecord @owner.transaction do flatten_deeper(records).each do |record| + record = @reflection.klass.new(record) if @reflection.options[:accessible] && record.is_a?(Hash) + raise_on_type_mismatch(record) add_record_to_target_with_callbacks(record) do |r| result &&= insert_record(record) unless @owner.new_record? @@ -229,6 +231,10 @@ module ActiveRecord # Replace this collection with +other_array+ # This will perform a diff and delete/add only records that have changed. def replace(other_array) + other_array.map! do |val| + val.is_a?(Hash) ? @reflection.klass.new(val) : val + end if @reflection.options[:accessible] + other_array.each { |val| raise_on_type_mismatch(val) } load_target -- cgit v1.2.3 From 0176e6adb388998414083e99523de318d3b8ca49 Mon Sep 17 00:00:00 2001 From: "Sebastian A. Espindola" Date: Tue, 8 Jul 2008 01:14:11 -0300 Subject: Added db:charset support to PostgreSQL. [#556 state:resolved] Signed-off-by: Pratik Naik --- .../active_record/connection_adapters/postgresql_adapter.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2e2d50ccf4..29ecd83ba0 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -623,6 +623,19 @@ module ActiveRecord end end + # Returns the current database name. + def current_database + query('select current_database()')[0][0] + end + + # Returns the current database encoding format. + def encoding + query(<<-end_sql)[0][0] + SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database + WHERE pg_database.datname LIKE '#{current_database}' + end_sql + end + # Sets the schema search path to a string of comma-separated schema names. # Names beginning with $ have to be quoted (e.g. $user => '$user'). # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html -- cgit v1.2.3 From 30370227890dc950f1544b7b1040aa75e505f877 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 14 Jul 2008 10:12:54 -0500 Subject: Fixed that create database statements would always include "DEFAULT NULL" (Nick Sieger) [#334 status:committed] --- .../active_record/connection_adapters/abstract/schema_definitions.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index d4c8a80448..13ccfea0b8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -257,7 +257,10 @@ module ActiveRecord def to_sql column_sql = "#{base.quote_column_name(name)} #{sql_type}" - add_column_options!(column_sql, :null => null, :default => default) unless type.to_sym == :primary_key + column_options = {} + column_options[:null] = null unless null.nil? + column_options[:default] = default unless default.nil? + add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key column_sql end alias to_s :to_sql -- cgit v1.2.3 From cdf0f1aa2ee4ba73bafc9b9217ee35b7f7eb3273 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 12 Jul 2008 11:42:17 -0700 Subject: Faster and clearer value_to_boolean --- .../connection_adapters/abstract/schema_definitions.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 13ccfea0b8..31d6c7942c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -1,4 +1,5 @@ require 'date' +require 'set' require 'bigdecimal' require 'bigdecimal/util' @@ -6,6 +7,8 @@ module ActiveRecord module ConnectionAdapters #:nodoc: # An abstract definition of a column in a table. class Column + TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set + module Format ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/ ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/ @@ -135,11 +138,7 @@ module ActiveRecord # convert something to a boolean def value_to_boolean(value) - if value == true || value == false - value - else - !(value.to_s !~ /\A(?:1|t|true)\Z/i) - end + TRUE_VALUES.include?(value) end # convert something to a BigDecimal -- cgit v1.2.3 From c760dbfd3117562c6f27170a213f586e3ba2b794 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 14 Jul 2008 11:59:46 -0700 Subject: PostgreSQL: don't dump :limit => 4 for integers --- activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 29ecd83ba0..6d16d72dea 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -49,7 +49,6 @@ module ActiveRecord private def extract_limit(sql_type) case sql_type - when /^integer/i; 4 when /^bigint/i; 8 when /^smallint/i; 2 else super -- cgit v1.2.3 From 07578ac85585d3c64d4d38d4892fd31582c7c473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Mon, 14 Jul 2008 09:42:20 +0300 Subject: Fixed mysql change_column_default to not make the column always nullable. Also added change_column_null to both mysql and sqlite to keep the api features closer to postgresql. [#617 state:resolved] --- .../connection_adapters/mysql_adapter.rb | 33 +++++++++++++++++----- .../connection_adapters/sqlite_adapter.rb | 9 ++++++ 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 4b13ac8be0..35b9ed4746 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -437,18 +437,29 @@ module ActiveRecord end def change_column_default(table_name, column_name, default) #:nodoc: - current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] + column = column_for(table_name, column_name) + change_column table_name, column_name, column.sql_type, :default => default + end + + def change_column_null(table_name, column_name, null, default = nil) + column = column_for(table_name, column_name) + + unless null || default.nil? + execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") + end - execute("ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{current_type} DEFAULT #{quote(default)}") + change_column table_name, column_name, column.sql_type, :null => null end def change_column(table_name, column_name, type, options = {}) #:nodoc: + column = column_for(table_name, column_name) + unless options_include_default?(options) - if column = columns(table_name).find { |c| c.name == column_name.to_s } - options[:default] = column.default - else - raise "No such column: #{table_name}.#{column_name}" - end + options[:default] = column.default + end + + unless options.has_key?(:null) + options[:null] = column.null end change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" @@ -460,6 +471,7 @@ module ActiveRecord options = {} if column = columns(table_name).find { |c| c.name == column_name.to_s } options[:default] = column.default + options[:null] = column.null else raise ActiveRecordError, "No such column: #{table_name}.#{column_name}" end @@ -536,6 +548,13 @@ module ActiveRecord def version @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } end + + def column_for(table_name, column_name) + unless column = columns(table_name).find { |c| c.name == column_name.to_s } + raise "No such column: #{table_name}.#{column_name}" + end + column + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 51cfd10e5c..f4d387cfb4 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -238,6 +238,15 @@ module ActiveRecord end end + def change_column_null(table_name, column_name, null, default = nil) + unless null || default.nil? + execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") + end + alter_table(table_name) do |definition| + definition[column_name].null = null + end + end + def change_column(table_name, column_name, type, options = {}) #:nodoc: alter_table(table_name) do |definition| include_default = options_include_default?(options) -- cgit v1.2.3 From cd9b24286a90111a08002e0da753198c5fb2432a Mon Sep 17 00:00:00 2001 From: Gabe da Silveira Date: Tue, 3 Jun 2008 17:50:42 -0300 Subject: Add assert_sql helper method to check for specific SQL output in Active Record test suite. [#325 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/test_case.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/test_case.rb b/activerecord/lib/active_record/test_case.rb index 7dee962c8a..ca5591ae35 100644 --- a/activerecord/lib/active_record/test_case.rb +++ b/activerecord/lib/active_record/test_case.rb @@ -22,11 +22,22 @@ module ActiveRecord end end + def assert_sql(*patterns_to_match) + $queries_executed = [] + yield + ensure + failed_patterns = [] + patterns_to_match.each do |pattern| + failed_patterns << pattern unless $queries_executed.any?{ |sql| pattern === sql } + end + assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} not found." + end + def assert_queries(num = 1) - $query_count = 0 + $queries_executed = [] yield ensure - assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed." + assert_equal num, $queries_executed.size, "#{$queries_executed.size} instead of #{num} queries were executed." end def assert_no_queries(&block) -- cgit v1.2.3 From 76df9fa0680d62ce41fa6f3b743c605101d101d2 Mon Sep 17 00:00:00 2001 From: Tiago Macedo Date: Fri, 11 Jul 2008 04:18:41 +0100 Subject: Fix integer quoting issues in association preload. [#602 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/association_preload.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 49f5270396..174ec95de2 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -188,7 +188,6 @@ module ActiveRecord through_records end - # FIXME: quoting def preload_belongs_to_association(records, reflection, preload_options={}) options = reflection.options primary_key_name = reflection.primary_key_name @@ -227,9 +226,19 @@ module ActiveRecord table_name = klass.quoted_table_name primary_key = klass.primary_key - conditions = "#{table_name}.#{primary_key} IN (?)" + conditions = "#{table_name}.#{connection.quote_column_name(primary_key)} IN (?)" conditions << append_conditions(options, preload_options) - associated_records = klass.find(:all, :conditions => [conditions, id_map.keys.uniq], + column_type = klass.columns.detect{|c| c.name == primary_key}.type + ids = id_map.keys.uniq.map do |id| + if column_type == :integer + id.to_i + elsif column_type == :float + id.to_f + else + id + end + end + associated_records = klass.find(:all, :conditions => [conditions, ids], :include => options[:include], :select => options[:select], :joins => options[:joins], -- cgit v1.2.3 From 8c91b767c0f36e9d767eb230ec42b111e57d90da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Tue, 15 Jul 2008 05:17:06 +0300 Subject: Fixed postgresql limited eager loading for the case where scoped :order was present --- activerecord/lib/active_record/associations.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index d43e07ab4e..7ad7802cbc 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1486,10 +1486,15 @@ module ActiveRecord join_dependency.joins_for_table_name(table) }.flatten.compact.uniq + order = options[:order] + if scoped_order = (scope && scope[:order]) + order = order ? "#{order}, #{scoped_order}" : scoped_order + end + is_distinct = !options[:joins].blank? || include_eager_conditions?(options, tables_from_conditions) || include_eager_order?(options, tables_from_order) sql = "SELECT " if is_distinct - sql << connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", options[:order]) + sql << connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", order) else sql << primary_key end @@ -1503,8 +1508,8 @@ module ActiveRecord add_conditions!(sql, options[:conditions], scope) add_group!(sql, options[:group], scope) - if options[:order] && is_distinct - connection.add_order_by_for_association_limiting!(sql, options) + if order && is_distinct + connection.add_order_by_for_association_limiting!(sql, :order => order) else add_order!(sql, options[:order], scope) end -- cgit v1.2.3 From c1531ae00dbd3ac804bce02733e050ec43400607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Tue, 15 Jul 2008 05:24:24 +0300 Subject: SQLite: rename_column raises if the column doesn't exist. [#622 state:resolved] --- activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index f4d387cfb4..84f8c0284e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -260,6 +260,9 @@ module ActiveRecord end def rename_column(table_name, column_name, new_column_name) #:nodoc: + unless columns(table_name).detect{|c| c.name == column_name.to_s } + raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}" + end alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s}) end -- cgit v1.2.3 From 4f72feb84c25b54f66c7192c788b7fd965f2d493 Mon Sep 17 00:00:00 2001 From: Jonathan Viney Date: Wed, 2 Jul 2008 16:01:26 +1200 Subject: Move the transaction counter to the connection object rather than maintaining it on the current Thread. Signed-off-by: Michael Koziarski [#533 state:resolved] --- .../connection_adapters/abstract_adapter.rb | 13 +++++++++++++ activerecord/lib/active_record/fixtures.rb | 8 ++++---- activerecord/lib/active_record/transactions.rb | 17 +++-------------- 3 files changed, 20 insertions(+), 18 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index f48b107a2a..47dbf5a5f3 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -118,6 +118,19 @@ module ActiveRecord @connection end + def open_transactions + @open_transactions ||= 0 + end + + def increment_open_transactions + @open_transactions ||= 0 + @open_transactions += 1 + end + + def decrement_open_transactions + @open_transactions -= 1 + end + def log_info(sql, name, runtime) if @logger && @logger.debug? name = "#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})" diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 17fb9355c4..622cfc3c3f 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -515,7 +515,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) all_loaded_fixtures.update(fixtures_map) - connection.transaction(Thread.current['open_transactions'].to_i == 0) do + connection.transaction(connection.open_transactions.zero?) do fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures } fixtures.each { |fixture| fixture.insert_fixtures } @@ -930,7 +930,7 @@ module Test #:nodoc: load_fixtures @@already_loaded_fixtures[self.class] = @loaded_fixtures end - ActiveRecord::Base.send :increment_open_transactions + ActiveRecord::Base.connection.increment_open_transactions ActiveRecord::Base.connection.begin_db_transaction # Load fixtures for every test. else @@ -951,9 +951,9 @@ module Test #:nodoc: end # Rollback changes if a transaction is active. - if use_transactional_fixtures? && Thread.current['open_transactions'] != 0 + if use_transactional_fixtures? && ActiveRecord::Base.connection.open_transactions != 0 ActiveRecord::Base.connection.rollback_db_transaction - Thread.current['open_transactions'] = 0 + ActiveRecord::Base.connection.decrement_open_transactions end ActiveRecord::Base.verify_active_connections! end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 3b6835762c..354a6c83a2 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -73,25 +73,14 @@ module ActiveRecord # trigger a ROLLBACK when raised, but not be re-raised by the transaction block. module ClassMethods def transaction(&block) - increment_open_transactions + connection.increment_open_transactions begin - connection.transaction(Thread.current['start_db_transaction'], &block) + connection.transaction(connection.open_transactions == 1, &block) ensure - decrement_open_transactions + connection.decrement_open_transactions end end - - private - def increment_open_transactions #:nodoc: - open = Thread.current['open_transactions'] ||= 0 - Thread.current['start_db_transaction'] = open.zero? - Thread.current['open_transactions'] = open + 1 - end - - def decrement_open_transactions #:nodoc: - Thread.current['open_transactions'] -= 1 - end end def transaction(&block) -- cgit v1.2.3 From 459e5817a513b95741b77af26771a6252a13d01f Mon Sep 17 00:00:00 2001 From: miloops Date: Thu, 26 Jun 2008 13:46:33 -0300 Subject: update_counters should update nil values. This allows counter columns with default null instead of requiring default 0. [#493 state:resolved] --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 962c2b36d9..8ca5a85ad8 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -828,7 +828,7 @@ module ActiveRecord #:nodoc: def update_counters(id, counters) updates = counters.inject([]) { |list, (counter_name, increment)| sign = increment < 0 ? "-" : "+" - list << "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} #{sign} #{increment.abs}" + list << "#{connection.quote_column_name(counter_name)} = COALESCE(#{connection.quote_column_name(counter_name)}, 0) #{sign} #{increment.abs}" }.join(", ") update_all(updates, "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}") end -- cgit v1.2.3 From fbef982e4b906b879240a35a1ecff447007da6b2 Mon Sep 17 00:00:00 2001 From: Stefan Kaes Date: Tue, 15 Jul 2008 20:55:14 +0200 Subject: Observers not longer add an after_find method to the observed class. [#625 state:resolved] --- activerecord/lib/active_record/observer.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 25e0e61c69..c96e5f9d51 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -20,7 +20,7 @@ module ActiveRecord # ActiveRecord::Base.observers = Cacher, GarbageCollector # # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is - # called during startup, and before each development request. + # called during startup, and before each development request. def observers=(*observers) @observers = observers.flatten end @@ -130,11 +130,11 @@ module ActiveRecord # Observers register themselves in the model class they observe, since it is the class that # notifies them of events when they occur. As a side-effect, when an observer is loaded its # corresponding model class is loaded. - # + # # Up to (and including) Rails 2.0.2 observers were instantiated between plugins and - # application initializers. Now observers are loaded after application initializers, + # application initializers. Now observers are loaded after application initializers, # so observed models can make use of extensions. - # + # # If by any chance you are using observed models in the initialization you can still # load their observers by calling ModelObserver.instance before. Observers are # singletons and that call instantiates and registers them. @@ -189,7 +189,6 @@ module ActiveRecord def add_observer!(klass) klass.add_observer(self) - klass.class_eval 'def after_find() end' unless klass.method_defined?(:after_find) end end end -- cgit v1.2.3