aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/association_preload.rb3
-rwxr-xr-xactiverecord/lib/active_record/associations.rb21
-rw-r--r--activerecord/lib/active_record/associations/association_collection.rb12
-rw-r--r--activerecord/lib/active_record/associations/association_proxy.rb11
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb1
-rw-r--r--activerecord/lib/active_record/associations/has_one_association.rb2
-rwxr-xr-xactiverecord/lib/active_record/base.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb19
8 files changed, 52 insertions, 20 deletions
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index 99e3973830..6e194ab9b4 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -193,6 +193,7 @@ module ActiveRecord
end
def preload_has_one_association(records, reflection, preload_options={})
+ return if records.first.send("loaded_#{reflection.name}?")
id_to_record_map, ids = construct_id_map(records)
options = reflection.options
records.each {|record| record.send("set_#{reflection.name}_target", nil)}
@@ -214,6 +215,7 @@ module ActiveRecord
end
def preload_has_many_association(records, reflection, preload_options={})
+ return if records.first.send(reflection.name).loaded?
options = reflection.options
primary_key_name = reflection.through_reflection_primary_key_name
@@ -271,6 +273,7 @@ module ActiveRecord
end
def preload_belongs_to_association(records, reflection, preload_options={})
+ return if records.first.send("loaded_#{reflection.name}?")
options = reflection.options
primary_key_name = reflection.primary_key_name
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index d1a0b2f96a..187caa13d0 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -624,7 +624,8 @@ module ActiveRecord
# Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
# [collection.delete(object, ...)]
# Removes one or more objects from the collection by setting their foreign keys to +NULL+.
- # This will also destroy the objects if they're declared as +belongs_to+ and dependent on this model.
+ # Objects will be in addition destroyed if they're associated with <tt>:dependent => :destroy</tt>,
+ # and deleted if they're associated with <tt>:dependent => :delete_all</tt>.
# [collection=objects]
# Replaces the collections content by deleting and adding objects as appropriate.
# [collection_singular_ids]
@@ -1235,7 +1236,7 @@ module ActiveRecord
association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
- if association.nil? || !association.loaded? || force_reload
+ if association.nil? || force_reload
association = association_proxy_class.new(self, reflection)
retval = association.reload
if retval.nil? and association_proxy_class == BelongsToAssociation
@@ -1248,6 +1249,11 @@ module ActiveRecord
association.target.nil? ? nil : association
end
+ define_method("loaded_#{reflection.name}?") do
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
+ association && association.loaded?
+ end
+
define_method("#{reflection.name}=") do |new_value|
association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
@@ -1264,17 +1270,6 @@ module ActiveRecord
end
end
- if association_proxy_class == BelongsToAssociation
- define_method("#{reflection.primary_key_name}=") do |target_id|
- if instance_variable_defined?(ivar)
- if association = instance_variable_get(ivar)
- association.reset
- end
- end
- write_attribute(reflection.primary_key_name, target_id)
- end
- end
-
define_method("set_#{reflection.name}_target") do |target|
return if target.nil? and association_proxy_class == BelongsToAssociation
association = association_proxy_class.new(self, reflection)
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb
index 463de9d819..da1a7887ce 100644
--- a/activerecord/lib/active_record/associations/association_collection.rb
+++ b/activerecord/lib/active_record/associations/association_collection.rb
@@ -183,7 +183,13 @@ module ActiveRecord
end
- # Remove +records+ from this association. Does not destroy +records+.
+ # Removes +records+ from this association calling +before_remove+ and
+ # +after_remove+ callbacks.
+ #
+ # This method is abstract in the sense that +delete_records+ has to be
+ # provided by descendants. Note this method does not imply the records
+ # are actually removed from the database, that depends precisely on
+ # +delete_records+. They are in any case removed from the collection.
def delete(*records)
records = flatten_deeper(records)
records.each { |record| raise_on_type_mismatch(record) }
@@ -320,6 +326,10 @@ module ActiveRecord
exists?(record)
end
+ def proxy_respond_to?(method)
+ super || @reflection.klass.respond_to?(method)
+ end
+
protected
def construct_find_options!(options)
end
diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb
index b617147f67..d1a79df6e6 100644
--- a/activerecord/lib/active_record/associations/association_proxy.rb
+++ b/activerecord/lib/active_record/associations/association_proxy.rb
@@ -140,6 +140,15 @@ module ActiveRecord
@target.inspect
end
+ def send(method, *args)
+ if proxy_respond_to?(method)
+ super
+ else
+ load_target
+ @target.send(method, *args)
+ end
+ end
+
protected
# Does the association have a <tt>:dependent</tt> option?
def dependent?
@@ -197,6 +206,8 @@ module ActiveRecord
# Forwards any missing method call to the \target.
def method_missing(method, *args)
if load_target
+ raise NoMethodError unless @target.respond_to?(method)
+
if block_given?
@target.send(method, *args) { |*block_args| yield(*block_args) }
else
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index 3b2f306637..3348079e9d 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -61,6 +61,7 @@ module ActiveRecord
record.save
end
+ # Deletes the records according to the <tt>:dependent</tt> option.
def delete_records(records)
case @reflection.options[:dependent]
when :destroy
diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb
index c92ef5c2c9..960323004d 100644
--- a/activerecord/lib/active_record/associations/has_one_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_association.rb
@@ -57,7 +57,7 @@ module ActiveRecord
protected
def owner_quoted_id
if @reflection.options[:primary_key]
- quote_value(@owner.send(@reflection.options[:primary_key]))
+ @owner.class.quote_value(@owner.send(@reflection.options[:primary_key]))
else
@owner.quoted_id
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 6a1a3794a2..039e14435f 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -514,7 +514,7 @@ module ActiveRecord #:nodoc:
#
# ==== Parameters
#
- # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1" or <tt>[ "user_name = ?", username ]</tt>. See conditions in the intro.
+ # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1", <tt>[ "user_name = ?", username ]</tt>, or <tt>["user_name = :user_name", { :user_name => user_name }]</tt>. See conditions in the intro.
# * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
# * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
# * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
@@ -551,6 +551,7 @@ module ActiveRecord #:nodoc:
# # find first
# Person.find(:first) # returns the first object fetched by SELECT * FROM people
# Person.find(:first, :conditions => [ "user_name = ?", user_name])
+ # Person.find(:first, :conditions => [ "user_name = :u", { :u => user_name }])
# Person.find(:first, :order => "created_on DESC", :offset => 5)
#
# # find last
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 10dc1a81f3..97c6cd4331 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -120,10 +120,6 @@ module ActiveRecord
sql
end
- def sanitize_limit(limit)
- limit.to_s[/,/] ? limit.split(',').map{ |i| i.to_i }.join(',') : limit.to_i
- end
-
# Appends a locking clause to an SQL statement.
# This method *modifies* the +sql+ parameter.
# # SELECT * FROM suppliers FOR UPDATE
@@ -185,6 +181,21 @@ module ActiveRecord
def delete_sql(sql, name = nil)
update_sql(sql, name)
end
+
+ # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
+ #
+ # +limit+ may be anything that can evaluate to a string via #to_s. It
+ # should look like an integer, or a comma-delimited list of integers.
+ #
+ # Returns the sanitized limit parameter, either as an integer, or as a
+ # string which contains a comma-delimited list of integers.
+ def sanitize_limit(limit)
+ if limit.to_s =~ /,/
+ limit.to_s.split(',').map{ |i| i.to_i }.join(',')
+ else
+ limit.to_i
+ end
+ end
end
end
end