From 61e831564aa4b22983646ecdc15d43991bc0e522 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 16 Jan 2010 21:21:20 +0530 Subject: Add Relation#apply_finder_options for applying old finder options --- activerecord/lib/active_record/base.rb | 30 +--------------------- .../lib/active_record/relation/spawn_methods.rb | 23 +++++++++++++++++ 2 files changed, 24 insertions(+), 29 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index e84130f42e..5bd24ac3eb 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1563,24 +1563,8 @@ module ActiveRecord #:nodoc: end def construct_finder_arel(options = {}, scope = nil) - validate_find_options(options) - - relation = active_relation. - joins(options[:joins]). - where(options[:conditions]). - select(options[:select]). - group(options[:group]). - having(options[:having]). - order(options[:order]). - limit(options[:limit]). - offset(options[:offset]). - from(options[:from]). - includes(options[:include]) - + relation = active_relation.apply_finder_options(options) relation = relation.where(type_condition) if finder_needs_type_condition? - relation = relation.lock(options[:lock]) if options[:lock].present? - relation = relation.readonly(options[:readonly]) if options.has_key?(:readonly) - relation = scope.merge(relation) if scope relation end @@ -1781,11 +1765,6 @@ module ActiveRecord #:nodoc: end method_scoping.assert_valid_keys([ :find, :create ]) - - if f = method_scoping[:find] - f.assert_valid_keys(VALID_FIND_OPTIONS) - end - relation = construct_finder_arel(method_scoping[:find] || {}) if current_scoped_methods && current_scoped_methods.create_with_value && method_scoping[:create] @@ -2047,13 +2026,6 @@ module ActiveRecord #:nodoc: end end - VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, - :order, :select, :readonly, :group, :having, :from, :lock ] - - def validate_find_options(options) #:nodoc: - options.assert_valid_keys(VALID_FIND_OPTIONS) - end - def encode_quoted_value(value) #:nodoc: quoted_value = connection.quote(value) quoted_value = "'#{quoted_value[1..-2].gsub(/\'/, "\\\\'")}'" if quoted_value.include?("\\\'") # (for ruby mode) " diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index a248c72715..59cfca85ae 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -88,5 +88,28 @@ module ActiveRecord result end + VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, + :order, :select, :readonly, :group, :having, :from, :lock ] + + def apply_finder_options(options) + options.assert_valid_keys(VALID_FIND_OPTIONS) + + relation = joins(options[:joins]). + where(options[:conditions]). + select(options[:select]). + group(options[:group]). + having(options[:having]). + order(options[:order]). + limit(options[:limit]). + offset(options[:offset]). + from(options[:from]). + includes(options[:include]) + + relation = relation.lock(options[:lock]) if options[:lock].present? + relation = relation.readonly(options[:readonly]) if options.has_key?(:readonly) + + relation + end + end end -- cgit v1.2.3 From f80be3ea0fa2bb3416e180901d441b0834001c7f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 16 Jan 2010 22:05:01 +0530 Subject: Use Relation#apply_finder_options from calculations --- activerecord/lib/active_record/calculations.rb | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index cd7bd185c5..a79ceb1d05 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -163,14 +163,7 @@ module ActiveRecord join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, includes, construct_join(joins)) construct_calculation_arel_with_included_associations(options, join_dependency, merge_with_relation) else - relation = active_relation. - joins(options[:joins]). - where(options[:conditions]). - order(options[:order]). - limit(options[:limit]). - offset(options[:offset]). - group(options[:group]). - having(options[:having]) + relation = active_relation.apply_finder_options(options.slice(:joins, :conditions, :order, :limit, :offset, :group, :having)) if merge_with_relation relation = merge_with_relation.except(:select, :order, :limit, :offset, :group, :from).merge(relation) @@ -205,14 +198,8 @@ module ActiveRecord relation = relation.where(type_condition) if finder_needs_type_condition? end - relation = relation.joins(options[:joins]). - select(column_aliases(join_dependency)). - group(options[:group]). - having(options[:having]). - order(options[:order]). - where(options[:conditions]). - from(options[:from]) - + relation = relation.apply_finder_options(options.slice(:joins, :group, :having, :order, :conditions, :from)). + select(column_aliases(join_dependency)) if !using_limitable_reflections?(join_dependency.reflections) && (merge_limit || options[:limit]) relation = relation.where(construct_arel_limited_ids_condition(options, join_dependency)) -- cgit v1.2.3 From cfdfd899262c79c37ac89e030f4d90c8f9868b50 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 16 Jan 2010 22:14:10 +0530 Subject: Use new finder methods for association preloading --- .../lib/active_record/association_preload.rb | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 9f7b2a60b2..a43c4d09d6 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -188,11 +188,11 @@ module ActiveRecord conditions << append_conditions(reflection, preload_options) associated_records = reflection.klass.with_exclusive_scope do - reflection.klass.find(:all, :conditions => [conditions, ids], - :include => options[:include], - :joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}", - :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id", - :order => options[:order]) + reflection.klass.where([conditions, ids]). + includes(options[:include]). + joins("INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}"). + select("#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id"). + order(options[:order]).to_a end set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id') end @@ -327,6 +327,7 @@ module ActiveRecord table_name = klass.quoted_table_name primary_key = klass.primary_key column_type = klass.columns.detect{|c| c.name == primary_key}.type + ids = id_map.keys.map do |id| if column_type == :integer id.to_i @@ -336,15 +337,14 @@ module ActiveRecord id end end + conditions = "#{table_name}.#{connection.quote_column_name(primary_key)} #{in_or_equals_for_ids(ids)}" conditions << append_conditions(reflection, preload_options) + associated_records = klass.with_exclusive_scope do - klass.find(:all, :conditions => [conditions, ids], - :include => options[:include], - :select => options[:select], - :joins => options[:joins], - :order => options[:order]) + klass.where([conditions, ids]).apply_finder_options(options.slice(:include, :select, :joins, :order)).to_a end + set_association_single_records(id_map, reflection.name, associated_records, primary_key) end end @@ -363,13 +363,12 @@ module ActiveRecord conditions << append_conditions(reflection, preload_options) reflection.klass.with_exclusive_scope do - reflection.klass.find(:all, - :select => (preload_options[:select] || options[:select] || "#{table_name}.*"), - :include => preload_options[:include] || options[:include], - :conditions => [conditions, ids], - :joins => options[:joins], - :group => preload_options[:group] || options[:group], - :order => preload_options[:order] || options[:order]) + reflection.klass.select(preload_options[:select] || options[:select] || "#{table_name}.*"). + includes(preload_options[:include] || options[:include]). + where([conditions, ids]). + joins(options[:joins]). + group(preload_options[:group] || options[:group]). + order(preload_options[:order] || options[:order]) end end -- cgit v1.2.3 From 3968825f5ff6a75cb83400716d56ec10f261e41a Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 16 Jan 2010 23:11:35 +0530 Subject: Make sure Model#active_relation always adds STI conditions if needed --- activerecord/lib/active_record/base.rb | 5 ++--- activerecord/lib/active_record/calculations.rb | 4 ---- activerecord/lib/active_record/named_scope.rb | 2 +- activerecord/lib/active_record/relation/spawn_methods.rb | 4 +++- 4 files changed, 6 insertions(+), 9 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 5bd24ac3eb..d0db9fadcd 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -872,7 +872,6 @@ module ActiveRecord #:nodoc: relation = active_relation relation = relation.where(conditions) if conditions - relation = relation.where(type_condition) if finder_needs_type_condition? relation = relation.limit(options[:limit]) if options[:limit].present? relation = relation.order(options[:order]) if options[:order].present? @@ -1389,7 +1388,7 @@ module ActiveRecord #:nodoc: def reset_column_information undefine_attribute_methods @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @inheritance_column = nil - @active_relation = @arel_engine = nil + @arel_engine = @active_relation = @arel_engine = nil end def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc: @@ -1504,6 +1503,7 @@ module ActiveRecord #:nodoc: def active_relation @active_relation ||= Relation.new(self, arel_table) + finder_needs_type_condition? ? @active_relation.where(type_condition) : @active_relation end def arel_table(table_name_alias = nil) @@ -1564,7 +1564,6 @@ module ActiveRecord #:nodoc: def construct_finder_arel(options = {}, scope = nil) relation = active_relation.apply_finder_options(options) - relation = relation.where(type_condition) if finder_needs_type_condition? relation = scope.merge(relation) if scope relation end diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index a79ceb1d05..ed4218807d 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -167,8 +167,6 @@ module ActiveRecord if merge_with_relation relation = merge_with_relation.except(:select, :order, :limit, :offset, :group, :from).merge(relation) - else - relation = relation.where(type_condition) if finder_needs_type_condition? end from = merge_with_relation.from_value if merge_with_relation && merge_with_relation.from_value.present? @@ -194,8 +192,6 @@ module ActiveRecord relation.where_values = merge_with_relation.where_values merge_limit = merge_with_relation.taken - else - relation = relation.where(type_condition) if finder_needs_type_condition? end relation = relation.apply_finder_options(options.slice(:joins, :group, :having, :order, :conditions, :from)). diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 47b69dec62..531419fd8e 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -29,7 +29,7 @@ module ActiveRecord current_scope = current_scoped_methods unless current_scope - finder_needs_type_condition? ? active_relation.where(type_condition) : active_relation.spawn + active_relation.spawn else construct_finder_arel({}, current_scoped_methods) end diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 59cfca85ae..33df8fd06c 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -94,7 +94,9 @@ module ActiveRecord def apply_finder_options(options) options.assert_valid_keys(VALID_FIND_OPTIONS) - relation = joins(options[:joins]). + relation = spawn + + relation = relation.joins(options[:joins]). where(options[:conditions]). select(options[:select]). group(options[:group]). -- cgit v1.2.3 From 07e41a83616966fef848797c3474eb7704a62794 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 16 Jan 2010 23:17:14 +0530 Subject: No need to set @arel_engine to nil twice. Committed by mistake in 3968825f --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index d0db9fadcd..acebf1e7fd 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1388,7 +1388,7 @@ module ActiveRecord #:nodoc: def reset_column_information undefine_attribute_methods @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @inheritance_column = nil - @arel_engine = @active_relation = @arel_engine = nil + @arel_engine = @active_relation = nil end def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc: -- cgit v1.2.3 From 7f8d4d3c4ed82a90f94251438d61d395a544026c Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 16 Jan 2010 23:59:57 +0530 Subject: Get rid of Base#merge_includes --- activerecord/lib/active_record/base.rb | 5 ----- activerecord/lib/active_record/calculations.rb | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index acebf1e7fd..bf42a5b221 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1583,11 +1583,6 @@ module ActiveRecord #:nodoc: end end - # Merges includes so that the result is a valid +include+ - def merge_includes(first, second) - (Array.wrap(first) + Array.wrap(second)).uniq - end - def build_association_joins(joins) join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, joins, nil) relation = active_relation.table diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index ed4218807d..f2de56ae5e 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -155,7 +155,8 @@ module ActiveRecord validate_calculation_options(options) options = options.except(:distinct) - includes = merge_includes(merge_with_relation ? merge_with_relation.includes_values : [], options[:include]) + merge_with_includes = merge_with_relation ? merge_with_relation.includes_values : [] + includes = (merge_with_includes + Array.wrap(options[:include])).uniq if includes.any? merge_with_joins = merge_with_relation ? merge_with_relation.joins_values : [] -- cgit v1.2.3 From 468cfcedd311a428339fa01e5f62b935f2995ec0 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 02:08:42 +0530 Subject: Improve the error message for class mismatch on Relation#merge --- activerecord/lib/active_record/relation/spawn_methods.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 33df8fd06c..f4abaae43e 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -15,7 +15,9 @@ module ActiveRecord end def merge(r) - raise ArgumentError, "Cannot merge a #{r.klass.name} relation with #{@klass.name} relation" if r.klass != @klass + if r.klass != @klass + raise ArgumentError, "Cannot merge a #{r.klass.name}(##{r.klass.object_id}) relation with #{@klass.name}(##{@klass.object_id}) relation" + end merged_relation = spawn.eager_load(r.eager_load_values).preload(r.preload_values).includes(r.includes_values) -- cgit v1.2.3 From cd90dcb1bde5c411a55bcec97597a8fe22b56a5d Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 02:59:42 +0530 Subject: Rename Model.active_relation to Model.unscoped --- activerecord/lib/active_record/associations.rb | 4 ++-- activerecord/lib/active_record/base.rb | 24 +++++++++++----------- activerecord/lib/active_record/calculations.rb | 4 ++-- .../lib/active_record/locking/optimistic.rb | 2 +- activerecord/lib/active_record/named_scope.rb | 2 +- .../active_record/relation/calculation_methods.rb | 4 ++-- .../lib/active_record/validations/uniqueness.rb | 2 +- 7 files changed, 21 insertions(+), 21 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index b52b298027..3034e9d237 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1703,7 +1703,7 @@ module ActiveRecord end def construct_finder_arel_with_included_associations(options, join_dependency) - relation = active_relation + relation = unscoped for association in join_dependency.join_associations relation = association.join_relation(relation) @@ -1754,7 +1754,7 @@ module ActiveRecord end def construct_finder_sql_for_association_limiting(options, join_dependency) - relation = active_relation + relation = unscoped for association in join_dependency.join_associations relation = association.join_relation(relation) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index bf42a5b221..b0c9ed2548 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -869,7 +869,7 @@ module ActiveRecord #:nodoc: # # Update all books that match our conditions, but limit it to 5 ordered by date # Book.update_all "author = 'David'", "title LIKE '%Rails%'", :order => 'created_at', :limit => 5 def update_all(updates, conditions = nil, options = {}) - relation = active_relation + relation = unscoped relation = relation.where(conditions) if conditions relation = relation.limit(options[:limit]) if options[:limit].present? @@ -1388,7 +1388,7 @@ module ActiveRecord #:nodoc: def reset_column_information undefine_attribute_methods @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @inheritance_column = nil - @arel_engine = @active_relation = nil + @arel_engine = @unscoped = nil end def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc: @@ -1501,9 +1501,9 @@ module ActiveRecord #:nodoc: "(#{segments.join(') AND (')})" unless segments.empty? end - def active_relation - @active_relation ||= Relation.new(self, arel_table) - finder_needs_type_condition? ? @active_relation.where(type_condition) : @active_relation + def unscoped + @unscoped ||= Relation.new(self, arel_table) + finder_needs_type_condition? ? @unscoped.where(type_condition) : @unscoped end def arel_table(table_name_alias = nil) @@ -1563,7 +1563,7 @@ module ActiveRecord #:nodoc: end def construct_finder_arel(options = {}, scope = nil) - relation = active_relation.apply_finder_options(options) + relation = unscoped.apply_finder_options(options) relation = scope.merge(relation) if scope relation end @@ -1585,7 +1585,7 @@ module ActiveRecord #:nodoc: def build_association_joins(joins) join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, joins, nil) - relation = active_relation.table + relation = unscoped.table join_dependency.join_associations.map { |association| if (association_relation = association.relation).is_a?(Array) [Arel::InnerJoin.new(relation, association_relation.first, *association.association_join.first).joins(relation), @@ -2193,7 +2193,7 @@ module ActiveRecord #:nodoc: # be made (since they can't be persisted). def destroy unless new_record? - self.class.active_relation.where(self.class.active_relation[self.class.primary_key].eq(id)).delete_all + self.class.unscoped.where(self.class.unscoped[self.class.primary_key].eq(id)).delete_all end @destroyed = true @@ -2480,7 +2480,7 @@ module ActiveRecord #:nodoc: def update(attribute_names = @attributes.keys) attributes_with_values = arel_attributes_values(false, false, attribute_names) return 0 if attributes_with_values.empty? - self.class.active_relation.where(self.class.active_relation[self.class.primary_key].eq(id)).update(attributes_with_values) + self.class.unscoped.where(self.class.unscoped[self.class.primary_key].eq(id)).update(attributes_with_values) end # Creates a record with values matching those of the instance attributes @@ -2493,9 +2493,9 @@ module ActiveRecord #:nodoc: attributes_values = arel_attributes_values new_id = if attributes_values.empty? - self.class.active_relation.insert connection.empty_insert_statement_value + self.class.unscoped.insert connection.empty_insert_statement_value else - self.class.active_relation.insert attributes_values + self.class.unscoped.insert attributes_values end self.id ||= new_id @@ -2590,7 +2590,7 @@ module ActiveRecord #:nodoc: if value && ((self.class.serialized_attributes.has_key?(name) && (value.acts_like?(:date) || value.acts_like?(:time))) || value.is_a?(Hash) || value.is_a?(Array)) value = value.to_yaml end - attrs[self.class.active_relation[name]] = value + attrs[self.class.unscoped[name]] = value end end end diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index f2de56ae5e..e4b3caab4e 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -164,7 +164,7 @@ module ActiveRecord join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, includes, construct_join(joins)) construct_calculation_arel_with_included_associations(options, join_dependency, merge_with_relation) else - relation = active_relation.apply_finder_options(options.slice(:joins, :conditions, :order, :limit, :offset, :group, :having)) + relation = unscoped.apply_finder_options(options.slice(:joins, :conditions, :order, :limit, :offset, :group, :having)) if merge_with_relation relation = merge_with_relation.except(:select, :order, :limit, :offset, :group, :from).merge(relation) @@ -182,7 +182,7 @@ module ActiveRecord end def construct_calculation_arel_with_included_associations(options, join_dependency, merge_with_relation = nil) - relation = active_relation + relation = unscoped for association in join_dependency.join_associations relation = association.join_relation(relation) diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index f9e538c586..9fcdabdb44 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -78,7 +78,7 @@ module ActiveRecord attribute_names.uniq! begin - relation = self.class.active_relation + relation = self.class.unscoped affected_rows = relation.where( relation[self.class.primary_key].eq(quoted_id).and( diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 531419fd8e..90fd700437 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -29,7 +29,7 @@ module ActiveRecord current_scope = current_scoped_methods unless current_scope - active_relation.spawn + unscoped.spawn else construct_finder_arel({}, current_scoped_methods) end diff --git a/activerecord/lib/active_record/relation/calculation_methods.rb b/activerecord/lib/active_record/relation/calculation_methods.rb index 2477481ec8..91de89e607 100644 --- a/activerecord/lib/active_record/relation/calculation_methods.rb +++ b/activerecord/lib/active_record/relation/calculation_methods.rb @@ -53,7 +53,7 @@ module ActiveRecord def execute_simple_calculation(operation, column_name, distinct) #:nodoc: column = if @klass.column_names.include?(column_name.to_s) - Arel::Attribute.new(@klass.active_relation, column_name) + Arel::Attribute.new(@klass.unscoped, column_name) else Arel::SqlLiteral.new(column_name == :all ? "*" : column_name.to_s) end @@ -77,7 +77,7 @@ module ActiveRecord select_statement = if operation == 'count' && column_name == :all "COUNT(*) AS count_all" else - Arel::Attribute.new(@klass.active_relation, column_name).send(operation).as(aggregate_alias).to_sql + Arel::Attribute.new(@klass.unscoped, column_name).send(operation).as(aggregate_alias).to_sql end select_statement << ", #{group_field} AS #{group_alias}" diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 4ff851dfa1..e28808df98 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -12,7 +12,7 @@ module ActiveRecord def validate_each(record, attribute, value) finder_class = find_finder_class_for(record) - table = finder_class.active_relation + table = finder_class.unscoped table_name = record.class.quoted_table_name sql, params = mount_sql_and_params(finder_class, table_name, attribute, value) -- cgit v1.2.3 From 0ab30637dd5bc7536c5accd66b45ce0263134a14 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 03:04:11 +0530 Subject: Revert "Fix #microseconds conversion and #fast_string_to_time" This reverts commit 717a2941e15b32d07cc456bb0d81742ecfc5b4a3. Bunch of failures when running postgresql tests. --- .../connection_adapters/abstract/schema_definitions.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'activerecord/lib') 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 5e8a01644d..520f3c8c0c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -13,7 +13,6 @@ module ActiveRecord 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/ - NEW_ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(?:\.(\d+))?\z/ end attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale @@ -168,11 +167,10 @@ module ActiveRecord end protected - # Rational(123456, 1_000_000) -> 123456 - # The sec_fraction component returned by Date._parse is a Rational fraction of a second or nil - # NB: This method is optimized for performance by immediately converting away from Rational. + # '0.123456' -> 123456 + # '1.123456' -> 123456 def microseconds(time) - ((time[:sec_fraction].to_f % 1) * 1_000_000).round + ((time[:sec_fraction].to_f % 1) * 1_000_000).to_i end def new_date(year, mon, mday) @@ -196,8 +194,9 @@ module ActiveRecord # Doesn't handle time zones. def fast_string_to_time(string) - if md = Format::NEW_ISO_DATETIME.match(string) - new_time *md.to_a[1..7].map(&:to_i) + if string =~ Format::ISO_DATETIME + microsec = ($7.to_f * 1_000_000).to_i + new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec end end -- cgit v1.2.3 From 6806483b913aba611af48c1630f229a76a98ecc7 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 03:10:07 +0530 Subject: Use arel_table[] instead of unscoped[] to get arel attribute --- activerecord/lib/active_record/base.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index b0c9ed2548..3c4a9fe99d 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2193,7 +2193,7 @@ module ActiveRecord #:nodoc: # be made (since they can't be persisted). def destroy unless new_record? - self.class.unscoped.where(self.class.unscoped[self.class.primary_key].eq(id)).delete_all + self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).delete_all end @destroyed = true @@ -2480,7 +2480,7 @@ module ActiveRecord #:nodoc: def update(attribute_names = @attributes.keys) attributes_with_values = arel_attributes_values(false, false, attribute_names) return 0 if attributes_with_values.empty? - self.class.unscoped.where(self.class.unscoped[self.class.primary_key].eq(id)).update(attributes_with_values) + self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).update(attributes_with_values) end # Creates a record with values matching those of the instance attributes @@ -2590,7 +2590,7 @@ module ActiveRecord #:nodoc: if value && ((self.class.serialized_attributes.has_key?(name) && (value.acts_like?(:date) || value.acts_like?(:time))) || value.is_a?(Hash) || value.is_a?(Array)) value = value.to_yaml end - attrs[self.class.unscoped[name]] = value + attrs[self.class.arel_table[name]] = value end end end -- cgit v1.2.3 From 6e3bee6cf1f0d2684152292db0a8b757249824fd Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 03:14:17 +0530 Subject: Cache Model.arel_table --- activerecord/lib/active_record/base.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 3c4a9fe99d..82e91a80ad 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1388,7 +1388,7 @@ module ActiveRecord #:nodoc: def reset_column_information undefine_attribute_methods @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @inheritance_column = nil - @arel_engine = @unscoped = nil + @arel_engine = @unscoped = @arel_table = nil end def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc: @@ -1506,8 +1506,8 @@ module ActiveRecord #:nodoc: finder_needs_type_condition? ? @unscoped.where(type_condition) : @unscoped end - def arel_table(table_name_alias = nil) - Arel::Table.new(table_name, :as => table_name_alias, :engine => arel_engine) + def arel_table + @arel_table ||= Arel::Table.new(table_name, :engine => arel_engine) end def arel_engine -- cgit v1.2.3 From dba196cb7f8d34b93f6872e4a43737bb52019065 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 03:26:20 +0530 Subject: Merge docrails --- activerecord/lib/active_record/associations.rb | 8 +++----- activerecord/lib/active_record/base.rb | 4 ++-- activerecord/lib/active_record/fixtures.rb | 3 +-- activerecord/lib/active_record/migration.rb | 3 ++- activerecord/lib/active_record/nested_attributes.rb | 10 +++++----- 5 files changed, 13 insertions(+), 15 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 3034e9d237..468a6cd9f8 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -774,13 +774,12 @@ module ActiveRecord # [collection.build(attributes = {}, ...)] # Returns one or more new objects of the collection type that have been instantiated # with +attributes+ and linked to this object through a foreign key, but have not yet - # been saved. Note: This only works if an associated object already exists, not if - # it's +nil+! + # been saved. # [collection.create(attributes = {})] # Returns a new object of the collection type that has been instantiated # with +attributes+, linked to this object through a foreign key, and that has already - # been saved (if it passed the validation). Note: This only works if an associated - # object already exists, not if it's +nil+! + # been saved (if it passed the validation). *Note*: This only works if the base model + # already exists in the DB, not if it is a new (unsaved) record! # # (*Note*: +collection+ is replaced with the symbol passed as the first argument, so # has_many :clients would add among others clients.empty?.) @@ -1040,7 +1039,6 @@ module ActiveRecord # A Post class declares belongs_to :author, which will add: # * Post#author (similar to Author.find(author_id)) # * Post#author=(author) (similar to post.author_id = author.id) - # * Post#author? (similar to post.author == some_author) # * Post#build_author (similar to post.author = Author.new) # * Post#create_author (similar to post.author = Author.new; post.author.save; post.author) # The declaration can also include an options hash to specialize the behavior of the association. diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 82e91a80ad..4ee9887186 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1724,10 +1724,10 @@ module ActiveRecord #:nodoc: # class Article < ActiveRecord::Base # def self.find_with_scope # with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do - # with_scope(:find => { :limit => 10 }) + # with_scope(:find => { :limit => 10 }) do # find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10 # end - # with_scope(:find => { :conditions => "author_id = 3" }) + # with_scope(:find => { :conditions => "author_id = 3" }) do # find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1 # end # end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index adc675966a..79f70f07cd 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -335,7 +335,6 @@ end # george: # id: 1 # name: George the Monkey -# pirate_id: 1 # # ### in fruits.yml # @@ -370,8 +369,8 @@ end # ### in monkeys.yml # # george: +# id: 1 # name: George the Monkey -# pirate: reginald # fruits: apple, orange, grape # # ### in fruits.yml diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index aeeed24881..c059b2d18b 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -1,7 +1,8 @@ require 'active_support/core_ext/object/metaclass' module ActiveRecord - class IrreversibleMigration < ActiveRecordError#:nodoc: + # Exception that can be raised to stop migrations from going backwards. + class IrreversibleMigration < ActiveRecordError end class DuplicateMigrationVersionError < ActiveRecordError#:nodoc: diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index f79a12a95c..d8fae495e7 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -49,14 +49,14 @@ module ActiveRecord # create the member and avatar in one go: # # params = { :member => { :name => 'Jack', :avatar_attributes => { :icon => 'smiling' } } } - # member = Member.create(params) + # member = Member.create(params[:member]) # member.avatar.id # => 2 # member.avatar.icon # => 'smiling' # # It also allows you to update the avatar through the member: # - # params = { :member' => { :avatar_attributes => { :id => '2', :icon => 'sad' } } } - # member.update_attributes params['member'] + # params = { :member => { :avatar_attributes => { :id => '2', :icon => 'sad' } } } + # member.update_attributes params[:member] # member.avatar.icon # => 'sad' # # By default you will only be able to set and update attributes on the @@ -75,7 +75,7 @@ module ActiveRecord # member.avatar_attributes = { :id => '2', :_destroy => '1' } # member.avatar.marked_for_destruction? # => true # member.save - # member.avatar #=> nil + # member.reload.avatar #=> nil # # Note that the model will _not_ be destroyed until the parent is saved. # @@ -179,7 +179,7 @@ module ActiveRecord # member.posts.detect { |p| p.id == 2 }.marked_for_destruction? # => true # member.posts.length #=> 2 # member.save - # member.posts.length # => 1 + # member.reload.posts.length # => 1 # # === Saving # -- cgit v1.2.3 From b8b6621acbc26a41421e9f9daded9b2a9ab82f1b Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 03:54:52 +0530 Subject: Simplify Model.scoped definition --- activerecord/lib/active_record/named_scope.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 90fd700437..bc04ffc089 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -26,13 +26,7 @@ module ActiveRecord if options.present? Scope.new(self, options, &block) else - current_scope = current_scoped_methods - - unless current_scope - unscoped.spawn - else - construct_finder_arel({}, current_scoped_methods) - end + current_scoped_methods ? unscoped.merge(current_scoped_methods) : unscoped.spawn end end -- cgit v1.2.3 From 7921a73acda62c3208b173858a40221cb33f9ff8 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 04:20:11 +0530 Subject: Use relations to build scope for named scopes --- activerecord/lib/active_record/named_scope.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index bc04ffc089..3f5cf68fd2 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -124,7 +124,7 @@ module ActiveRecord end end - delegate :scopes, :with_scope, :scoped_methods, :to => :proxy_scope + delegate :scopes, :with_scope, :scoped_methods, :unscoped, :to => :proxy_scope def initialize(proxy_scope, options, &block) options ||= {} @@ -186,6 +186,11 @@ module ActiveRecord end protected + + def relation + @relation ||= unscoped.apply_finder_options(proxy_options) + end + def proxy_found @found || load_found end @@ -195,7 +200,7 @@ module ActiveRecord if scopes.include?(method) scopes[method].call(self, *args) else - with_scope({:find => proxy_options, :create => proxy_options[:conditions].is_a?(Hash) ? proxy_options[:conditions] : {}}, :reverse_merge) do + with_scope(relation, :reverse_merge) do method = :new if method == :build if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) with_scope current_scoped_methods_when_defined do -- cgit v1.2.3 From 8d87c80c19b7f0c0966fcfd52e7a6ed99d347a36 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 04:25:59 +0530 Subject: Make Relation#reload force load the records immediately --- activerecord/lib/active_record/relation.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 85bf878416..7c2a080ead 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -124,12 +124,13 @@ module ActiveRecord end def reload - @loaded = false reset + to_a # force reload + self end def reset - @first = @last = @to_sql = @order_clause = @scope_for_create = @arel = nil + @first = @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil @records = [] self end -- cgit v1.2.3 From 54a043895f904e0237a590738d494554ec555265 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 14:16:50 +0530 Subject: Make merging of order values consistent --- activerecord/lib/active_record/relation/spawn_methods.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index f4abaae43e..953ea5ea1c 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -33,7 +33,7 @@ module ActiveRecord from(r.from_value). having(r.having_values) - merged_relation.order_values = Array.wrap(order_values) + Array.wrap(r.order_values) + merged_relation.order_values = r.order_values if r.order_values.present? merged_relation.create_with_value = @create_with_value -- cgit v1.2.3 From 27d9836ad3519d57462b86a4e539c1aa176b6d95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 17 Jan 2010 12:41:55 +0100 Subject: Add ActionDispatch::Railties::Subscriber and finish tidying up the logging. --- activerecord/lib/active_record/railties/subscriber.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/railties/subscriber.rb b/activerecord/lib/active_record/railties/subscriber.rb index 7c2a10cf0f..fd873dbff8 100644 --- a/activerecord/lib/active_record/railties/subscriber.rb +++ b/activerecord/lib/active_record/railties/subscriber.rb @@ -12,7 +12,7 @@ module ActiveRecord name = color(name, :magenta, true) end - debug "#{name} #{sql}" + debug " #{name} #{sql}" end def odd? -- cgit v1.2.3 From c0d31ca41b2f019d3bf940ac79f104c412b115bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 17 Jan 2010 14:22:27 +0100 Subject: save(false) is gone, use save(:validate => false) instead. --- .../associations/has_and_belongs_to_many_association.rb | 2 +- .../lib/active_record/associations/has_many_association.rb | 2 +- .../associations/has_many_through_association.rb | 2 +- activerecord/lib/active_record/autosave_association.rb | 10 +++++----- activerecord/lib/active_record/base.rb | 10 +++++----- activerecord/lib/active_record/transactions.rb | 4 ++-- activerecord/lib/active_record/validations.rb | 12 +++++++++++- 7 files changed, 26 insertions(+), 16 deletions(-) (limited to 'activerecord/lib') 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 bd05d1014c..7f39a189e4 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 if force record.save! else - return false unless record.save(validate) + return false unless record.save(:validate => validate) end end diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index d3336cf2d2..146a6ca55f 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -58,7 +58,7 @@ module ActiveRecord def insert_record(record, force = false, validate = true) set_belongs_to_association_for(record) - force ? record.save! : record.save(validate) + force ? record.save! : record.save(:validate => validate) end # Deletes the records according to the :dependent option. 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 387b85aacd..bd2acd4340 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -60,7 +60,7 @@ module ActiveRecord if force record.save! else - return false unless record.save(validate) + return false unless record.save(:validate => validate) end end diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index e178cb4ef2..325a8aa7ec 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -116,14 +116,14 @@ module ActiveRecord # post = Post.find(1) # post.author.name = '' # post.save # => false - # post.errors # => #["can't be blank"]}, @base=#> + # post.errors # => #["can't be blank"]}, @base=#> # # No validations will be performed on the associated models when validations # are skipped for the parent: # # post = Post.find(1) # post.author.name = '' - # post.save(false) # => true + # post.save(:validate => false) # => true module AutosaveAssociation extend ActiveSupport::Concern @@ -302,7 +302,7 @@ module ActiveRecord association.send(:insert_record, record) end elsif autosave - saved = record.save(false) + saved = record.save(:validate => false) end raise ActiveRecord::Rollback if saved == false @@ -332,7 +332,7 @@ module ActiveRecord key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id if autosave != false && (new_record? || association.new_record? || association[reflection.primary_key_name] != key || autosave) association[reflection.primary_key_name] = key - saved = association.save(!autosave) + saved = association.save(:validate => !autosave) raise ActiveRecord::Rollback if !saved && autosave saved end @@ -355,7 +355,7 @@ module ActiveRecord if autosave && association.marked_for_destruction? association.destroy elsif autosave != false - saved = association.save(!autosave) if association.new_record? || autosave + saved = association.save(:validate => !autosave) if association.new_record? || autosave if association.updated? association_id = association.send(reflection.options[:primary_key] || :id) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 4ee9887186..06244d1132 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2136,16 +2136,16 @@ module ActiveRecord #:nodoc: end # :call-seq: - # save(perform_validation = true) + # save(options) # # Saves the model. # # If the model is new a record gets created in the database, otherwise # the existing record gets updated. # - # If +perform_validation+ is true validations run. If any of them fail - # the action is cancelled and +save+ returns +false+. If the flag is - # false validations are bypassed altogether. See + # By default, save always run validations. If any of them fail the action + # is cancelled and +save+ returns +false+. However, if you supply + # :validate => false, validations are bypassed altogether. See # ActiveRecord::Validations for more information. # # There's a series of callbacks associated with +save+. If any of the @@ -2220,7 +2220,7 @@ module ActiveRecord #:nodoc: # in Base is replaced with this when the validations module is mixed in, which it is by default. def update_attribute(name, value) send(name.to_s + '=', value) - save(false) + save(:validate => false) end # Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 4f8ccdd40e..cf0fe8934d 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -192,8 +192,8 @@ module ActiveRecord with_transaction_returning_status(:destroy_without_transactions) end - def save_with_transactions(perform_validation = true) #:nodoc: - rollback_active_record_state! { with_transaction_returning_status(:save_without_transactions, perform_validation) } + def save_with_transactions(*args) #:nodoc: + rollback_active_record_state! { with_transaction_returning_status(:save_without_transactions, *args) } end def save_with_transactions! #:nodoc: diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index d5adcba3ba..a9743aa1ea 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -42,7 +42,17 @@ module ActiveRecord module InstanceMethods # The validation process on save can be skipped by passing false. The regular Base#save method is # replaced with this when the validations module is mixed in, which it is by default. - def save_with_validation(perform_validation = true) + def save_with_validation(options=nil) + perform_validation = case options + when NilClass + true + when Hash + options[:validate] != false + else + ActiveSupport::Deprecation.warn "save(#{options}) is deprecated, please give save(:validate => #{options}) instead", caller + options + end + if perform_validation && valid? || !perform_validation save_without_validation else -- cgit v1.2.3 From f0cde5be541e1f3877a15fb5d39c87a487a14381 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 21:34:26 +0530 Subject: Make sure named_scope names are not used as method names already --- activerecord/lib/active_record/named_scope.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 3f5cf68fd2..5a1cb7e769 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -99,6 +99,11 @@ module ActiveRecord # assert_equal expected_options, Shirt.colored('red').proxy_options def named_scope(name, options = {}, &block) name = name.to_sym + + if !scopes[name] && respond_to?(name, true) + raise ArgumentError, "Cannot define named_scope :#{name} because #{self.name}.#{name} method already exists." + end + scopes[name] = lambda do |parent_scope, *args| Scope.new(parent_scope, case options when Hash -- cgit v1.2.3 From dca3de3bc766175f49b56202246d3625c58fd763 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 Jan 2010 23:22:11 +0530 Subject: Make relations work as scopes --- activerecord/lib/active_record/named_scope.rb | 26 +++++++++++++++++----- .../lib/active_record/relation/spawn_methods.rb | 10 ++++++--- 2 files changed, 28 insertions(+), 8 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 5a1cb7e769..30e75534dd 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -106,7 +106,7 @@ module ActiveRecord scopes[name] = lambda do |parent_scope, *args| Scope.new(parent_scope, case options - when Hash + when Hash, Relation options when Proc options.call(*args) @@ -132,13 +132,21 @@ module ActiveRecord delegate :scopes, :with_scope, :scoped_methods, :unscoped, :to => :proxy_scope def initialize(proxy_scope, options, &block) - options ||= {} - [options[:extend]].flatten.each { |extension| extend extension } if options[:extend] extend Module.new(&block) if block_given? + + options ||= {} + if options.is_a?(Hash) + Array.wrap(options[:extend]).each {|extension| extend extension } + @proxy_options = options.except(:extend) + else + @proxy_options = options + end + unless Scope === proxy_scope @current_scoped_methods_when_defined = proxy_scope.send(:current_scoped_methods) end - @proxy_scope, @proxy_options = proxy_scope, options.except(:extend) + + @proxy_scope = proxy_scope end def reload @@ -193,7 +201,13 @@ module ActiveRecord protected def relation - @relation ||= unscoped.apply_finder_options(proxy_options) + @relation ||= begin + if proxy_options.is_a?(Hash) + unscoped.apply_finder_options(proxy_options) + else + unscoped.merge(proxy_options) + end + end end def proxy_found @@ -201,6 +215,7 @@ module ActiveRecord end private + def method_missing(method, *args, &block) if scopes.include?(method) scopes[method].call(self, *args) @@ -221,6 +236,7 @@ module ActiveRecord def load_found @found = find(:all) end + end end end diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 953ea5ea1c..2979f4b82d 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -19,7 +19,10 @@ module ActiveRecord raise ArgumentError, "Cannot merge a #{r.klass.name}(##{r.klass.object_id}) relation with #{@klass.name}(##{@klass.object_id}) relation" end - merged_relation = spawn.eager_load(r.eager_load_values).preload(r.preload_values).includes(r.includes_values) + merged_relation = spawn + return merged_relation unless r + + merged_relation = merged_relation.eager_load(r.eager_load_values).preload(r.preload_values).includes(r.includes_values) merged_relation.readonly_value = r.readonly_value unless r.readonly_value.nil? merged_relation.limit_value = r.limit_value if r.limit_value.present? @@ -94,9 +97,10 @@ module ActiveRecord :order, :select, :readonly, :group, :having, :from, :lock ] def apply_finder_options(options) - options.assert_valid_keys(VALID_FIND_OPTIONS) - relation = spawn + return relation unless options + + options.assert_valid_keys(VALID_FIND_OPTIONS) relation = relation.joins(options[:joins]). where(options[:conditions]). -- cgit v1.2.3 From c6850d8361bbf288cf3adefd087cb9a4bc9c97bc Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 00:03:18 +0530 Subject: Ensure that Scope#proxy_scope is always klass. Rename proxy_scope to klass too. --- activerecord/lib/active_record/named_scope.rb | 38 +++++++++++---------------- activerecord/lib/active_record/relation.rb | 2 ++ 2 files changed, 18 insertions(+), 22 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 30e75534dd..9e65fb4ca5 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -121,7 +121,7 @@ module ActiveRecord end class Scope - attr_reader :proxy_scope, :proxy_options, :current_scoped_methods_when_defined + attr_reader :klass, :proxy_options, :current_scoped_methods_when_defined NON_DELEGATE_METHODS = %w(nil? send object_id class extend find size count sum average maximum minimum paginate first last empty? any? many? respond_to?).to_set [].methods.each do |m| unless m =~ /^__/ || NON_DELEGATE_METHODS.include?(m.to_s) @@ -129,9 +129,10 @@ module ActiveRecord end end - delegate :scopes, :with_scope, :scoped_methods, :unscoped, :to => :proxy_scope + delegate :scopes, :with_scope, :with_exclusive_scope, :scoped_methods, :scoped, :to => :klass + delegate :new, :build, :all, :to => :relation - def initialize(proxy_scope, options, &block) + def initialize(klass, options, &block) extend Module.new(&block) if block_given? options ||= {} @@ -142,11 +143,11 @@ module ActiveRecord @proxy_options = options end - unless Scope === proxy_scope - @current_scoped_methods_when_defined = proxy_scope.send(:current_scoped_methods) + unless Scope === klass + @current_scoped_methods_when_defined = klass.send(:current_scoped_methods) end - @proxy_scope = proxy_scope + @klass = klass end def reload @@ -178,7 +179,7 @@ module ActiveRecord end def respond_to?(method, include_private = false) - super || @proxy_scope.respond_to?(method, include_private) + super || @klass.respond_to?(method, include_private) end def any? @@ -198,14 +199,12 @@ module ActiveRecord end end - protected - def relation @relation ||= begin if proxy_options.is_a?(Hash) - unscoped.apply_finder_options(proxy_options) + scoped.apply_finder_options(proxy_options) else - unscoped.merge(proxy_options) + scoped.merge(proxy_options) end end end @@ -217,18 +216,13 @@ module ActiveRecord private def method_missing(method, *args, &block) - if scopes.include?(method) - scopes[method].call(self, *args) - else - with_scope(relation, :reverse_merge) do - method = :new if method == :build - if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) - with_scope current_scoped_methods_when_defined do - proxy_scope.send(method, *args, &block) - end - else - proxy_scope.send(method, *args, &block) + with_scope(relation, :reverse_merge) do + if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) && !scopes.include?(method) + with_scope current_scoped_methods_when_defined do + klass.send(method, *args, &block) end + else + klass.send(method, *args, &block) end end end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 7c2a080ead..fc429486e4 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -20,6 +20,8 @@ module ActiveRecord with_create_scope { @klass.new(*args, &block) } end + alias build new + def create(*args, &block) with_create_scope { @klass.create(*args, &block) } end -- cgit v1.2.3 From 88de6b2de2606e141483ff90323c5f3ec0cfb298 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 04:24:24 +0530 Subject: Inherit named scope class Scope from Relation --- .../associations/association_collection.rb | 2 - activerecord/lib/active_record/named_scope.rb | 118 ++++++++------------- activerecord/lib/active_record/relation.rb | 4 +- .../active_record/relation/predicate_builder.rb | 2 +- .../lib/active_record/relation/spawn_methods.rb | 6 +- 5 files changed, 49 insertions(+), 83 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 64dd5cf629..e9402d3547 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -403,8 +403,6 @@ module ActiveRecord else super end - elsif @reflection.klass.scopes.include?(method) - @reflection.klass.scopes[method].call(self, *args) else with_scope(construct_scope) do if block_given? diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 9e65fb4ca5..16fde1ffb8 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -24,7 +24,7 @@ module ActiveRecord # You can define a scope that applies to all finders using ActiveRecord::Base.default_scope. def scoped(options = {}, &block) if options.present? - Scope.new(self, options, &block) + Scope.init(self, options, &block) else current_scoped_methods ? unscoped.merge(current_scoped_methods) : unscoped.spawn end @@ -105,7 +105,7 @@ module ActiveRecord end scopes[name] = lambda do |parent_scope, *args| - Scope.new(parent_scope, case options + Scope.init(parent_scope, case options when Hash, Relation options when Proc @@ -120,117 +120,83 @@ module ActiveRecord end end - class Scope - attr_reader :klass, :proxy_options, :current_scoped_methods_when_defined - NON_DELEGATE_METHODS = %w(nil? send object_id class extend find size count sum average maximum minimum paginate first last empty? any? many? respond_to?).to_set - [].methods.each do |m| - unless m =~ /^__/ || NON_DELEGATE_METHODS.include?(m.to_s) - delegate m, :to => :proxy_found - end - end + class Scope < Relation + attr_accessor :current_scoped_methods_when_defined delegate :scopes, :with_scope, :with_exclusive_scope, :scoped_methods, :scoped, :to => :klass - delegate :new, :build, :all, :to => :relation - def initialize(klass, options, &block) - extend Module.new(&block) if block_given? + def self.init(klass, options, &block) + relation = new(klass, klass.arel_table) - options ||= {} - if options.is_a?(Hash) - Array.wrap(options[:extend]).each {|extension| extend extension } - @proxy_options = options.except(:extend) + scope = if options.is_a?(Hash) + klass.scoped.apply_finder_options(options.except(:extend)) else - @proxy_options = options + options ? klass.scoped.merge(options) : klass.scoped end - unless Scope === klass - @current_scoped_methods_when_defined = klass.send(:current_scoped_methods) - end + relation = relation.merge(scope) - @klass = klass - end + Array.wrap(options[:extend]).each {|extension| relation.send(:extend, extension) } if options.is_a?(Hash) + relation.send(:extend, Module.new(&block)) if block_given? - def reload - load_found; self + relation.current_scoped_methods_when_defined = klass.send(:current_scoped_methods) + relation end - def first(*args) - if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) - proxy_found.first(*args) - else - find(:first, *args) - end - end + def find(*args) + options = args.extract_options! + relation = options.present? ? apply_finder_options(options) : self - def last(*args) - if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) - proxy_found.last(*args) + case args.first + when :first, :last, :all + relation.send(args.first) else - find(:last, *args) + options.present? ? relation.find(*args) : super end end - def size - @found ? @found.length : count - end - - def empty? - @found ? @found.empty? : count.zero? - end - - def respond_to?(method, include_private = false) - super || @klass.respond_to?(method, include_private) - end - - def any? - if block_given? - proxy_found.any? { |*block_args| yield(*block_args) } + def first(*args) + if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash)) + to_a.first(*args) else - !empty? + args.first.present? ? apply_finder_options(args.first).first : super end end - # Returns true if the named scope has more than 1 matching record. - def many? - if block_given? - proxy_found.many? { |*block_args| yield(*block_args) } + def last(*args) + if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash)) + to_a.last(*args) else - size > 1 + args.first.present? ? apply_finder_options(args.first).last : super end end - def relation - @relation ||= begin - if proxy_options.is_a?(Hash) - scoped.apply_finder_options(proxy_options) - else - scoped.merge(proxy_options) - end - end + def count(*args) + options = args.extract_options! + options.present? ? apply_finder_options(options).count(*args) : super end - def proxy_found - @found || load_found + def ==(other) + to_a == other.to_a end private def method_missing(method, *args, &block) - with_scope(relation, :reverse_merge) do - if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) && !scopes.include?(method) - with_scope current_scoped_methods_when_defined do + if klass.respond_to?(method) + with_scope(self) do + if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) && !scopes.include?(method) + with_scope(current_scoped_methods_when_defined) { klass.send(method, *args, &block) } + else klass.send(method, *args, &block) end - else - klass.send(method, *args, &block) end + else + super end end - def load_found - @found = find(:all) - end - end + end end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index fc429486e4..1d6fced952 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -7,7 +7,7 @@ module ActiveRecord include FinderMethods, CalculationMethods, SpawnMethods, QueryMethods - delegate :length, :collect, :map, :each, :all?, :to => :to_a + delegate :length, :collect, :map, :each, :all?, :include?, :to => :to_a attr_reader :table, :klass @@ -175,6 +175,8 @@ module ActiveRecord end end + private + def with_create_scope @klass.send(:with_scope, :create => scope_for_create, :find => {}) { yield } end diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 6b7d941350..03f194c462 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -24,7 +24,7 @@ module ActiveRecord case value when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope - attribute.in(value) + attribute.in(value.to_a) when Range # TODO : Arel should handle ranges with excluded end. if value.exclude_end? diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 2979f4b82d..4ac9e50f5a 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -1,7 +1,7 @@ module ActiveRecord module SpawnMethods def spawn(arel_table = self.table) - relation = Relation.new(@klass, arel_table) + relation = self.class.new(@klass, arel_table) (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).each do |query_method| relation.send(:"#{query_method}_values=", send(:"#{query_method}_values")) @@ -64,7 +64,7 @@ module ActiveRecord alias :& :merge def except(*skips) - result = Relation.new(@klass, table) + result = self.class.new(@klass, table) (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).each do |method| result.send(:"#{method}_values=", send(:"#{method}_values")) unless skips.include?(method) @@ -78,7 +78,7 @@ module ActiveRecord end def only(*onlies) - result = Relation.new(@klass, table) + result = self.class.new(@klass, table) onlies.each do |only| if (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).include?(only) -- cgit v1.2.3 From e1d507c7fb541d29d57d152f40e3a539e70781d0 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 04:28:21 +0530 Subject: Dont check for class equaity when merging relations --- activerecord/lib/active_record/relation/spawn_methods.rb | 4 ---- 1 file changed, 4 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 4ac9e50f5a..d5b13c6100 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -15,10 +15,6 @@ module ActiveRecord end def merge(r) - if r.klass != @klass - raise ArgumentError, "Cannot merge a #{r.klass.name}(##{r.klass.object_id}) relation with #{@klass.name}(##{@klass.object_id}) relation" - end - merged_relation = spawn return merged_relation unless r -- cgit v1.2.3 From d60bb0a9e4be2ac0a9de9a69041a4ddc2e0cc914 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 04:38:19 +0530 Subject: Rename named_scope to scope --- activerecord/lib/active_record/named_scope.rb | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 16fde1ffb8..42fc6c5f28 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -38,11 +38,11 @@ module ActiveRecord # such as :conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions. # # class Shirt < ActiveRecord::Base - # named_scope :red, :conditions => {:color => 'red'} - # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] + # scope :red, :conditions => {:color => 'red'} + # scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] # end # - # The above calls to named_scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, + # The above calls to scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, # in effect, represents the query Shirt.find(:all, :conditions => {:color => 'red'}). # # Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it resembles the association object @@ -68,7 +68,7 @@ module ActiveRecord # Named \scopes can also be procedural: # # class Shirt < ActiveRecord::Base - # named_scope :colored, lambda { |color| + # scope :colored, lambda { |color| # { :conditions => { :color => color } } # } # end @@ -78,7 +78,7 @@ module ActiveRecord # Named \scopes can also have extensions, just as with has_many declarations: # # class Shirt < ActiveRecord::Base - # named_scope :red, :conditions => {:color => 'red'} do + # scope :red, :conditions => {:color => 'red'} do # def dom_id # 'red_shirts' # end @@ -90,14 +90,14 @@ module ActiveRecord # proxy_options method on the proxy itself. # # class Shirt < ActiveRecord::Base - # named_scope :colored, lambda { |color| + # scope :colored, lambda { |color| # { :conditions => { :color => color } } # } # end # # expected_options = { :conditions => { :colored => 'red' } } # assert_equal expected_options, Shirt.colored('red').proxy_options - def named_scope(name, options = {}, &block) + def scope(name, options = {}, &block) name = name.to_sym if !scopes[name] && respond_to?(name, true) @@ -118,6 +118,11 @@ module ActiveRecord end end end + + def named_scope(*args, &block) + ActiveSupport::Deprecation.warn("Base#named_scope has been deprecated, please use Base.scope instead.", caller) + scope(*args, &block) + end end class Scope < Relation -- cgit v1.2.3 From 40c4a0036a690b2e0e3157520f1851efc77fbef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 18 Jan 2010 09:56:36 +0100 Subject: Ensure deprecated validate methods are invoked when they are private [#3214 status:resolved] --- activerecord/lib/active_record/callbacks.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index aecde5848c..1128286f2b 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -291,7 +291,7 @@ module ActiveRecord end def deprecated_callback_method(symbol) #:nodoc: - if respond_to?(symbol) + if respond_to?(symbol, true) ActiveSupport::Deprecation.warn("Overwriting #{symbol} in your models has been deprecated, please use Base##{symbol} :method_name instead") send(symbol) end -- cgit v1.2.3 From 8ba2902dd4c3e9a3715130c499d78c4fc79fbf16 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 12:32:15 +0530 Subject: Fix the named_scope deprecation notice --- activerecord/lib/active_record/named_scope.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 42fc6c5f28..5c0cf10f4c 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -120,7 +120,7 @@ module ActiveRecord end def named_scope(*args, &block) - ActiveSupport::Deprecation.warn("Base#named_scope has been deprecated, please use Base.scope instead.", caller) + ActiveSupport::Deprecation.warn("Base.named_scope has been deprecated, please use Base.scope instead.", caller) scope(*args, &block) end end -- cgit v1.2.3 From 8bb527464845071ee72bcbcddcf860d4af1eda32 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 12:50:20 +0530 Subject: Get rid of Relation#order_clauses --- activerecord/lib/active_record/relation.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 1d6fced952..4ed118b02d 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -50,14 +50,14 @@ module ActiveRecord @records = if find_with_associations begin options = { - :select => @select_values.any? ? @select_values.join(", ") : nil, + :select => @select_values.join(", "), :joins => arel.joins(arel), - :group => @group_values.any? ? @group_values.join(", ") : nil, - :order => order_clause, + :group => @group_values.join(", "), + :order => @order_values.join(', '), :conditions => where_clause, - :limit => arel.taken, - :offset => arel.skipped, - :from => (arel.send(:from_clauses) if arel.send(:sources).present?) + :limit => @limit_value, + :offset => @offset_value, + :from => @from_value } including = (@eager_load_values + @includes_values).uniq @@ -185,10 +185,6 @@ module ActiveRecord arel.send(:where_clauses).join(join_string) end - def order_clause - @order_clause ||= arel.send(:order_clauses).join(', ') - end - def references_eager_loaded_tables? joined_tables = (tables_in_string(arel.joins(arel)) + [table.name, table.table_alias]).compact.uniq (tables_in_string(to_sql) - joined_tables).any? -- cgit v1.2.3 From 2a2bc8e84aa619089abcc4f9a4c2711a118e5fa9 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 12:55:23 +0530 Subject: Handle invalid query IN() generated when a blank array is supplied in hash conditions --- activerecord/lib/active_record/relation/predicate_builder.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 03f194c462..9e855209f9 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -24,7 +24,8 @@ module ActiveRecord case value when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope - attribute.in(value.to_a) + values = value.to_a + values.any? ? attribute.in(values) : attribute.eq(nil) when Range # TODO : Arel should handle ranges with excluded end. if value.exclude_end? -- cgit v1.2.3 From 4c00c65c58055b341b4ca59a38c3c93082049c84 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 19:16:20 +0530 Subject: Simplify construct_finder_arel_* methods --- activerecord/lib/active_record/associations.rb | 34 ++++++-------------------- 1 file changed, 7 insertions(+), 27 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 468a6cd9f8..ebf1a41e85 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1701,30 +1701,19 @@ module ActiveRecord end def construct_finder_arel_with_included_associations(options, join_dependency) - relation = unscoped + relation = scoped for association in join_dependency.join_associations relation = association.join_relation(relation) end - relation = relation.joins(options[:joins]). - select(column_aliases(join_dependency)). - group(options[:group]). - having(options[:having]). - order(options[:order]). - where(options[:conditions]). - from(options[:from]) + relation = relation.apply_finder_options(options).select(column_aliases(join_dependency)) - scoped_relation = current_scoped_methods - scoped_relation_limit = scoped_relation.taken if scoped_relation - - relation = current_scoped_methods.except(:limit).merge(relation) if current_scoped_methods - - if !using_limitable_reflections?(join_dependency.reflections) && ((scoped_relation && scoped_relation.taken) || options[:limit]) + if !using_limitable_reflections?(join_dependency.reflections) && relation.limit_value relation = relation.where(construct_arel_limited_ids_condition(options, join_dependency)) end - relation = relation.limit(options[:limit] || scoped_relation_limit) if using_limitable_reflections?(join_dependency.reflections) + relation = relation.except(:limit, :offset) unless using_limitable_reflections?(join_dependency.reflections) relation end @@ -1752,23 +1741,14 @@ module ActiveRecord end def construct_finder_sql_for_association_limiting(options, join_dependency) - relation = unscoped + relation = scoped for association in join_dependency.join_associations relation = association.join_relation(relation) end - relation = relation.joins(options[:joins]). - where(options[:conditions]). - group(options[:group]). - having(options[:having]). - order(options[:order]). - limit(options[:limit]). - offset(options[:offset]). - from(options[:from]) - - relation = current_scoped_methods.except(:select, :includes, :eager_load).merge(relation) if current_scoped_methods - relation = relation.select(connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", options[:order])) + relation = relation.apply_finder_options(options).except(:select) + relation = relation.select(connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", relation.order_values.join(", "))) relation.to_sql end -- cgit v1.2.3 From 9fffdc5cdb80b1824473a6d7ae1fedf9e74aa748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 18 Jan 2010 13:44:32 +0100 Subject: Generators load path now will be Ruby load path. If you want to use rspec:install generator, you need generators/rspec/install_generator in your load path. --- activerecord/lib/generators/active_record.rb | 31 ++++++++++++++++++++ .../active_record/migration/migration_generator.rb | 25 ++++++++++++++++ .../active_record/migration/templates/migration.rb | 11 ++++++++ .../active_record/model/model_generator.rb | 33 ++++++++++++++++++++++ .../active_record/model/templates/migration.rb | 16 +++++++++++ .../active_record/model/templates/model.rb | 5 ++++ .../active_record/observer/observer_generator.rb | 15 ++++++++++ .../active_record/observer/templates/observer.rb | 2 ++ .../session_migration_generator.rb | 24 ++++++++++++++++ .../session_migration/templates/migration.rb | 16 +++++++++++ 10 files changed, 178 insertions(+) create mode 100644 activerecord/lib/generators/active_record.rb create mode 100644 activerecord/lib/generators/active_record/migration/migration_generator.rb create mode 100644 activerecord/lib/generators/active_record/migration/templates/migration.rb create mode 100644 activerecord/lib/generators/active_record/model/model_generator.rb create mode 100644 activerecord/lib/generators/active_record/model/templates/migration.rb create mode 100644 activerecord/lib/generators/active_record/model/templates/model.rb create mode 100644 activerecord/lib/generators/active_record/observer/observer_generator.rb create mode 100644 activerecord/lib/generators/active_record/observer/templates/observer.rb create mode 100644 activerecord/lib/generators/active_record/session_migration/session_migration_generator.rb create mode 100644 activerecord/lib/generators/active_record/session_migration/templates/migration.rb (limited to 'activerecord/lib') diff --git a/activerecord/lib/generators/active_record.rb b/activerecord/lib/generators/active_record.rb new file mode 100644 index 0000000000..25b982f296 --- /dev/null +++ b/activerecord/lib/generators/active_record.rb @@ -0,0 +1,31 @@ +require 'rails/generators/named_base' +require 'rails/generators/migration' +require 'rails/generators/active_model' +require 'active_record' + +module ActiveRecord + module Generators + class Base < Rails::Generators::NamedBase #:nodoc: + include Rails::Generators::Migration + + def self.source_root + @_ar_source_root ||= begin + if base_name && generator_name + File.expand_path(File.join(base_name, generator_name, 'templates'), File.dirname(__FILE__)) + end + end + end + + protected + # Implement the required interface for Rails::Generators::Migration. + # + def next_migration_number(dirname) #:nodoc: + if ActiveRecord::Base.timestamped_migrations + Time.now.utc.strftime("%Y%m%d%H%M%S") + else + "%.3d" % (current_migration_number(dirname) + 1) + end + end + end + end +end diff --git a/activerecord/lib/generators/active_record/migration/migration_generator.rb b/activerecord/lib/generators/active_record/migration/migration_generator.rb new file mode 100644 index 0000000000..7939977f72 --- /dev/null +++ b/activerecord/lib/generators/active_record/migration/migration_generator.rb @@ -0,0 +1,25 @@ +require 'generators/active_record' + +module ActiveRecord + module Generators + class MigrationGenerator < Base + argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + + def create_migration_file + set_local_assigns! + migration_template "migration.rb", "db/migrate/#{file_name}.rb" + end + + protected + attr_reader :migration_action + + def set_local_assigns! + if file_name =~ /^(add|remove)_.*_(?:to|from)_(.*)/ + @migration_action = $1 + @table_name = $2.pluralize + end + end + + end + end +end diff --git a/activerecord/lib/generators/active_record/migration/templates/migration.rb b/activerecord/lib/generators/active_record/migration/templates/migration.rb new file mode 100644 index 0000000000..bbb7c53d86 --- /dev/null +++ b/activerecord/lib/generators/active_record/migration/templates/migration.rb @@ -0,0 +1,11 @@ +class <%= migration_class_name %> < ActiveRecord::Migration + def self.up<% attributes.each do |attribute| %> + <%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end -%> + <%- end %> + end + + def self.down<% attributes.reverse.each do |attribute| %> + <%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end -%> + <%- end %> + end +end diff --git a/activerecord/lib/generators/active_record/model/model_generator.rb b/activerecord/lib/generators/active_record/model/model_generator.rb new file mode 100644 index 0000000000..2641083e0d --- /dev/null +++ b/activerecord/lib/generators/active_record/model/model_generator.rb @@ -0,0 +1,33 @@ +require 'generators/active_record' + +module ActiveRecord + module Generators + class ModelGenerator < Base + argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + + check_class_collision + + class_option :migration, :type => :boolean + class_option :timestamps, :type => :boolean + class_option :parent, :type => :string, :desc => "The parent class for the generated model" + + def create_migration_file + return unless options[:migration] && options[:parent].nil? + migration_template "migration.rb", "db/migrate/create_#{table_name}.rb" + end + + def create_model_file + template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb") + end + + hook_for :test_framework + + protected + + def parent_class_name + options[:parent] || "ActiveRecord::Base" + end + + end + end +end diff --git a/activerecord/lib/generators/active_record/model/templates/migration.rb b/activerecord/lib/generators/active_record/model/templates/migration.rb new file mode 100644 index 0000000000..1f68487304 --- /dev/null +++ b/activerecord/lib/generators/active_record/model/templates/migration.rb @@ -0,0 +1,16 @@ +class <%= migration_class_name %> < ActiveRecord::Migration + def self.up + create_table :<%= table_name %> do |t| +<% for attribute in attributes -%> + t.<%= attribute.type %> :<%= attribute.name %> +<% end -%> +<% if options[:timestamps] %> + t.timestamps +<% end -%> + end + end + + def self.down + drop_table :<%= table_name %> + end +end diff --git a/activerecord/lib/generators/active_record/model/templates/model.rb b/activerecord/lib/generators/active_record/model/templates/model.rb new file mode 100644 index 0000000000..21ae29e9f2 --- /dev/null +++ b/activerecord/lib/generators/active_record/model/templates/model.rb @@ -0,0 +1,5 @@ +class <%= class_name %> < <%= parent_class_name.classify %> +<% attributes.select {|attr| attr.reference? }.each do |attribute| -%> + belongs_to :<%= attribute.name %> +<% end -%> +end diff --git a/activerecord/lib/generators/active_record/observer/observer_generator.rb b/activerecord/lib/generators/active_record/observer/observer_generator.rb new file mode 100644 index 0000000000..a6b57423b8 --- /dev/null +++ b/activerecord/lib/generators/active_record/observer/observer_generator.rb @@ -0,0 +1,15 @@ +require 'generators/active_record' + +module ActiveRecord + module Generators + class ObserverGenerator < Base + check_class_collision :suffix => "Observer" + + def create_observer_file + template 'observer.rb', File.join('app/models', class_path, "#{file_name}_observer.rb") + end + + hook_for :test_framework + end + end +end diff --git a/activerecord/lib/generators/active_record/observer/templates/observer.rb b/activerecord/lib/generators/active_record/observer/templates/observer.rb new file mode 100644 index 0000000000..b9a3004161 --- /dev/null +++ b/activerecord/lib/generators/active_record/observer/templates/observer.rb @@ -0,0 +1,2 @@ +class <%= class_name %>Observer < ActiveRecord::Observer +end diff --git a/activerecord/lib/generators/active_record/session_migration/session_migration_generator.rb b/activerecord/lib/generators/active_record/session_migration/session_migration_generator.rb new file mode 100644 index 0000000000..59c4792066 --- /dev/null +++ b/activerecord/lib/generators/active_record/session_migration/session_migration_generator.rb @@ -0,0 +1,24 @@ +require 'generators/active_record' + +module ActiveRecord + module Generators + class SessionMigrationGenerator < Base + argument :name, :type => :string, :default => "add_sessions_table" + + def create_migration_file + migration_template "migration.rb", "db/migrate/#{file_name}.rb" + end + + protected + + def session_table_name + current_table_name = ActiveRecord::SessionStore::Session.table_name + if ["sessions", "session"].include?(current_table_name) + current_table_name = (ActiveRecord::Base.pluralize_table_names ? 'session'.pluralize : 'session') + end + current_table_name + end + + end + end +end diff --git a/activerecord/lib/generators/active_record/session_migration/templates/migration.rb b/activerecord/lib/generators/active_record/session_migration/templates/migration.rb new file mode 100644 index 0000000000..919822af7b --- /dev/null +++ b/activerecord/lib/generators/active_record/session_migration/templates/migration.rb @@ -0,0 +1,16 @@ +class <%= migration_class_name %> < ActiveRecord::Migration + def self.up + create_table :<%= session_table_name %> do |t| + t.string :session_id, :null => false + t.text :data + t.timestamps + end + + add_index :<%= session_table_name %>, :session_id + add_index :<%= session_table_name %>, :updated_at + end + + def self.down + drop_table :<%= session_table_name %> + end +end -- cgit v1.2.3 From e27bfad6a5f9e9171148226dee7ce51d41731ea7 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Mon, 18 Jan 2010 08:45:24 +0100 Subject: Forgot to change named_scope to scope in an ArgumentError raise exception for duplication scopes related to commit d60bb0a9e4be [#3736 status:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/lib/active_record/named_scope.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 5c0cf10f4c..2d88f49f5f 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -101,7 +101,7 @@ module ActiveRecord name = name.to_sym if !scopes[name] && respond_to?(name, true) - raise ArgumentError, "Cannot define named_scope :#{name} because #{self.name}.#{name} method already exists." + raise ArgumentError, "Cannot define scope :#{name} because #{self.name}.#{name} method already exists." end scopes[name] = lambda do |parent_scope, *args| -- cgit v1.2.3 From 68b76a38eb83db8515336ec2e7fd8191798386be Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 18 Jan 2010 09:49:05 -0600 Subject: Cleanup deprecation notices. --- activerecord/lib/active_record/named_scope.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 2d88f49f5f..92030e5bfd 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -9,7 +9,7 @@ module ActiveRecord module ClassMethods # Returns a relation if invoked without any arguments. # - # posts = Post.scoped + # posts = Post.scoped # posts.size # Fires "select count(*) from posts" and returns the count # posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects # @@ -41,8 +41,8 @@ module ActiveRecord # scope :red, :conditions => {:color => 'red'} # scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] # end - # - # The above calls to scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, + # + # The above calls to scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, # in effect, represents the query Shirt.find(:all, :conditions => {:color => 'red'}). # # Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it resembles the association object @@ -120,7 +120,7 @@ module ActiveRecord end def named_scope(*args, &block) - ActiveSupport::Deprecation.warn("Base.named_scope has been deprecated, please use Base.scope instead.", caller) + ActiveSupport::Deprecation.warn("Base.named_scope has been deprecated, please use Base.scope instead", caller) scope(*args, &block) end end -- cgit v1.2.3 From 728db5a932a1a185e6c366f1671e0b1f81d7b027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 18 Jan 2010 18:22:55 +0100 Subject: Rake tasks should load generators from new paths. --- activerecord/lib/active_record/railties/databases.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index b39e064e45..88974dd786 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -428,7 +428,7 @@ namespace :db do task :create => :environment do raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations? require 'rails/generators' - require 'rails/generators/rails/session_migration/session_migration_generator' + require 'generators/rails/session_migration/session_migration_generator' Rails::Generators::SessionMigrationGenerator.start [ ENV["MIGRATION"] || "add_sessions_table" ] end -- cgit v1.2.3 From 893524382a54ac9f65c49f08759d47ca5049b381 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 21:38:22 +0530 Subject: No need to pass current_scoped_methods to construct_calculation_arel everytime --- activerecord/lib/active_record/calculations.rb | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index e4b3caab4e..051f22db85 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -46,19 +46,19 @@ module ActiveRecord def count(*args) case args.size when 0 - construct_calculation_arel({}, current_scoped_methods).count + construct_calculation_arel.count when 1 if args[0].is_a?(Hash) options = args[0] distinct = options.has_key?(:distinct) ? options.delete(:distinct) : false - construct_calculation_arel(options, current_scoped_methods).count(options[:select], :distinct => distinct) + construct_calculation_arel(options).count(options[:select], :distinct => distinct) else - construct_calculation_arel({}, current_scoped_methods).count(args[0]) + construct_calculation_arel.count(args[0]) end when 2 column_name, options = args distinct = options.has_key?(:distinct) ? options.delete(:distinct) : false - construct_calculation_arel(options, current_scoped_methods).count(column_name, :distinct => distinct) + construct_calculation_arel(options).count(column_name, :distinct => distinct) else raise ArgumentError, "Unexpected parameters passed to count(): #{args.inspect}" end @@ -141,7 +141,7 @@ module ActiveRecord # Person.minimum(:age, :having => 'min(age) > 17', :group => :last_name) # Selects the minimum age for any family without any minors # Person.sum("2 * age") def calculate(operation, column_name, options = {}) - construct_calculation_arel(options, current_scoped_methods).calculate(operation, column_name, options.slice(:distinct)) + construct_calculation_arel(options).calculate(operation, column_name, options.slice(:distinct)) rescue ThrowResult 0 end @@ -151,48 +151,48 @@ module ActiveRecord options.assert_valid_keys(CALCULATIONS_OPTIONS) end - def construct_calculation_arel(options = {}, merge_with_relation = nil) + def construct_calculation_arel(options = {}) validate_calculation_options(options) options = options.except(:distinct) - merge_with_includes = merge_with_relation ? merge_with_relation.includes_values : [] + merge_with_includes = current_scoped_methods ? current_scoped_methods.includes_values : [] includes = (merge_with_includes + Array.wrap(options[:include])).uniq if includes.any? - merge_with_joins = merge_with_relation ? merge_with_relation.joins_values : [] + merge_with_joins = current_scoped_methods ? current_scoped_methods.joins_values : [] joins = (merge_with_joins + Array.wrap(options[:joins])).uniq join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, includes, construct_join(joins)) - construct_calculation_arel_with_included_associations(options, join_dependency, merge_with_relation) + construct_calculation_arel_with_included_associations(options, join_dependency) else relation = unscoped.apply_finder_options(options.slice(:joins, :conditions, :order, :limit, :offset, :group, :having)) - if merge_with_relation - relation = merge_with_relation.except(:select, :order, :limit, :offset, :group, :from).merge(relation) + if current_scoped_methods + relation = current_scoped_methods.except(:select, :order, :limit, :offset, :group, :from).merge(relation) end - from = merge_with_relation.from_value if merge_with_relation && merge_with_relation.from_value.present? + from = current_scoped_methods.from_value if current_scoped_methods && current_scoped_methods.from_value.present? from = options[:from] if from.blank? && options[:from].present? relation = relation.from(from) - select = options[:select].presence || (merge_with_relation ? merge_with_relation.select_values.join(", ") : nil) + select = options[:select].presence || (current_scoped_methods ? current_scoped_methods.select_values.join(", ") : nil) relation = relation.select(select) relation end end - def construct_calculation_arel_with_included_associations(options, join_dependency, merge_with_relation = nil) + def construct_calculation_arel_with_included_associations(options, join_dependency) relation = unscoped for association in join_dependency.join_associations relation = association.join_relation(relation) end - if merge_with_relation - relation.joins_values = (merge_with_relation.joins_values + relation.joins_values).uniq - relation.where_values = merge_with_relation.where_values + if current_scoped_methods + relation.joins_values = (current_scoped_methods.joins_values + relation.joins_values).uniq + relation.where_values = current_scoped_methods.where_values - merge_limit = merge_with_relation.taken + merge_limit = current_scoped_methods.taken end relation = relation.apply_finder_options(options.slice(:joins, :group, :having, :order, :conditions, :from)). -- cgit v1.2.3 From 3c4186b366a14042a6ea6cc3432634d41986d1e2 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 22:05:43 +0530 Subject: Remove construct_calculation_arel_with_included_associations because it's same as construct_finder_arel_with_included_associations --- activerecord/lib/active_record/calculations.rb | 28 +------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index 051f22db85..f279bdfc8d 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -162,7 +162,7 @@ module ActiveRecord merge_with_joins = current_scoped_methods ? current_scoped_methods.joins_values : [] joins = (merge_with_joins + Array.wrap(options[:joins])).uniq join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, includes, construct_join(joins)) - construct_calculation_arel_with_included_associations(options, join_dependency) + construct_finder_arel_with_included_associations(options, join_dependency) else relation = unscoped.apply_finder_options(options.slice(:joins, :conditions, :order, :limit, :offset, :group, :having)) @@ -181,32 +181,6 @@ module ActiveRecord end end - def construct_calculation_arel_with_included_associations(options, join_dependency) - relation = unscoped - - for association in join_dependency.join_associations - relation = association.join_relation(relation) - end - - if current_scoped_methods - relation.joins_values = (current_scoped_methods.joins_values + relation.joins_values).uniq - relation.where_values = current_scoped_methods.where_values - - merge_limit = current_scoped_methods.taken - end - - relation = relation.apply_finder_options(options.slice(:joins, :group, :having, :order, :conditions, :from)). - select(column_aliases(join_dependency)) - - if !using_limitable_reflections?(join_dependency.reflections) && (merge_limit || options[:limit]) - relation = relation.where(construct_arel_limited_ids_condition(options, join_dependency)) - end - - relation = relation.limit(options[:limit] || merge_limit) if using_limitable_reflections?(join_dependency.reflections) - - relation - end - end end end -- cgit v1.2.3 From 9e7ec2a9f13aa52cdf07cf9308e8031548dcddc0 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 Jan 2010 23:39:19 +0530 Subject: Simplify calculation scope building. Remove :order from associations as it is troublesome w/ calculation methods using postgresql. --- activerecord/lib/active_record/calculations.rb | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index f279bdfc8d..8a44dc7df1 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -164,20 +164,7 @@ module ActiveRecord join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, includes, construct_join(joins)) construct_finder_arel_with_included_associations(options, join_dependency) else - relation = unscoped.apply_finder_options(options.slice(:joins, :conditions, :order, :limit, :offset, :group, :having)) - - if current_scoped_methods - relation = current_scoped_methods.except(:select, :order, :limit, :offset, :group, :from).merge(relation) - end - - from = current_scoped_methods.from_value if current_scoped_methods && current_scoped_methods.from_value.present? - from = options[:from] if from.blank? && options[:from].present? - relation = relation.from(from) - - select = options[:select].presence || (current_scoped_methods ? current_scoped_methods.select_values.join(", ") : nil) - relation = relation.select(select) - - relation + scoped.apply_finder_options(options) end end -- cgit v1.2.3 From e6a68a5cc3b47865abbba59bf693215c50136002 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 19 Jan 2010 04:32:40 +0530 Subject: Add Relation#find_with_associations to load relation with eager loaded associations --- activerecord/lib/active_record/relation.rb | 29 +++-------------- .../lib/active_record/relation/finder_methods.rb | 36 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 25 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 4ed118b02d..e37e692a97 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -45,33 +45,12 @@ module ActiveRecord def to_a return @records if loaded? - find_with_associations = @eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?) - - @records = if find_with_associations - begin - options = { - :select => @select_values.join(", "), - :joins => arel.joins(arel), - :group => @group_values.join(", "), - :order => @order_values.join(', '), - :conditions => where_clause, - :limit => @limit_value, - :offset => @offset_value, - :from => @from_value - } - - including = (@eager_load_values + @includes_values).uniq - join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, nil) - @klass.send(:find_with_associations, options, join_dependency) - rescue ThrowResult - [] - end - else - @klass.find_by_sql(arel.to_sql) - end + eager_loading = @eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?) + + @records = eager_loading ? find_with_associations : @klass.find_by_sql(arel.to_sql) preload = @preload_values - preload += @includes_values unless find_with_associations + preload += @includes_values unless eager_loading preload.each {|associations| @klass.send(:preload_associations, @records, associations) } # @readonly_value is true only if set explicity. @implicit_readonly is true if there are JOINS and no explicit SELECT. diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 3668b0997f..980c5796f3 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -44,6 +44,42 @@ module ActiveRecord protected + def find_with_associations + including = (@eager_load_values + @includes_values).uniq + join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, nil) + rows = construct_relation_for_association_find(join_dependency).to_a + join_dependency.instantiate(rows) + rescue ThrowResult + [] + end + + def construct_relation_for_association_find(join_dependency) + relation = except(:includes, :eager_load, :preload, :select).select(@klass.send(:column_aliases, join_dependency)) + + for association in join_dependency.join_associations + relation = association.join_relation(relation) + end + + limitable_reflections = @klass.send(:using_limitable_reflections?, join_dependency.reflections) + + if !limitable_reflections && relation.limit_value + limited_id_condition = construct_limited_ids_condition(relation.except(:select)) + relation = relation.where(limited_id_condition) + end + + relation = relation.except(:limit, :offset) unless limitable_reflections + + relation + end + + def construct_limited_ids_condition(relation) + orders = relation.order_values.join(", ") + values = @klass.connection.distinct("#{@klass.connection.quote_table_name @klass.table_name}.#{@klass.primary_key}", orders) + + ids_array = relation.select(values).collect {|row| row[@klass.primary_key]} + ids_array.empty? ? raise(ThrowResult) : primary_key.in(ids_array) + end + def find_by_attributes(match, attributes, *args) conditions = attributes.inject({}) {|h, a| h[a] = args[attributes.index(a)]; h} result = where(conditions).send(match.finder) -- cgit v1.2.3 From b9599502c9e738a5a1513e75d08f8d40ed408265 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 19 Jan 2010 15:22:09 +0530 Subject: Add Relation#construct_relation_for_association_calculations for calculations with includes --- activerecord/lib/active_record/calculations.rb | 25 ++++------------------ activerecord/lib/active_record/relation.rb | 11 ++++++---- .../lib/active_record/relation/finder_methods.rb | 6 ++++++ 3 files changed, 17 insertions(+), 25 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index 8a44dc7df1..fc6cb793ab 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -2,8 +2,6 @@ module ActiveRecord module Calculations #:nodoc: extend ActiveSupport::Concern - CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from] - module ClassMethods # Count operates using three different approaches. # @@ -147,26 +145,11 @@ module ActiveRecord end private - def validate_calculation_options(options = {}) - options.assert_valid_keys(CALCULATIONS_OPTIONS) - end - - def construct_calculation_arel(options = {}) - validate_calculation_options(options) - options = options.except(:distinct) - - merge_with_includes = current_scoped_methods ? current_scoped_methods.includes_values : [] - includes = (merge_with_includes + Array.wrap(options[:include])).uniq - if includes.any? - merge_with_joins = current_scoped_methods ? current_scoped_methods.joins_values : [] - joins = (merge_with_joins + Array.wrap(options[:joins])).uniq - join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, includes, construct_join(joins)) - construct_finder_arel_with_included_associations(options, join_dependency) - else - scoped.apply_finder_options(options) - end - end + def construct_calculation_arel(options = {}) + relation = scoped.apply_finder_options(options.except(:distinct)) + (relation.eager_loading? || relation.includes_values.present?) ? relation.send(:construct_relation_for_association_calculations) : relation + end end end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index e37e692a97..19f91f4278 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -45,12 +45,10 @@ module ActiveRecord def to_a return @records if loaded? - eager_loading = @eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?) - - @records = eager_loading ? find_with_associations : @klass.find_by_sql(arel.to_sql) + @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql) preload = @preload_values - preload += @includes_values unless eager_loading + preload += @includes_values unless eager_loading? preload.each {|associations| @klass.send(:preload_associations, @records, associations) } # @readonly_value is true only if set explicity. @implicit_readonly is true if there are JOINS and no explicit SELECT. @@ -112,6 +110,7 @@ module ActiveRecord def reset @first = @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil + @should_eager_load = @join_dependency = nil @records = [] self end @@ -133,6 +132,10 @@ module ActiveRecord end end + def eager_loading? + @should_eager_load ||= (@eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?)) + end + protected def method_missing(method, *args, &block) diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 980c5796f3..c48c8fe828 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -53,6 +53,12 @@ module ActiveRecord [] end + def construct_relation_for_association_calculations + including = (@eager_load_values + @includes_values).uniq + join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, arel.joins(arel)) + construct_relation_for_association_find(join_dependency) + end + def construct_relation_for_association_find(join_dependency) relation = except(:includes, :eager_load, :preload, :select).select(@klass.send(:column_aliases, join_dependency)) -- cgit v1.2.3