Skip to content

Commit

Permalink
Merge pull request norman#673 from dgynn/find_by_find_by
Browse files Browse the repository at this point in the history
Use ActiveRecord's find_by to perform the query in finder_methods
  • Loading branch information
norman committed Jun 7, 2015
2 parents 3c90bb0 + 8e6fe6c commit b6b6c00
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 7 deletions.
10 changes: 10 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ task :bench => :load_path do
require File.expand_path("../bench", __FILE__)
end

desc "Run benchmarks on finders"
task :bench_finders => :load_path do
require File.expand_path("../test/benchmarks/finders", __FILE__)
end

desc "Run benchmarks on ObjectUtils"
task :bench_object_utils => :load_path do
require File.expand_path("../test/benchmarks/object_utils", __FILE__)
end

desc "Generate Guide.md"
task :guide do
load File.expand_path('../guide.rb', __FILE__)
Expand Down
12 changes: 6 additions & 6 deletions bench.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require File.expand_path("../test/helper", __FILE__)
require "ffaker"

N = 1000
N = 10000

def transaction
ActiveRecord::Base.transaction { yield ; raise ActiveRecord::Rollback }
Expand Down Expand Up @@ -37,7 +37,7 @@ class Restaurant < ActiveRecord::Base
RESTAURANTS = []

100.times do
name = Faker::Name.name
name = FFaker::Name.name
BOOKS << (Book.create! :name => name).id
JOURNALISTS << (Journalist.create! :name => name).friendly_id
MANUALS << (Manual.create! :name => name).friendly_id
Expand All @@ -64,18 +64,18 @@ class Restaurant < ActiveRecord::Base
end

x.report 'insert (without FriendlyId)' do
N.times {transaction {Book.create :name => Faker::Name.name}}
N.times {transaction {Book.create :name => FFaker::Name.name}}
end

x.report 'insert (in-table-slug)' do
N.times {transaction {Journalist.create :name => Faker::Name.name}}
N.times {transaction {Journalist.create :name => FFaker::Name.name}}
end

x.report 'insert (in-table-slug; using finders module)' do
N.times {transaction {Restaurant.create :name => Faker::Name.name}}
N.times {transaction {Restaurant.create :name => FFaker::Name.name}}
end

x.report 'insert (external slug)' do
N.times {transaction {Manual.create :name => Faker::Name.name}}
N.times {transaction {Manual.create :name => FFaker::Name.name}}
end
end
2 changes: 1 addition & 1 deletion lib/friendly_id/finder_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def potential_primary_key?(id)
end

def first_by_friendly_id(id)
where(friendly_id_config.query_field => id).first
find_by(friendly_id_config.query_field => id)
end

end
Expand Down
88 changes: 88 additions & 0 deletions test/benchmarks/finders.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
require File.expand_path("../../helper", __FILE__)
require "ffaker"

# This benchmark tests ActiveRecord and FriendlyId methods for performing a find
#
# ActiveRecord: where.first 8.970000 0.040000 9.010000 ( 9.029544)
# ActiveRecord: where.take 8.100000 0.030000 8.130000 ( 8.157024)
# ActiveRecord: find 2.720000 0.010000 2.730000 ( 2.733527)
# ActiveRecord: find_by(:id) 2.920000 0.000000 2.920000 ( 2.926318)
# ActiveRecord: find_by(:slug) 2.650000 0.020000 2.670000 ( 2.662677)
# FriendlyId: find (in-table slug w/ finders) 9.820000 0.030000 9.850000 ( 9.873358)
# FriendlyId: friendly.find (in-table slug) 12.890000 0.050000 12.940000 ( 12.951156)

N = 50000

def transaction
ActiveRecord::Base.transaction { yield ; raise ActiveRecord::Rollback }
end

class Array
def rand
self[Kernel.rand(length)]
end
end

Book = Class.new ActiveRecord::Base

class Journalist < ActiveRecord::Base
extend FriendlyId
friendly_id :name, :use => :slugged
end

class Manual < ActiveRecord::Base
extend FriendlyId
friendly_id :name, :use => :history
end

class Restaurant < ActiveRecord::Base
extend FriendlyId
friendly_id :name, :use => :finders
end


BOOKS = []
JOURNALISTS = []
MANUALS = []
RESTAURANTS = []

100.times do
name = FFaker::Name.name
BOOKS << (Book.create! :name => name).id
JOURNALISTS << (Journalist.create! :name => name).friendly_id
MANUALS << (Manual.create! :name => name).friendly_id
RESTAURANTS << (Restaurant.create! :name => name).friendly_id
end

ActiveRecord::Base.connection.execute "UPDATE manuals SET slug = NULL"

Benchmark.bmbm do |x|
x.report 'ActiveRecord: where.first' do
N.times {Book.where(:id=>BOOKS.rand).first}
end

x.report 'ActiveRecord: where.take' do
N.times {Book.where(:id=>BOOKS.rand).take}
end

x.report 'ActiveRecord: find' do
N.times {Book.find BOOKS.rand}
end

x.report 'ActiveRecord: find_by(:id)' do
N.times {Book.find_by(:id=>BOOKS.rand)}
end

x.report 'ActiveRecord: find_by(:slug)' do
N.times {Restaurant.find_by(:slug=>RESTAURANTS.rand)}
end

x.report 'FriendlyId: find (in-table slug w/ finders)' do
N.times {Restaurant.find RESTAURANTS.rand}
end

x.report 'FriendlyId: friendly.find (in-table slug)' do
N.times {Restaurant.friendly.find RESTAURANTS.rand}
end

end
56 changes: 56 additions & 0 deletions test/benchmarks/object_utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require File.expand_path("../../helper", __FILE__)

# This benchmark compares the timings of the friendly_id? and unfriendly_id? on various objects
#
# integer friendly_id? 6.370000 0.000000 6.370000 ( 6.380925)
# integer unfriendly_id? 6.640000 0.010000 6.650000 ( 6.646057)
# AR::Base friendly_id? 2.340000 0.000000 2.340000 ( 2.340743)
# AR::Base unfriendly_id? 2.560000 0.000000 2.560000 ( 2.560039)
# hash friendly_id? 5.090000 0.010000 5.100000 ( 5.097662)
# hash unfriendly_id? 5.430000 0.000000 5.430000 ( 5.437160)
# nil friendly_id? 5.610000 0.010000 5.620000 ( 5.611487)
# nil unfriendly_id? 5.870000 0.000000 5.870000 ( 5.880484)
# numeric string friendly_id? 9.270000 0.030000 9.300000 ( 9.308452)
# numeric string unfriendly_id? 9.190000 0.040000 9.230000 ( 9.252890)
# test_string friendly_id? 8.380000 0.010000 8.390000 ( 8.411762)
# test_string unfriendly_id? 8.450000 0.010000 8.460000 ( 8.463662)

# From the ObjectUtils docs...
# 123.friendly_id? #=> false
# :id.friendly_id? #=> false
# {:name => 'joe'}.friendly_id? #=> false
# ['name = ?', 'joe'].friendly_id? #=> false
# nil.friendly_id? #=> false
# "123".friendly_id? #=> nil
# "abc123".friendly_id? #=> true

Book = Class.new ActiveRecord::Base

test_integer = 123
test_active_record_object = Book.new
test_hash = {:name=>'joe'}
test_nil = nil
test_numeric_string = "123"
test_string = "abc123"

N = 5_000_000

Benchmark.bmbm do |x|
x.report('integer friendly_id?') { N.times {test_integer.friendly_id?} }
x.report('integer unfriendly_id?') { N.times {test_integer.unfriendly_id?} }

x.report('AR::Base friendly_id?') { N.times {test_active_record_object.friendly_id?} }
x.report('AR::Base unfriendly_id?') { N.times {test_active_record_object.unfriendly_id?} }

x.report('hash friendly_id?') { N.times {test_hash.friendly_id?} }
x.report('hash unfriendly_id?') { N.times {test_hash.unfriendly_id?} }

x.report('nil friendly_id?') { N.times {test_nil.friendly_id?} }
x.report('nil unfriendly_id?') { N.times {test_nil.unfriendly_id?} }

x.report('numeric string friendly_id?') { N.times {test_numeric_string.friendly_id?} }
x.report('numeric string unfriendly_id?') { N.times {test_numeric_string.unfriendly_id?} }

x.report('test_string friendly_id?') { N.times {test_string.friendly_id?} }
x.report('test_string unfriendly_id?') { N.times {test_string.unfriendly_id?} }
end

0 comments on commit b6b6c00

Please sign in to comment.