diff options
Diffstat (limited to 'activerecord/lib')
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 |