diff options
Diffstat (limited to 'activerecord/lib')
13 files changed, 89 insertions, 37 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 68f8bbeb1c..a62fce4756 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1167,6 +1167,8 @@ module ActiveRecord # If true, always save the associated objects or destroy them if marked for destruction, # when saving the parent object. If false, never save or destroy the associated objects. # By default, only save associated objects that are new records. + # + # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>. # [:inverse_of] # Specifies the name of the <tt>belongs_to</tt> association on the associated object # that is the inverse of this <tt>has_many</tt> association. Does not work in combination @@ -1288,6 +1290,8 @@ module ActiveRecord # If true, always save the associated object or destroy it if marked for destruction, # when saving the parent object. If false, never save or destroy the associated object. # By default, only save the associated object if it's a new record. + # + # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>. # [:inverse_of] # Specifies the name of the <tt>belongs_to</tt> association on the associated object # that is the inverse of this <tt>has_one</tt> association. Does not work in combination @@ -1404,6 +1408,8 @@ module ActiveRecord # saving the parent object. # If false, never save or destroy the associated object. # By default, only save the associated object if it's a new record. + # + # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>. # [:touch] # If true, the associated object will be touched (the updated_at/on attributes set to now) # when this record is either saved or destroyed. If you specify a symbol, that attribute @@ -1589,6 +1595,8 @@ module ActiveRecord # If false, never save or destroy the associated objects. # By default, only save associated objects that are new records. # + # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>. + # # Option examples: # has_and_belongs_to_many :projects # has_and_belongs_to_many :projects, :include => [ :milestones, :manager ] diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb index ab6d253ef8..5b41f72e52 100644 --- a/activerecord/lib/active_record/attribute_assignment.rb +++ b/activerecord/lib/active_record/attribute_assignment.rb @@ -158,11 +158,12 @@ module ActiveRecord begin send(name + "=", read_value_from_parameter(name, values_with_empty_parameters)) rescue => ex - errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name}", ex, name) + errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name) end end unless errors.empty? - raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes" + error_descriptions = errors.map { |ex| ex.message }.join(",") + raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]" end end @@ -180,15 +181,27 @@ module ActiveRecord end def read_time_parameter_value(name, values_hash_from_param) - # If Date bits were not provided, error - raise "Missing Parameter" if [1,2,3].any?{|position| !values_hash_from_param.has_key?(position)} - max_position = extract_max_param_for_multiparameter_attributes(values_hash_from_param, 6) - # If Date bits were provided but blank, then return nil - return nil if (1..3).any? {|position| values_hash_from_param[position].blank?} + # If column is a :time (and not :date or :timestamp) there is no need to validate if + # there are year/month/day fields + if column_for_attribute(name).type == :time + # if the column is a time set the values to their defaults as January 1, 1970, but only if they're nil + {1 => 1970, 2 => 1, 3 => 1}.each do |key,value| + values_hash_from_param[key] ||= value + end + else + # else column is a timestamp, so if Date bits were not provided, error + if missing_parameter = [1,2,3].detect{ |position| !values_hash_from_param.has_key?(position) } + raise ArgumentError.new("Missing Parameter - #{name}(#{missing_parameter}i)") + end + + # If Date bits were provided but blank, then return nil + return nil if (1..3).any? { |position| values_hash_from_param[position].blank? } + end - set_values = (1..max_position).collect{|position| values_hash_from_param[position] } + max_position = extract_max_param_for_multiparameter_attributes(values_hash_from_param, 6) + set_values = (1..max_position).collect{ |position| values_hash_from_param[position] } # If Time bits are not there, then default to 0 - (3..5).each {|i| set_values[i] = set_values[i].blank? ? 0 : set_values[i]} + (3..5).each { |i| set_values[i] = set_values[i].blank? ? 0 : set_values[i] } instantiate_time_object(name, set_values) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 921278d145..df4a9d5afc 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -72,6 +72,8 @@ module ActiveRecord when /^mediumint/i; 3 when /^smallint/i; 2 when /^tinyint/i; 1 + when /^enum\((.+)\)/i + $1.split(',').map{|enum| enum.strip.length - 2}.max else super end diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 8491d42b86..dd40351a38 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -1,3 +1,5 @@ +require 'uri' + module ActiveRecord module ConnectionAdapters class ConnectionSpecification #:nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index a9940209fa..507e937c3e 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -916,7 +916,8 @@ module ActiveRecord end # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>, - # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses + # <tt>:encoding</tt>, <tt>:collate</tt>, <tt>:ctype</tt>, + # <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>). # # Example: @@ -933,6 +934,10 @@ module ActiveRecord " TEMPLATE = \"#{value}\"" when :encoding " ENCODING = '#{value}'" + when :collate + " LC_COLLATE = '#{value}'" + when :ctype + " LC_CTYPE = '#{value}'" when :tablespace " TABLESPACE = \"#{value}\"" when :connection_limit @@ -1059,6 +1064,20 @@ module ActiveRecord end_sql end + # Returns the current database collate. + def collate + query(<<-end_sql, 'SCHEMA')[0][0] + SELECT pg_database.datcollate FROM pg_database WHERE pg_database.datname LIKE '#{current_database}' + end_sql + end + + # Returns the current database ctype. + def ctype + query(<<-end_sql, 'SCHEMA')[0][0] + SELECT pg_database.datctype FROM pg_database WHERE pg_database.datname LIKE '#{current_database}' + end_sql + end + # Returns an array of schema names. def schema_names query(<<-SQL, 'SCHEMA').flatten diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 858b667e22..5f157fde6d 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -106,13 +106,11 @@ module ActiveRecord attr_reader :record, :attempted_action def initialize(record, attempted_action) + super("Attempted to #{attempted_action} a stale object: #{record.class.name}") @record = record @attempted_action = attempted_action end - def message - "Attempted to #{attempted_action} a stale object: #{record.class.name}" - end end # Raised when association is being configured improperly or @@ -168,9 +166,9 @@ module ActiveRecord class AttributeAssignmentError < ActiveRecordError attr_reader :exception, :attribute def initialize(message, exception, attribute) + super(message) @exception = exception @attribute = attribute - @message = message end end @@ -189,12 +187,10 @@ module ActiveRecord attr_reader :model def initialize(model) + super("Unknown primary key for table #{model.table_name} in model #{model}.") @model = model end - def message - "Unknown primary key for table #{model.table_name} in model #{model}." - end end class ImmutableRelation < ActiveRecordError diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index c6ec946b73..78ecb1cdc5 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -148,13 +148,10 @@ db_namespace = namespace :db do # desc "Retrieves the collation for the current environment's database" task :collation => [:environment, :load_config] do - config = ActiveRecord::Base.configurations[Rails.env || 'development'] - case config['adapter'] - when /mysql/ - ActiveRecord::Base.establish_connection(config) - puts ActiveRecord::Base.connection.collation - else - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' + begin + puts ActiveRecord::Tasks::DatabaseTasks.collation_current + rescue NoMethodError + $stderr.puts 'Sorry, your database adapter is not supported yet, feel free to submit a patch' end end @@ -274,7 +271,7 @@ db_namespace = namespace :db do ENV['ISC_USER'] = config['username'].to_s if config['username'] ENV['ISC_PASSWORD'] = config['password'].to_s if config['password'] end - + def firebird_db_string(config) FireRuby::Database.db_string_for(config.symbolize_keys) end @@ -435,7 +432,7 @@ namespace :railties do task :migrations => :'db:load_config' do to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip } railties = {} - Rails.application.railties.all do |railtie| + Rails.application.railties.each do |railtie| next unless to_load == :all || to_load.include?(railtie.railtie_name) if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first) diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index fe3aa00a74..e268d451e0 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -492,10 +492,6 @@ module ActiveRecord end end - def inspect - to_a.inspect - end - def pretty_print(q) q.pp(self.to_a) end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index e6a67b76fe..974cd326ef 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -146,8 +146,8 @@ module ActiveRecord to_a end - # Returns true if a record exists in the table that matches the +id+ or - # conditions given, or false otherwise. The argument can take five forms: + # Returns +true+ if a record exists in the table that matches the +id+ or + # conditions given, or +false+ otherwise. The argument can take six forms: # # * Integer - Finds the record with this primary key. # * String - Finds the record with a primary key corresponding to this @@ -155,8 +155,9 @@ module ActiveRecord # * Array - Finds the record that matches these +find+-style conditions # (such as <tt>['color = ?', 'red']</tt>). # * Hash - Finds the record that matches these +find+-style conditions - # (such as <tt>{:color => 'red'}</tt>). - # * No args - Returns false if the table is empty, true otherwise. + # (such as <tt>{color: 'red'}</tt>). + # * +false+ - Returns always +false+. + # * No args - Returns +false+ if the table is empty, +true+ otherwise. # # For more information about specifying conditions as a Hash or Array, # see the Conditions section in the introduction to ActiveRecord::Base. @@ -168,7 +169,8 @@ module ActiveRecord # Person.exists?(5) # Person.exists?('5') # Person.exists?(['name LIKE ?', "%#{query}%"]) - # Person.exists?(:name => "David") + # Person.exists?(name: 'David') + # Person.exists?(false) # Person.exists? def exists?(conditions = :none) conditions = conditions.id if ActiveRecord::Model === conditions diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index d61df216bc..6f49548aab 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -415,10 +415,10 @@ module ActiveRecord # # Can accept other relation objects. For example: # - # Topic.select('title').from(Topics.approved) + # Topic.select('title').from(Topic.approved) # # => SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery # - # Topics.select('a.title').from(Topics.approved, :a) + # Topic.select('a.title').from(Topic.approved, :a) # # => SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a # def from(value, subquery_name = nil) diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 999b2ebc85..f1241502f5 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -56,6 +56,15 @@ module ActiveRecord class_for_adapter(configuration['adapter']).new(*arguments).charset end + def collation_current(environment = Rails.env) + collation ActiveRecord::Base.configurations[environment] + end + + def collation(*arguments) + configuration = arguments.first + class_for_adapter(configuration['adapter']).new(*arguments).collation + end + def purge(configuration) class_for_adapter(configuration['adapter']).new(configuration).purge end diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb index b39cd2282f..bf62dfd5b5 100644 --- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb @@ -44,6 +44,10 @@ module ActiveRecord connection.charset end + def collation + connection.collation + end + def structure_dump(filename) establish_connection configuration File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump } diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb index a210392e53..4139460273 100644 --- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb @@ -29,6 +29,10 @@ module ActiveRecord connection.encoding end + def collation + connection.collate + end + def purge clear_active_connections! drop |