Reputation: 79
for one of my views I want to include a search field with jqueries typeahead function.
The array should contain all the attribute values of a client.
The array for the query is generated the following way:
@clients = []
Client.each do |client|
@clients << client.attributes.values.join(' ')
end
Is this approach performant enough for a dataset of about 3000 entries? Or is there a better and faster solution?
Thanks in advance. Cheers, Patrick
One user mentioned to implement it like this:
@clients = Client.map do |client|
client.attributes.values.join(' ')
end
This is another way to do it. But a benchmark reveals that this is no improvement in performance.
This leaves me with the question: Maybe there is a more performant way, but speaking about a maxium of 3000 records - does it really matter?
Upvotes: 1
Views: 102
Reputation: 4880
You probably don't need to retrieve all the attributes (for example 'updated_at'), so the following may be faster:
@clients = Client.select([:name, :email, :id]).map do |client|
client.attributes.values.join(' ')
end
Added the id
in case you need to link to the client.
Upvotes: 1
Reputation: 54684
Even if ActiveRecord models would implement the map
method (which they don't i believe), the two solutions suggested by the OP and @xdazz are time- and memory-complexity-wise equivalent. This can be observed with this simple benchmark:
require 'fruity'
# Dummy client class
class Client < Struct.new(:first_name, :last_name, :position, :company)
class << self
include Enumerable
def each(&block)
5000.times do
yield Client.new('Firstname', 'Lastname', 'CEO', 'Company Inc.')
end
end
end
alias_method :attributes, :to_h
end
compare do
schnika do
clients = []
Client.each do |client|
clients << client.attributes.values.join(' ')
end
nil
end
xdazz do
clients = Client.map do |client|
client.attributes.values.join(' ')
end
nil
end
end
Which will output
schnika is similar to xdazz
Also, when you look at the implementation of map
(synonymous to collect
), it becomes clear that really nothing else happens than in the OP's method:
static VALUE
rb_ary_collect(VALUE ary)
{
long i;
VALUE collect;
RETURN_ENUMERATOR(ary, 0, 0);
collect = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i]));
}
return collect;
}
This translates to:
class Array
def collect
collect = []
self.each do |el|
collect << yield(el)
end
collect
end
end
Upvotes: 4
Reputation: 160843
You could use .map
:
@clients = Client.map do |client|
client.attributes.values.join(' ')
end
Upvotes: 5