qiezi的学习园地

AS/C/C++/D/Java/JS/Python/Ruby

  C++博客 :: 首页 :: 新随笔 ::  ::  :: 管理 ::
这是前段时间有人讨论过的问题:
代码:

order = Order.find(1)
order.update_attribute(:status, 'finished')

假定orders表有10个字段,你只想更新其中一个,但active record会生成一个更新全部字段的SQL语句,假定其中一个字段值长度是20K,这个负担可能会有些重。

我尝试解决这个问题,写了个简单的插件:
代码:

module ActiveRecord
  class Base
    def update_attribute(name, value)
      update_attributes(name => value)
    end

    def update_attributes(new_attributes)
      return if new_attributes.nil?
      attributes = new_attributes.dup
      attributes.stringify_keys!
      self.attributes = attributes
      update(attributes)
    end

    private
      def update(attrs = nil)
        connection.update(
          "UPDATE #{self.class.table_name} " +
          "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, attrs))} " +
          "WHERE #{self.class.primary_key} = #{quote(id)}",
          "#{self.class.name} Update"
        )
       
        return true
      end

      def attributes_with_quotes(include_primary_key = true, attrs = nil)
        (attrs || attributes).inject({}) do |quoted, (name, value)|
          if column = column_for_attribute(name)
            quoted[name] = quote(value, column) unless !include_primary_key && column.primary
          end
          quoted
        end
      end
  end
end


attributes_with_quotes函数的参数搞这么复杂,原因是我想即便是用这段代码替换库里面的部分,也不影响原有代码的正常功能。

可以简单测试一下上面的例子,它生成的SQL语句会简洁很多,大概是这样子:
UPDATE orders SET "status" = 'finished' WHERE id = 1

已发现的BUG和修复:

1、没有调用validation (by cookoo)。由于原有代码调用save,而save被覆盖成有验证的代码,所以具有验证功能。解决办法是增加一段代码:

module ActiveRecord
  module ValidationsFix
    
def  self.append_features(base)  #  :nodoc:
      super
      base.class_eval do
        alias_method :update_attributes_without_validation, :update_attributes
        alias_method :update_attributes, :update_attributes_with_validation
      end
    end

    
def  update_attributes_with_validation(new_attributes)
      
return   if  new_attributes.nil?
      attributes = new_attributes.dup
      attributes.stringify_keys!
      self.attributes 
=  attributes

      
if  valid?
        update_attributes_without_validation(attributes)
      
else
        
return  false
      end
    end
  end
end

ActiveRecord::Base.class_eval do
  include ActiveRecord::ValidationsFix
end

简单测试通过。

posted on 2006-08-26 02:10 qiezi 阅读(669) 评论(0)  编辑 收藏 引用 所属分类: Ruby