I have 3 associated tables: Elment, Measurement and Image.
Element has_many Measurements
Measurements has_many Images, also Images has_many Measurements (N-N association)
How can I minimize number of queries in
images = @element.measurements.map {|e| e.images}.reject!(&:blank?)
images.flatten.map {|i| i.file.url}
For this code, there are N queries for every measurement. Can I minimize this with something like this:
@element.measurements.joins(:images).select('images.file')
Query: `
SELECT "images.file" FROM "measurements"
INNER JOIN "images" ON "element_images"."measurement_id" = "measurements"."id"
INNER JOIN "images" ON "element_images"."id" = "images"."image_id"
WHERE "measurements"."element_id" = $1`
Here is step by step replacing:
images = @element.measurements.map {|e| e.images}.reject!(&:blank?)
For this line of code it is better to produce next relation
has_many :images, through: :measurements
# OR for better naming
has_many :measurement_images, through: :measurements, source: :images
Then you can just do:
images = @element.measurement_images
Which will execute next SQL
SELECT *
FROM images
INNER JOIN measurements
ON measurements.id = images.measurement_id
WHERE measurements.element_id = $1
So no need to reject blank images as INNER JOIN just do exactly that, throws away non-matching records, check out the doc
After creating this has_many through relation, next code won't produce any N+1 issues:
images.map {|i| i.file.url}
Also you can minimize the output by adding #select, but I don't advise you to do that, as it complicates code a lot and heavily coupled on image library implementation, so in case of updating library you can break the code.
But for note, if you use paperclip gem with default URL generation pattern you can do something like this:
image_ulrs = @element
.measurement_images
.select(
:id,
:type, # if you have STI model
:<your_file_field>_file_name,
:<your_file_field>_updated_at
).map { |i| i.file.url }
<your_file_field> is the first argument which is passed to has_attached_file for example
has_attached_file :attachment
will result in
...
.select(
:id,
:type, # if you have STI model
:attachment_file_name,
:attachment_updated_at
)
but again I do NOT suggest to do that as it does not give a lot of performance improvement but can be a headache in future.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With