In order to be most efficient I would first ensure that you have the
possessive relationships are in place. If so you would be able to
include Training when Calling Initiative.
Initiative.all.includes(:training).each do |initiative|
puts initiative.training.size
end
This will utilize eager loading to reduce this run to 2 queries. The
issue with this would be dataset size, imagine if you have 1000
initiatives with a total of 300,000 trainings between them. You will
need to be able to hold all of those trainings in memory to run
this. Not efficient.
Likewise your methodology is not efficient as it essentially is an
n+1 anitpattern, meaning that you will be doing n queries to get the
trainings and another 1 for the initiatives. So if you have 1000
initiatives that will be 1001 queries.
So the better way to do this would be to have a counter cache of
trainings on the initiative model. This would involve adding a
trainings_count field to initiative and then setting the
relationship on the training model to something like
belongs_to :initiative, counter_cache: true
Then when you call initiative.training.size, rails would look to the
data in that field before trying to pull the data from the database,
so you would be able to use
Initiative.all.each do |initiative|
puts initiative.training.size
end
Note that, when adding counter_caching to an existing model set you
will need to run a process (pref in the migration) to reset the
counters for the model.
This could be your migration file. Though using a pure sql statement
might be more efficient.
add_column :initiatives, :trainings_count, null: false, default: 0
Initiative.all.each do |i|
Initiative.reset_counters(
i.id, :trainings)
end
hope this helps