From 3c3f8087647a15a5e88dd18a45d41358eacce142 Mon Sep 17 00:00:00 2001 From: Pete Campbell Date: Thu, 28 Jul 2011 09:44:51 -0400 Subject: Explicitly included hashes in sentence regarding SQL-injection-safe forms --- activerecord/lib/active_record/base.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 4136868b39..461df0555f 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -63,9 +63,9 @@ module ActiveRecord #:nodoc: # == Conditions # # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement. - # The array form is to be used when the condition input is tainted and requires sanitization. The string form can - # be used for statements that don't involve tainted data. The hash form works much like the array form, except - # only equality and range is possible. Examples: + # The array form is to be used when the condition input is tainted and requires sanitization. The string and hash + # forms can be used for statements that don't involve tainted data. The hash form works much like the array form, + # except only equality and range is possible. Examples: # # class User < ActiveRecord::Base # def self.authenticate_unsafely(user_name, password) -- cgit v1.2.3 From 9e18380a323c7087b2079ec479d26ce899268b72 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Thu, 4 Aug 2011 15:14:06 -0700 Subject: Revert "Explicitly included hashes in sentence regarding SQL-injection-safe forms" Reason: The hash form is secure, and preferred over the array form if possible. This reverts commit 6dc749596c328c44c80f898d5fa860fff6cab783. --- activerecord/lib/active_record/base.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 461df0555f..4136868b39 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -63,9 +63,9 @@ module ActiveRecord #:nodoc: # == Conditions # # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement. - # The array form is to be used when the condition input is tainted and requires sanitization. The string and hash - # forms can be used for statements that don't involve tainted data. The hash form works much like the array form, - # except only equality and range is possible. Examples: + # The array form is to be used when the condition input is tainted and requires sanitization. The string form can + # be used for statements that don't involve tainted data. The hash form works much like the array form, except + # only equality and range is possible. Examples: # # class User < ActiveRecord::Base # def self.authenticate_unsafely(user_name, password) -- cgit v1.2.3 From 7db90aa7c7dfe5033ad012b8ee13e6f15d1c66f0 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 8 Aug 2011 23:27:54 +0100 Subject: Make it the responsibility of the connection to hold onto an ARel visitor for generating SQL. This improves the code architecture generally, and solves some problems with marshalling. Adapter authors please take note: you now need to define an Adapter.visitor_for method, but it degrades gracefully with a deprecation warning for now. --- activerecord/lib/active_record/base.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 4136868b39..06087642d4 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1409,9 +1409,8 @@ MSG attrs = expand_hash_conditions_for_aggregates(attrs) table = Arel::Table.new(table_name).alias(default_table_name) - viz = Arel::Visitors.for(arel_engine) PredicateBuilder.build_from_hash(arel_engine, attrs, table).map { |b| - viz.accept b + connection.visitor.accept b }.join(' AND ') end alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions -- cgit v1.2.3 From 9062b75bb7dab38977805c1de35944079a56499a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 8 Aug 2011 14:41:23 +0100 Subject: Fully marshal AR::Base objects. Fixes #2431. --- activerecord/lib/active_record/base.rb | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 06087642d4..102d8f4175 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -937,17 +937,6 @@ module ActiveRecord #:nodoc: self.current_scope = nil end - # Specifies how the record is loaded by +Marshal+. - # - # +_load+ sets an instance variable for each key in the hash it takes as input. - # Override this method if you require more complex marshalling. - def _load(data) - record = allocate - record.init_with(Marshal.load(data)) - record - end - - # Finder methods must instantiate through this method to work with the # single-table inheritance model that makes it possible to create # objects of different types from the same table. @@ -1588,16 +1577,6 @@ MSG self end - # Specifies how the record is dumped by +Marshal+. - # - # +_dump+ emits a marshalled hash which has been passed to +encode_with+. Override this - # method if you require more complex marshalling. - def _dump(level) - dump = {} - encode_with(dump) - Marshal.dump(dump) - end - # Returns a String, which Action Pack uses for constructing an URL to this # object. The default implementation returns this record's id as a String, # or nil if this record's unsaved. -- cgit v1.2.3 From 24f902b1bcfa5dca4bfc7f2b978a4b0dece73894 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 13 Aug 2011 16:37:44 +0100 Subject: Fix default scope thread safety. Thanks @thedarkone for reporting. --- activerecord/lib/active_record/base.rb | 41 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 102d8f4175..5a57e1bc70 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1206,6 +1206,14 @@ MSG Thread.current["#{self}_current_scope"] = scope end + def ignore_default_scope? #:nodoc: + Thread.current["#{self}_ignore_default_scope"] + end + + def ignore_default_scope=(ignore) #:nodoc: + Thread.current["#{self}_ignore_default_scope"] = ignore + end + # Use this macro in your model to set a default scope for all operations on # the model. # @@ -1259,24 +1267,27 @@ MSG # The @ignore_default_scope flag is used to prevent an infinite recursion situation where # a default scope references a scope which has a default scope which references a scope... def build_default_scope #:nodoc: - return if defined?(@ignore_default_scope) && @ignore_default_scope - @ignore_default_scope = true - - if method(:default_scope).owner != Base.singleton_class - default_scope - elsif default_scopes.any? - default_scopes.inject(relation) do |default_scope, scope| - if scope.is_a?(Hash) - default_scope.apply_finder_options(scope) - elsif !scope.is_a?(Relation) && scope.respond_to?(:call) - default_scope.merge(scope.call) - else - default_scope.merge(scope) + return if ignore_default_scope? + + begin + self.ignore_default_scope = true + + if method(:default_scope).owner != Base.singleton_class + default_scope + elsif default_scopes.any? + default_scopes.inject(relation) do |default_scope, scope| + if scope.is_a?(Hash) + default_scope.apply_finder_options(scope) + elsif !scope.is_a?(Relation) && scope.respond_to?(:call) + default_scope.merge(scope.call) + else + default_scope.merge(scope) + end end end + ensure + self.ignore_default_scope = false end - ensure - @ignore_default_scope = false end # Returns the class type of the record using the current module as a prefix. So descendants of -- cgit v1.2.3 From 9ecc4433bbda255cbcb4a2be442c8ee985692d06 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 13 Aug 2011 16:50:03 +0100 Subject: Perf: don't mess around with thread local vars unless we actually need to --- activerecord/lib/active_record/base.rb | 41 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 5a57e1bc70..0c5248c576 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1206,14 +1206,6 @@ MSG Thread.current["#{self}_current_scope"] = scope end - def ignore_default_scope? #:nodoc: - Thread.current["#{self}_ignore_default_scope"] - end - - def ignore_default_scope=(ignore) #:nodoc: - Thread.current["#{self}_ignore_default_scope"] = ignore - end - # Use this macro in your model to set a default scope for all operations on # the model. # @@ -1264,17 +1256,11 @@ MSG self.default_scopes = default_scopes + [scope] end - # The @ignore_default_scope flag is used to prevent an infinite recursion situation where - # a default scope references a scope which has a default scope which references a scope... def build_default_scope #:nodoc: - return if ignore_default_scope? - - begin - self.ignore_default_scope = true - - if method(:default_scope).owner != Base.singleton_class - default_scope - elsif default_scopes.any? + if method(:default_scope).owner != Base.singleton_class + evaluate_default_scope { default_scope } + elsif default_scopes.any? + evaluate_default_scope do default_scopes.inject(relation) do |default_scope, scope| if scope.is_a?(Hash) default_scope.apply_finder_options(scope) @@ -1285,6 +1271,25 @@ MSG end end end + end + end + + def ignore_default_scope? #:nodoc: + Thread.current["#{self}_ignore_default_scope"] + end + + def ignore_default_scope=(ignore) #:nodoc: + Thread.current["#{self}_ignore_default_scope"] = ignore + end + + # The ignore_default_scope flag is used to prevent an infinite recursion situation where + # a default scope references a scope which has a default scope which references a scope... + def evaluate_default_scope + return if ignore_default_scope? + + begin + self.ignore_default_scope = true + yield ensure self.ignore_default_scope = false end -- cgit v1.2.3 From 0d5a6f68dfb930816392f9711f0a6a52872bc72f Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 15:01:18 +0100 Subject: In 1efd88283ef68d912df215125951a87526768a51, ConnectionAdapters was put under eager_autoload. Due to the requires in that file, this caused ConnectionSpecification to be loaded, which references ActiveRecord::Base, which means the database connection is established. We do not want to connect to the database when Active Record is loaded, only when ActiveRecord::Base is first referenced by the user. --- activerecord/lib/active_record/base.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 59977280b3..c76f98d6a0 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -178,7 +178,7 @@ module ActiveRecord #:nodoc: # Person.find_all_by_last_name(last_name). # # It's possible to add an exclamation point (!) on the end of the dynamic finders to get them to raise an - # ActiveRecord::RecordNotFound error if they do not return any records, + # ActiveRecord::RecordNotFound error if they do not return any records, # like Person.find_by_last_name!. # # It's also possible to use multiple attributes in the same find by separating them with "_and_". @@ -2163,4 +2163,5 @@ MSG end end +require 'active_record/connection_adapters/abstract/connection_specification' ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base) -- cgit v1.2.3 From 0a0da9d554490f01fe57d69fe8d98f29b02be3e5 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Wed, 24 Aug 2011 21:09:41 +0900 Subject: do not compute table names for abstract classes --- activerecord/lib/active_record/base.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c76f98d6a0..03aea81d2c 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -624,6 +624,8 @@ module ActiveRecord #:nodoc: # Computes the table name, (re)sets it internally, and returns it. def reset_table_name #:nodoc: + return if abstract_class? + self.table_name = compute_table_name end -- cgit v1.2.3 From c59c9bb8bc275a2be8695d4d431a0512d29353f1 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 29 Aug 2011 17:39:09 +0100 Subject: Move clear_timestamp_attributes into Timestamp module --- activerecord/lib/active_record/base.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'activerecord/lib/active_record/base.rb') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 03aea81d2c..374791deb1 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1849,7 +1849,7 @@ MSG ensure_proper_type populate_with_current_scope_attributes - clear_timestamp_attributes + super end # Returns +true+ if the record is read only. Records loaded through joins with piggy-back @@ -2113,14 +2113,6 @@ MSG send("#{att}=", value) if respond_to?("#{att}=") end end - - # Clear attributes and changed_attributes - def clear_timestamp_attributes - all_timestamp_attributes_in_model.each do |attribute_name| - self[attribute_name] = nil - changed_attributes.delete(attribute_name) - end - end end Base.class_eval do -- cgit v1.2.3