Skip to content

Instantly share code, notes, and snippets.

@thinkerbot
Created June 21, 2010 16:04
Show Gist options
  • Select an option

  • Save thinkerbot/447072 to your computer and use it in GitHub Desktop.

Select an option

Save thinkerbot/447072 to your computer and use it in GitHub Desktop.
require 'benchmark'
require 'active_record'
ActiveRecord.load_all!
# ActiveRecord::Base.logger = Logger.new(STDERR)
ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:dbfile => ":memory:"
)
ActiveRecord::Schema.define do
create_table :ones do |table|
table.column :field1, :number
end
create_table :tens do |table|
0.upto(10) do |i|
table.column "field#{i}".to_sym, :number
end
end
create_table :hundreds do |table|
0.upto(100) do |i|
table.column "field#{i}".to_sym, :number
end
end
end
class One < ActiveRecord::Base
end
class Ten < ActiveRecord::Base
end
class Hundred < ActiveRecord::Base
end
Benchmark.bm(20) do |x|
n = 1000
one_attrs = {:field1 => 1}
ten_attrs = {}; 0.upto(10) {|i| ten_attrs["field#{i}".to_sym] = i }
hun_attrs = {}; 0.upto(100) {|i| hun_attrs["field#{i}".to_sym] = i }
x.report("One.new") do
n.times { One.new }
end
x.report("One.new(attrs)") do
n.times { One.new(one_attrs) }
end
x.report("Ten.new(attrs)") do
n.times { Ten.new(ten_attrs) }
end
x.report("Hundred.new(attrs)") do
n.times { Hundred.new(hun_attrs) }
end
x.report("One.first") do
n.times { One.first }
end
x.report("Ten.first") do
n.times { Ten.first }
end
x.report("Hundred.first") do
n.times { Hundred.first }
end
puts
puts "optimimized"
require 'optimization'
x.report("One.new") do
n.times { One.new }
end
x.report("One.new(attrs)") do
n.times { One.new(one_attrs) }
end
x.report("Ten.new(attrs)") do
n.times { Ten.new(ten_attrs) }
end
x.report("Hundred.new(attrs)") do
n.times { Hundred.new(hun_attrs) }
end
x.report("One.first") do
n.times { One.first }
end
x.report("Ten.first") do
n.times { Ten.first }
end
x.report("Hundred.first") do
n.times { Hundred.first }
end
end
class ActiveRecord::Base
class << self
def attributes_protected_from_mass_assignment
@attributes_protected_from_mass_assignment ||= begin
if accessible_attributes.nil? && protected_attributes.nil?
attributes_protected_by_default
elsif protected_attributes.nil?
(accessible_attributes + attributes_protected_by_default).uniq
elsif accessible_attributes.nil?
(protected_attributes + attributes_protected_by_default).uniq
else
raise "Declare either attr_protected or attr_accessible for #{self}, but not both."
end
end
end
def attributes_protected_by_default
default = [ primary_key, inheritance_column ]
default << 'id' unless primary_key.eql? 'id'
default
end
def writer_hash
@writer_hash ||= begin
Hash.new do |hash, k|
hash[k] = instance_methods.include?("#{k}=") ? "#{k}=".to_sym : nil
end
end
end
end
def attributes=(new_attributes, guard_protected_attributes = true)
return if new_attributes.nil?
attributes = new_attributes.stringify_keys
multi_parameter_attributes = []
attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
attributes.each do |k, v|
if k.include?("(")
multi_parameter_attributes << [ k, v ]
else
writer = self.class.writer_hash[k] or raise(UnknownAttributeError, "unknown attribute: #{k}")
send(writer, v)
end
end
assign_multiparameter_attributes(multi_parameter_attributes)
end
def remove_attributes_protected_from_mass_assignment(attributes)
removed_attributes = attributes.keys & self.class.attributes_protected_from_mass_assignment
if removed_attributes.any?
log_protected_attribute_removal(removed_attributes)
end
attributes = attributes.dup
removed_attributes.each {|key| attributes.delete(key) }
attributes
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment