Skip to content

Commit 6408b73

Browse files
committed
Merge pull request #233 from SamSaffron/fix
Optimised performance for attribute extraction
2 parents 6642a86 + 710c375 commit 6408b73

File tree

4 files changed

+64
-12
lines changed

4 files changed

+64
-12
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ spec/reports
1515
test/tmp
1616
test/version_tmp
1717
tmp
18+
*.swp

Rakefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,9 @@ Rake::TestTask.new(:test) do |t|
1010
t.verbose = true
1111
end
1212

13+
desc 'Benchmark'
14+
task :bench do
15+
load 'bench/perf.rb'
16+
end
17+
1318
task :default => :test

bench/perf.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
require "rubygems"
2+
require "bundler/setup"
3+
require "active_model_serializers"
4+
require "active_support/json"
5+
require "benchmark"
6+
7+
class User < Struct.new(:id,:name,:age,:about)
8+
include ActiveModel::SerializerSupport
9+
10+
def fast_hash
11+
h = {
12+
id: read_attribute_for_serialization(:id),
13+
name: read_attribute_for_serialization(:name),
14+
about: read_attribute_for_serialization(:about)
15+
}
16+
h[:age] = read_attribute_for_serialization(:age) if age > 18
17+
h
18+
end
19+
end
20+
21+
class UserSerializer < ActiveModel::Serializer
22+
attributes :id, :name, :age, :about
23+
24+
def include_age?
25+
object.age > 18
26+
end
27+
end
28+
29+
30+
31+
u = User.new(1, "sam", 10, "about")
32+
s = UserSerializer.new(u)
33+
34+
n = 100000
35+
36+
Benchmark.bmbm {|x|
37+
x.report("init") { n.times { UserSerializer.new(u) } }
38+
x.report("fast_hash") { n.times { u.fast_hash } }
39+
x.report("attributes") { n.times { UserSerializer.new(u).attributes } }
40+
x.report("serializable_hash") { n.times { UserSerializer.new(u).serializable_hash } }
41+
}
42+
43+

lib/active_model/serializer.rb

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def attribute(attr, options={})
9696
end
9797

9898
define_include_method attr
99+
99100
end
100101

101102
def associate(klass, attrs) #:nodoc:
@@ -284,13 +285,9 @@ def as_json(options={})
284285
# object without the root.
285286
def serializable_hash
286287
return nil if @object.nil?
287-
instrument(:serialize, :serializer => self.class.name) do
288-
@node = attributes
289-
instrument :associations do
290-
include_associations! if _embed
291-
end
292-
@node
293-
end
288+
@node = attributes
289+
include_associations! if _embed
290+
@node
294291
end
295292

296293
def include_associations!
@@ -381,13 +378,19 @@ def merge_association(hash, key, serializables, unique_values)
381378
# Returns a hash representation of the serializable
382379
# object attributes.
383380
def attributes
384-
hash = {}
381+
_fast_attributes
382+
rescue NameError
383+
method = "def _fast_attributes\n"
385384

386-
_attributes.each do |name,key|
387-
hash[key] = read_attribute_for_serialization(name) if include?(name)
388-
end
385+
method << " h = {}\n"
386+
387+
_attributes.each do |name,key|
388+
method << " h[:#{key}] = read_attribute_for_serialization(:#{name}) if send #{INCLUDE_METHODS[name].inspect}\n"
389+
end
390+
method << " h\nend"
389391

390-
hash
392+
self.class.class_eval method
393+
_fast_attributes
391394
end
392395

393396
# Returns options[:scope]

0 commit comments

Comments
 (0)