First of all, I am still new to ROR and I am trying to come up with more efficient way to do a database query for my datatables.
My Model association
class Store < ActiveRecord::Base
has_many :surveys
has_many :customers
end
...
class Survey < ActiveRecord::Base
belongs_to :store
end
...
class Customer < ActiveRecord::Base
belongs_to :store
end
In my DataTables
<tbody>
<% @store.surveys.each do |survey| %>
<tr class="th-container table-fixer">
<td><%= find_customer_id(survey.email).nil? ? survey.first_name : link_to(survey.first_name, store_customer_path(@store, find_customer_id(survey.email))) %></td>
<td><%= get_ltv(survey) %></td>
</tr>
<% end %>
</tbody>
find_customer_id and get_ltv method as follows
def find_customer_id(customer_email)
BwCustomer.find_by(email: customer_email)
end
The problem with the code is that, currently I have over 1000 active record objects that I loop through, when find_customer_id method is hit it will find customer with the given email address and the query takes over 15 sec to process.
In my situation, what would be the best way to approach this?
solution that I have though about: 1. join the tables to so that I don't have to call another table 2. lazy load, only load the objects when needed
Some suggestion will be greatly appreciated
thank you
Your query by email ID should not take so much time.
Add index for the email column in Customers table (Refer this for adding indexes through Active record migrations - http://apidock.com/rails/v4.2.1/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index )
Your code shows calling the find_customer_id
twice. Do that once so only 1 database query is fired
You need not write a wrapper method - Customer.find_by_email(customer_email)
also works
To optimize further, you can collect all the customer IDs you need to check for existence in database in one loop, and fire a single database query: Customer.where(email: [list of customer emails])
The main problem is that you're missing an association between customer and survey. You could make one by joining on the email
class Survey < ActiveRecord::Base
belongs_to :customer, primary_key: :email, foreign_key: :email
end
but this is a somewhat sketchy approach. Does you application know the ID of the customer when they fill a survey? Or can these surveys be filled by anyone and you make the link if someone claims to have the same email as a customer?
In any case you need both the email columns to be indexed and if you make an association between the two you will be able to write the following in your controller code.
@store = Store.includes(surveys: :customer).find(params[store_id])
This will make a database query which eager loads all the surveys and customers that you're about to display so that inside the loop you can use survey.customer
without calling a new query for each row.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.