diff options
Diffstat (limited to 'activerecord/lib')
12 files changed, 103 insertions, 42 deletions
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index 1c1ba11c44..b0b1c13b0d 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -31,7 +31,8 @@ module ActiveRecord through_records = Array.wrap(owner.send(through_reflection.name)) # Dont cache the association - we would only be caching a subset - if reflection.options[:source_type] && through_reflection.collection? + if (through_scope != through_reflection.klass.unscoped) || + (reflection.options[:source_type] && through_reflection.collection?) owner.association(through_reflection.name).reset end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index d18b9c991f..aec4654eee 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -25,13 +25,19 @@ module ActiveRecord when true, false if column && column.type == :integer value ? '1' : '0' + elsif column && [:text, :string, :binary].include?(column.type) + value ? "'1'" : "'0'" else value ? quoted_true : quoted_false end # BigDecimals need to be put in a non-normalized form and quoted. when nil then "NULL" - when BigDecimal then value.to_s('F') - when Numeric, ActiveSupport::Duration then value.to_s + when Numeric, ActiveSupport::Duration + value = BigDecimal === value ? value.to_s('F') : value.to_s + if column && ![:integer, :float, :decimal].include?(column.type) + value = "'#{value}'" + end + value when Date, Time then "'#{quoted_date(value)}'" when Symbol then "'#{quote_string(value.to_s)}'" when Class then "'#{value.to_s}'" 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 b1ec33d06c..f758e19a4f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -252,15 +252,12 @@ module ActiveRecord self end - %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type| - class_eval <<-EOV, __FILE__, __LINE__ + 1 - def #{column_type}(*args) # def string(*args) - options = args.extract_options! # options = args.extract_options! - column_names = args # column_names = args - type = :'#{column_type}' # type = :string - column_names.each { |name| column(name, type, options) } # column_names.each { |name| column(name, type, options) } - end # end - EOV + [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type| + define_method column_type do |*args| + options = args.extract_options! + column_names = args + column_names.each { |name| column(name, column_type, options) } + end end # Adds index options to the indexes hash, keyed by column name @@ -486,15 +483,13 @@ module ActiveRecord # # t.string(:goat) # t.string(:goat, :sheep) - %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type| - class_eval <<-EOV, __FILE__, __LINE__ + 1 - def #{column_type}(*args) # def string(*args) - options = args.extract_options! # options = args.extract_options! - args.each do |name| # column_names.each do |name| - @base.add_column(@table_name, name, :#{column_type}, options) # @base.add_column(@table_name, name, :string, options) - end # end - end # end - EOV + [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type| + define_method column_type do |*args| + options = args.extract_options! + args.each do |name| + @base.add_column(@table_name, name, column_type, options) + end + end end private diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index b2ad4e600d..eecf4faa5d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -177,10 +177,16 @@ module ActiveRecord false end + # A list of extensions, to be filled in by databases that + # support them (at the moment, postgresql). + def extensions + [] + end + # QUOTING ================================================== # Returns a bind substitution value given a +column+ and list of current - # +binds+ + # +binds+. def substitute_at(column, index) Arel::Nodes::BindParam.new '?' end @@ -320,6 +326,10 @@ module ActiveRecord # override in derived class ActiveRecord::StatementInvalid.new(message) end + + def valid_types?(type) + true + end end end 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 52b0b3fe79..de5232f960 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -212,8 +212,6 @@ module ActiveRecord if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) s = column.class.string_to_binary(value).unpack("H*")[0] "x'#{s}'" - elsif value.kind_of?(BigDecimal) - value.to_s("F") else super end @@ -750,6 +748,9 @@ module ActiveRecord execute("SET #{encoding} #{variable_assignments}", :skip_logging) end + def valid_type?(type) + !native_database_types[type].nil? + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 747331f3a1..a4b3a0c584 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -74,12 +74,13 @@ module ActiveRecord def type_cast_for_write(value) return value unless number? - if value == false + case value + when FalseClass 0 - elsif value == true + when TrueClass 1 - elsif value.is_a?(String) && value.blank? - nil + when String + value.presence else value end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 5ce2f1b04c..271a6848ee 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -605,6 +605,15 @@ module ActiveRecord end end + def extensions + if supports_extensions? + res = exec_query "SELECT extname from pg_extension", "SCHEMA" + res.rows.map { |r| res.column_types['extname'].type_cast r.first } + else + super + end + end + # Returns the configured supported identifier length supported by PostgreSQL def table_alias_length @table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i @@ -878,6 +887,10 @@ module ActiveRecord def table_definition TableDefinition.new(self) end + + def valid_type?(type) + !native_database_types[type].nil? + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 7bead4bde9..b644e7bd60 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -603,6 +603,10 @@ module ActiveRecord end end + def valid_type?(type) + true + end + end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 537ebbef28..5cd015eba7 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -8,7 +8,7 @@ module ActiveRecord if value.is_a?(Hash) if value.empty? - queries << '1 = 2' + queries << '1=0' else table = Arel::Table.new(column, default_table.engine) association = klass.reflect_on_association(column.to_sym) @@ -98,6 +98,11 @@ module ActiveRecord when Class # FIXME: I think we need to deprecate this behavior attribute.eq(value.name) + when Integer, ActiveSupport::Duration + # Arel treats integers as literals, but they should be quoted when compared with strings + table = attribute.relation + column = table.engine.connection.schema_cache.columns_hash(table.name)[attribute.name.to_s] + attribute.eq(Arel::Nodes::SqlLiteral.new(table.engine.connection.quote(value, column))) else attribute.eq(value) end diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 36bde44e7c..df090b972d 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -24,6 +24,7 @@ module ActiveRecord def dump(stream) header(stream) + extensions(stream) tables(stream) trailer(stream) stream @@ -66,6 +67,18 @@ HEADER stream.puts "end" end + def extensions(stream) + return unless @connection.supports_extensions? + extensions = @connection.extensions + if extensions.any? + stream.puts " # These are extensions that must be enabled in order to support this database" + extensions.each do |extension| + stream.puts " enable_extension #{extension.inspect}" + end + stream.puts + end + end + def tables(stream) @connection.tables.sort.each do |tbl| next if ['schema_migrations', ignore_tables].flatten.any? do |ignored| diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb index cf4cf9e602..a610f479f2 100644 --- a/activerecord/lib/active_record/store.rb +++ b/activerecord/lib/active_record/store.rb @@ -42,21 +42,19 @@ module ActiveRecord # # All stored values are automatically available through accessors on the Active Record # object, but sometimes you want to specialize this behavior. This can be done by overwriting - # the default accessors (using the same name as the attribute) and calling - # <tt>read_store_attribute(store_attribute_name, attr_name)</tt> and - # <tt>write_store_attribute(store_attribute_name, attr_name, value)</tt> to actually - # change things. + # the default accessors (using the same name as the attribute) and calling <tt>super</tt> + # to actually change things. # # class Song < ActiveRecord::Base # # Uses a stored integer to hold the volume adjustment of the song # store :settings, accessors: [:volume_adjustment] # # def volume_adjustment=(decibels) - # write_store_attribute(:settings, :volume_adjustment, decibels.to_i) + # super(decibels.to_i) # end # # def volume_adjustment - # read_store_attribute(:settings, :volume_adjustment).to_i + # super.to_i # end # end module Store @@ -75,19 +73,30 @@ module ActiveRecord def store_accessor(store_attribute, *keys) keys = keys.flatten - keys.each do |key| - define_method("#{key}=") do |value| - write_store_attribute(store_attribute, key, value) - end - define_method(key) do - read_store_attribute(store_attribute, key) + _store_accessors_module.module_eval do + keys.each do |key| + define_method("#{key}=") do |value| + write_store_attribute(store_attribute, key, value) + end + + define_method(key) do + read_store_attribute(store_attribute, key) + end end end self.stored_attributes[store_attribute] ||= [] self.stored_attributes[store_attribute] |= keys end + + def _store_accessors_module + @_store_accessors_module ||= begin + mod = Module.new + include mod + mod + end + end end protected diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 4a608e4f7b..4b7a388dc7 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -286,8 +286,11 @@ module ActiveRecord end # Call the after_commit callbacks + # + # Ensure that it is not called if the object was never persisted (failed create), + # but call it after the commit of a destroyed object def committed! #:nodoc: - run_callbacks :commit + run_callbacks :commit if destroyed? || persisted? ensure clear_transaction_record_state end |