diff options
Diffstat (limited to 'activerecord/lib/active_record')
13 files changed, 59 insertions, 72 deletions
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index c6d204d3c2..badde9973f 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -128,9 +128,9 @@ module ActiveRecord reflection = chain_head while reflection table = reflection.alias_name + next_reflection = reflection.next unless reflection == chain_tail - next_reflection = reflection.next foreign_table = next_reflection.alias_name scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection) end @@ -138,7 +138,7 @@ module ActiveRecord # Exclude the scope of the association itself, because that # was already merged in the #scope method. reflection.constraints.each do |scope_chain_item| - item = eval_scope(reflection.klass, scope_chain_item, owner) + item = eval_scope(reflection.klass, table, scope_chain_item, owner) if scope_chain_item == refl.scope scope.merge! item.except(:where, :includes) @@ -153,14 +153,15 @@ module ActiveRecord scope.order_values |= item.order_values end - reflection = reflection.next + reflection = next_reflection end scope end - def eval_scope(klass, scope, owner) - klass.unscoped.instance_exec(owner, &scope) + def eval_scope(klass, table, scope, owner) + predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table)) + ActiveRecord::Relation.create(klass, table, predicate_builder).instance_exec(owner, &scope) end end end diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb index 604904abcc..1183bdf6f4 100644 --- a/activerecord/lib/active_record/associations/has_one_through_association.rb +++ b/activerecord/lib/active_record/associations/has_one_through_association.rb @@ -22,6 +22,10 @@ module ActiveRecord elsif record attributes = construct_join_attributes(record) + if through_record && through_record.destroyed? + through_record = through_proxy.tap(&:reload).target + end + if through_record through_record.update(attributes) elsif owner.new_record? diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index a79eb03acc..87e0847ec1 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -171,7 +171,7 @@ module ActiveRecord chain = child.reflection.chain foreign_table = parent.table foreign_klass = parent.base_klass - child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, child.reflection.scope_chain, chain) + child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, chain) end def make_outer_joins(parent, child) diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index a5705951f3..f5fcba1236 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -23,14 +23,11 @@ module ActiveRecord JoinInformation = Struct.new :joins, :binds - def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain) + def join_constraints(foreign_table, foreign_klass, node, join_type, tables, chain) joins = [] binds = [] tables = tables.reverse - scope_chain_index = 0 - scope_chain = scope_chain.reverse - # The chain starts with the target table, but we want to end with it here (makes # more sense in this context), so we reverse chain.reverse_each do |reflection| @@ -44,7 +41,7 @@ module ActiveRecord constraint = build_constraint(klass, table, key, foreign_table, foreign_key) predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table)) - scope_chain_items = scope_chain[scope_chain_index].map do |item| + scope_chain_items = reflection.scopes.map do |item| if item.is_a?(Relation) item else @@ -52,7 +49,6 @@ module ActiveRecord .instance_exec(node, &item) end end - scope_chain_index += 1 klass_scope = if klass.current_scope diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 945192fe04..4d9aff76cc 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -54,7 +54,7 @@ module ActiveRecord elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) } class_name_or_coder else - Coders::YAMLColumn.new(class_name_or_coder) + Coders::YAMLColumn.new(attr_name, class_name_or_coder) end decorate_attribute_type(attr_name, :serialize) do |type| diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb index 4b06987f08..2136da43fe 100644 --- a/activerecord/lib/active_record/coders/yaml_column.rb +++ b/activerecord/lib/active_record/coders/yaml_column.rb @@ -5,7 +5,8 @@ module ActiveRecord class YAMLColumn # :nodoc: attr_accessor :object_class - def initialize(object_class = Object) + def initialize(attr_name, object_class = Object) + @attr_name = attr_name @object_class = object_class check_arity_of_constructor end @@ -31,7 +32,7 @@ module ActiveRecord def assert_valid_value(obj) unless obj.nil? || obj.is_a?(object_class) raise SerializationTypeMismatch, - "Attribute was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}" + "Attribute `#{@attr_name}` was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}" end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 0c6bc16e6f..437e7c6510 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -1,4 +1,5 @@ require "active_support/core_ext/big_decimal/conversions" +require "active_support/multibyte/chars" module ActiveRecord module ConnectionAdapters # :nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 0ebd907cc0..a2c5ef6817 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -438,7 +438,7 @@ module ActiveRecord end end - def get_oid_type(oid, fmod, column_name, sql_type = "") + def get_oid_type(oid, fmod, column_name, sql_type = "".freeze) if !type_map.key?(oid) load_additional_types(type_map, [oid]) end @@ -759,11 +759,11 @@ module ActiveRecord query(<<-end_sql, "SCHEMA") SELECT a.attname, format_type(a.atttypid, a.atttypmod), pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod, - (SELECT c.collname FROM pg_collation c, pg_type t - WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation), - col_description(a.attrelid, a.attnum) AS comment - FROM pg_attribute a LEFT JOIN pg_attrdef d - ON a.attrelid = d.adrelid AND a.attnum = d.adnum + c.collname, col_description(a.attrelid, a.attnum) AS comment + FROM pg_attribute a + LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum + LEFT JOIN pg_type t ON a.atttypid = t.oid + LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 339332a60d..40f6226315 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -525,7 +525,7 @@ module ActiveRecord raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \ "Please specify the Rails release the migration was written for:\n" \ "\n" \ - " class #{self.class.name} < ActiveRecord::Migration[4.2]" + " class #{subclass} < ActiveRecord::Migration[4.2]" end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 4cd867faae..7ceb7d1a55 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -148,6 +148,8 @@ module ActiveRecord # # Attributes marked as readonly are silently ignored if the record is # being updated. + # + # Unless an error is raised, returns true. def save!(*args) create_or_update(*args) || raise(RecordNotSaved.new("Failed to save the record", self)) end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 2c8c4b6297..81ec4924b0 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -1,5 +1,6 @@ require "thread" require "active_support/core_ext/string/filters" +require "active_support/deprecation" module ActiveRecord # = Active Record Reflection @@ -175,8 +176,19 @@ module ActiveRecord JoinKeys.new(foreign_key, active_record_primary_key) end + # Returns a list of scopes that should be applied for this Reflection + # object when querying the database. + def scopes + scope ? [scope] : [] + end + + def scope_chain + chain.map(&:scopes) + end + deprecate :scope_chain + def constraints - scope_chain.flatten + chain.map(&:scopes).flatten end def counter_cache_column @@ -461,12 +473,6 @@ module ActiveRecord false end - # An array of arrays of scopes. Each item in the outside array corresponds to a reflection - # in the #chain. - def scope_chain - scope ? [[scope]] : [[]] - end - def has_scope? scope end @@ -796,45 +802,12 @@ module ActiveRecord through_reflection.clear_association_scope_cache end - # Consider the following example: - # - # class Person - # has_many :articles - # has_many :comment_tags, through: :articles - # end - # - # class Article - # has_many :comments - # has_many :comment_tags, through: :comments, source: :tags - # end - # - # class Comment - # has_many :tags - # end - # - # There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags, - # but only Comment.tags will be represented in the #chain. So this method creates an array - # of scopes corresponding to the chain. - def scope_chain - @scope_chain ||= begin - scope_chain = source_reflection.scope_chain.map(&:dup) - - # Add to it the scope from this reflection (if any) - scope_chain.first << scope if scope - - through_scope_chain = through_reflection.scope_chain.map(&:dup) - - if options[:source_type] - type = foreign_type - source_type = options[:source_type] - through_scope_chain.first << lambda { |object| - where(type => source_type) - } - end + def scopes + source_reflection.scopes + super + end - # Recursively fill out the rest of the array from the through reflection - scope_chain + through_scope_chain - end + def source_type_scope + through_reflection.klass.where(foreign_type => options[:source_type]) end def has_scope? @@ -1008,6 +981,15 @@ module ActiveRecord @previous_reflection = previous_reflection end + def scopes + scopes = @previous_reflection.scopes + if @previous_reflection.options[:source_type] + scopes + [@previous_reflection.source_type_scope] + else + scopes + end + end + def klass @reflection.klass end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 6663bdb244..4548944fe6 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -17,8 +17,8 @@ module ActiveRecord # Person.where("administrator = 1").order("created_on DESC").find(1) # # NOTE: The returned records may not be in the same order as the ids you - # provide since database rows are unordered. You'd need to provide an explicit QueryMethods#order - # option if you want the results are sorted. + # provide since database rows are unordered. You will need to provide an explicit QueryMethods#order + # option if you want the results to be sorted. # # ==== Find with lock # diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb index d4be20d999..006afe7495 100644 --- a/activerecord/lib/active_record/store.rb +++ b/activerecord/lib/active_record/store.rb @@ -78,7 +78,7 @@ module ActiveRecord module ClassMethods def store(store_attribute, options = {}) - serialize store_attribute, IndifferentCoder.new(options[:coder]) + serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder]) store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors end @@ -177,12 +177,12 @@ module ActiveRecord end class IndifferentCoder # :nodoc: - def initialize(coder_or_class_name) + def initialize(attr_name, coder_or_class_name) @coder = if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump) coder_or_class_name else - ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object) + ActiveRecord::Coders::YAMLColumn.new(attr_name, coder_or_class_name || Object) end end |