這是前段時間有人討論過的問題:
假定orders表有10個字段,你只想更新其中一個,但active record會生成一個更新全部字段的SQL語句,假定其中一個字段值長度是20K,這個負擔可能會有些重。
我嘗試解決這個問題,寫了個簡單的插件:
| 代碼: |
|
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
??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
簡單測試通過。

