Active Model Serializer caching of calculated field - ruby-on-rails

I'm trying to to cache a collection of items, this is my AMS:
class ApplicationCategorySerializer < ActiveModel::Serializer
cache({})
cache key: 'application_category', expires_in: 3.days
attributes :id
attributes :name
attributes :active
attributes :group
attributes :num_of_protocols
belongs_to :group do |serializer|
serializer.attributes[:group][:name]
end
def num_of_protocols
ApplicationCategory.find(object.id).protocol_categories.count
end
end
My problem is that without the :num_of_protocols part it takes 10 times faster to generate the response,
when I look at the log I can see:
Started GET "/application_categories.json" for 127.0.0.1 at 2016-08-04 19:12:27 +0300
Processing by ApplicationCategoriesController#index as JSON
ApplicationCategory Load (3.0ms) SELECT "application_categories".* FROM "application_categories"
[active_model_serializers] Group Load (1.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = ? LIMIT 1 [["id", 2066]]
[active_model_serializers] ApplicationCategory Load (0.0ms) SELECT "application_categories".* FROM "application_categories" WHERE "application_categories"."id" = ? LIMIT 1 [["id", 1]]
[active_model_serializers] (0.0ms) SELECT COUNT(*) FROM "protocol_categories" INNER JOIN "application_categories_protocol_categories" ON "protocol_categories"."id" = "application_categories_protocol_categories"."protocol_category_id" WHERE "application_categories_protocol_categories"."application_category_id" = ? [["application_category_id", 1]]
[active_model_serializers] CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = ? LIMIT 1 [["id", 2066]]
[active_model_serializers] ApplicationCategory Load (0.0ms) SELECT "application_categories".* FROM "application_categories" WHERE "application_categories"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] (0.0ms) SELECT COUNT(*) FROM "protocol_categories" INNER JOIN "application_categories_protocol_categories" ON "protocol_categories"."id" = "application_categories_protocol_categories"."protocol_category_id" WHERE "application_categories_protocol_categories"."application_category_id" = ? [["application_category_id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = ? LIMIT 1 [["id", 2066]]
...................... [many many more lines like those...]
[active_model_serializers] CACHE (0.0ms) SELECT "application_categories".* FROM "application_categories" WHERE "application_categories"."id" = ? LIMIT 1 [["id", 608]]
[active_model_serializers] CACHE (0.0ms) SELECT COUNT(*) FROM "protocol_categories" INNER JOIN "application_categories_protocol_categories" ON "protocol_categories"."id" = "application_categories_protocol_categories"."protocol_category_id" WHERE "application_categories_protocol_categories"."application_category_id" = ? [["application_category_id", 608]]
[active_model_serializers] CACHE (0.0ms) SELECT "application_categories".* FROM "application_categories" WHERE "application_categories"."id" = ? LIMIT 1 [["id", 609]]
[active_model_serializers] CACHE (0.0ms) SELECT COUNT(*) FROM "protocol_categories" INNER JOIN "application_categories_protocol_categories" ON "protocol_categories"."id" = "application_categories_protocol_categories"."protocol_category_id" WHERE "application_categories_protocol_categories"."application_category_id" = ? [["application_category_id", 609]]
[active_model_serializers] CACHE (0.0ms) SELECT "application_categories".* FROM "application_categories" WHERE "application_categories"."id" = ? LIMIT 1 [["id", 610]]
[active_model_serializers] CACHE (0.0ms) SELECT COUNT(*) FROM "protocol_categories" INNER JOIN "application_categories_protocol_categories" ON "protocol_categories"."id" = "application_categories_protocol_categories"."protocol_category_id" WHERE "application_categories_protocol_categories"."application_category_id" = ? [["application_category_id", 610]]
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModelSerializers::Adapter::Attributes (1521.15ms)
how can I get better results with caching? - when I comment out the cache lines I get aprox. same times as with them, when I remove the :num_of_protocols I get same time with & without cache.
what am I configuring wrong?

Can you do this?
def num_of_protocols
object.protocol_categories.count
end
And, it's been a while for serializers for me, but I thought you were able to do this...
def num_of_protocols
protocol_categories.count
end
And this is better ruby (in the case protocal_categories is already loaded as an array)
def num_of_protocols
protocol_categories.size
end
And, if all that works or not, make sure you include protocol_categories and groups when you instantiate #application_category before you render to json. You're doing too many queries.

Related

Solidus Paypal checkout fails in sandbox for non-PayPal payment variants

I have built a webshop in Ruby on Rails using Solidus.
When I try to checkout in the PayPal sandbox with credit card or SEPA with a German address, it complains that the shop does not deliver there.
It works fine when I use PayPal payment with an account, also to a German address in Berlin...
This is the error in the ruby console:
Started GET "/solidus_paypal_commerce_platform/shipping_rates?order_id=R977809399&order_token=[FILTERED]&address%5Bcity%5D=Berlin&address%5Bstate%5D=&address%5Bcountry_code%5D=DE&address%5Bpostal_code%5D=10117" for 127.0.0.1 at 2022-09-29 20:29:49 +0200
Processing by SolidusPaypalCommercePlatform::ShippingRatesController#simulate_shipping_rates as */*
Parameters: {"order_id"=>"R977809399", "order_token"=>"[FILTERED]", "address"=>{"city"=>"Berlin", "state"=>"", "country_code"=>"DE", "postal_code"=>"10117"}}
Spree::User Load (0.1ms) SELECT "spree_users".* FROM "spree_users" WHERE "spree_users"."deleted_at" IS NULL AND "spree_users"."spree_api_key" = ? LIMIT ? [["spree_api_key", "undefined"], ["LIMIT", 1]]
Spree::Order Load (0.1ms) SELECT "spree_orders".* FROM "spree_orders" WHERE "spree_orders"."number" = ? LIMIT ? [["number", "R977809399"], ["LIMIT", 1]]
Spree::User Load (0.1ms) SELECT "spree_users".* FROM "spree_users" WHERE "spree_users"."deleted_at" IS NULL AND "spree_users"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
CACHE Spree::Order Load (0.0ms) SELECT "spree_orders".* FROM "spree_orders" WHERE "spree_orders"."number" = ? LIMIT ? [["number", "R977809399"], ["LIMIT", 1]]
CACHE Spree::User Load (0.0ms) SELECT "spree_users".* FROM "spree_users" WHERE "spree_users"."deleted_at" IS NULL AND "spree_users"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
TRANSACTION (0.0ms) begin transaction
Spree::Country Load (0.1ms) SELECT "spree_countries".* FROM "spree_countries" WHERE "spree_countries"."iso" = ? LIMIT ? [["iso", "DE"], ["LIMIT", 1]]
Spree::State Load (0.1ms) SELECT "spree_states".* FROM "spree_states" WHERE "spree_states"."country_id" = ? AND "spree_states"."abbr" = ? ORDER BY "spree_states"."name" ASC LIMIT ? [["country_id", 57], ["abbr", ""], ["LIMIT", 1]]
Spree::State Load (0.1ms) SELECT "spree_states".* FROM "spree_states" WHERE "spree_states"."country_id" = ? AND "spree_states"."name" = ? ORDER BY "spree_states"."name" ASC LIMIT ? [["country_id", 57], ["name", ""], ["LIMIT", 1]]
Spree::Store Load (0.0ms) SELECT "spree_stores".* FROM "spree_stores" WHERE "spree_stores"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Spree::Order Exists? (0.1ms) SELECT 1 AS one FROM "spree_orders" WHERE "spree_orders"."number" = ? AND "spree_orders"."id" != ? LIMIT ? [["number", "R977809399"], ["id", 10], ["LIMIT", 1]]
Spree::Adjustment Load (0.0ms) SELECT "spree_adjustments".* FROM "spree_adjustments" WHERE "spree_adjustments"."order_id" = ? AND "spree_adjustments"."source_type" = ? [["order_id", 10], ["source_type", "Spree::PromotionAction"]]
Spree::LineItem Load (0.0ms) SELECT "spree_line_items".* FROM "spree_line_items" WHERE "spree_line_items"."order_id" = ? ORDER BY "spree_line_items"."created_at" ASC, "spree_line_items"."id" ASC [["order_id", 10]]
Spree::Product Load (0.0ms) SELECT "spree_products".* FROM "spree_products" INNER JOIN "spree_variants" ON "spree_products"."id" = "spree_variants"."product_id" WHERE "spree_variants"."id" = ? LIMIT ? [["id", 45], ["LIMIT", 1]]
TRANSACTION (0.0ms) rollback transaction
Completed 422 Unprocessable Entity in 35ms (Views: 0.2ms | ActiveRecord: 0.8ms | Allocations: 31326)
Would be grateful for any pointers where to adjust that,
as I cannot make head or tail of it.
I don't know why Solidus is erroring internally, but I can tell you that if the rendered PayPal button has an onShippingChange callback yet that callback does not respond with success or times out (due to some error, generally), the PayPal checkout will give that message since you're indicating the address needs to be checked during payment approval yet are not responding that it's OK when queried.
Another possible flow design -- likely not used/offered by Solidus -- is to not specify onShippingChange and to check the address after approval (but before final order capture) and provide a mechanism to patch it when it's not a valid address you'll accept.

Page loads unnecessary queries Ruby On Rails

I have a weird problem, every page of my website that contains database queries loads some extra items. I've never had this problem before, tried to check all controllers but haven't found any problems. Here is an example of output when I load (or refresh) home page:
=> Booting Puma
=> Rails 5.1.6 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.0 (ruby 2.5.0-p0), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Started GET "/c/wines" for 127.0.0.1 at 2018-11-02 15:55:30 -0400 (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by CatalogsController#show as HTML
Parameters: {"id"=>"wines"}
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."slug" = ? LIMIT ? [["slug", "wines"], ["LIMIT", 1]]
Rendering catalogs/show.html.haml within layouts/application (0.2ms) SELECT COUNT(*) FROM "categories" WHERE "categories"."catalog_id" = ? [["catalog_id", 1]] (0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Category Exists (0.3ms) SELECT 1 AS one FROM "categories" WHERE "categories"."catalog_id" = 1 AND "categories"."open" = ? LIMIT ? [["open", "t"], ["LIMIT", 1]]
Category Load (0.9ms) SELECT "categories".* FROM "categories" WHERE "categories"."catalog_id" = 1 AND "categories"."open" = ? [["open", "t"]]
CACHE Category Load (0.0ms) SELECT "categories".* FROM "categories" WHERE "categories"."catalog_id" = 1 AND "categories"."open" = ? [["open", "t"]]
CACHE Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."catalog_id" = 1 AND "categories"."open" = ? [["open", "t"]]
Product Load (0.8ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 AND "products"."open" = ? AND "products"."category_id" = 1 [["open", "t"]]
Catalog Load (0.7ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
Product Load (0.3ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 AND "products"."open" = ? AND "products"."category_id" = 2 [["open", "t"]]
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
Rendered catalogs/show.html.haml within layouts/application (142.7ms)
Rendered application/_favicon.html.haml (11.1ms)
Catalog Load (0.4ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_navbar.html.haml (23.7ms)
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_footer.html.haml (15.7ms)
Completed 200 OK in 937ms (Views: 890.8ms | ActiveRecord: 9.4ms)
Started GET "/uploads/catalog/photo/1/hero-8.png" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Started GET "/" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Processing by StaticController#home as HTML
Started GET "/uploads/product/photo/4/pc_pistachio.png" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Started GET "/uploads/product/photo/7/pc_pistachio.png" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Started GET "/uploads/product/photo/1/pc_creame.png" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Started GET "/uploads/product/photo/10/pc_pistachio.png" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Rendering static/home.html.haml within layouts/application
Catalog Load (0.3ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? ORDER BY created_at ASC LIMIT ? [["open", "t"], ["LIMIT", 6]]
(0.3ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
CACHE (0.0ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Product Exists (0.4ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 1]]
Product Load (0.9ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 2
Product Exists (0.2ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 1]]
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 2
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 3
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 3
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 1]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 3
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 2
Rendered static/home.html.haml within layouts/application (95.0ms)
Rendered application/_favicon.html.haml (15.0ms)
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_navbar.html.haml (19.9ms)
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_footer.html.haml (18.0ms)
Completed 200 OK in 400ms (Views: 389.1ms | ActiveRecord: 4.3ms)
Started GET "/" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Started GET "/" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Processing by StaticController#home as HTML
Started GET "/" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Started GET "/" for 127.0.0.1 at 2018-11-02 15:55:31 -0400
Processing by StaticController#home as HTML
Rendering static/home.html.haml within layouts/application
Processing by StaticController#home as HTML
Catalog Load (0.5ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? ORDER BY created_at ASC LIMIT ? [["open", "t"], ["LIMIT", 6]]
Rendering static/home.html.haml within layouts/application
Processing by StaticController#home as HTML
Catalog Load (0.4ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? ORDER BY created_at ASC LIMIT ? [["open", "t"], ["LIMIT", 6]]
Rendering static/home.html.haml within layouts/application
(0.3ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
CACHE (0.0ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 1]]
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? ORDER BY created_at ASC LIMIT ? [["open", "t"], ["LIMIT", 6]]
(0.1ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
CACHE (0.0ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Product Exists (0.2ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 1]]
Rendering static/home.html.haml within layouts/application
(0.4ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? ORDER BY created_at ASC LIMIT ? [["open", "t"], ["LIMIT", 6]]
Product Load (0.3ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 6]]
(0.1ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
CACHE (0.0ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
CACHE (0.0ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Product Exists (0.2ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 1]]
Category Load (0.3ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
Product Load (0.4ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 6]]
Product Exists (0.4ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 1]]
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 2
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 1]]
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 2
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 3
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 3
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 1]]
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 2
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 6]]
Product Exists (0.4ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 1]]
Product Load (0.3ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 2
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
Product Load (0.4ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 6]]
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 2
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 2
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 1]]
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 2
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 3
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 3
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 1]]
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 3
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 1]]
Product Load (0.3ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 3
Catalog Load (0.4ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 3
Product Load (0.6ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 6]]
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 3
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 1]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 3
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 2
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 2
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 3
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 2
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 2
Rendered static/home.html.haml within layouts/application (206.4ms)
Rendered application/_favicon.html.haml (6.5ms)
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 3
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 1]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 3
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 2
Rendered static/home.html.haml within layouts/application (195.5ms)
Rendered application/_favicon.html.haml (0.1ms)
Rendered static/home.html.haml within layouts/application (246.3ms)
Rendered static/home.html.haml within layouts/application (255.3ms)
Rendered application/_favicon.html.haml (0.1ms)
Rendered application/_favicon.html.haml (0.0ms)
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_navbar.html.haml (13.9ms)
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_footer.html.haml (9.7ms)
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_navbar.html.haml (3.2ms)
Catalog Load (0.3ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_navbar.html.haml (3.2ms)
Rendered shared/_navbar.html.haml (14.3ms)
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_footer.html.haml (5.9ms)
Rendered shared/_footer.html.haml (3.0ms)
Rendered shared/_footer.html.haml (6.0ms)
Completed 200 OK in 859ms (Views: 853.1ms | ActiveRecord: 3.5ms)
Completed 200 OK in 802ms (Views: 795.7ms | ActiveRecord: 4.0ms)
Completed 200 OK in 849ms (Views: 842.5ms | ActiveRecord: 3.7ms)
Started GET "/" for 127.0.0.1 at 2018-11-02 15:55:32 -0400
Processing by StaticController#home as HTML
Completed 200 OK in 858ms (Views: 851.2ms | ActiveRecord: 3.8ms)
Rendering static/home.html.haml within layouts/application
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? ORDER BY created_at ASC LIMIT ? [["open", "t"], ["LIMIT", 6]]
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
CACHE (0.0ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Product Exists (0.3ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 1]]
Product Load (0.6ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.4ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
(0.5ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 2
Product Exists (0.2ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 1]]
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 2
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 3
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 3
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 1]]
Product Load (0.4ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.3ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 3
Category Load (0.5ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 2
Rendered static/home.html.haml within layouts/application (58.7ms)
Rendered application/_favicon.html.haml (9.7ms)
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_navbar.html.haml (16.9ms)
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_footer.html.haml (11.7ms)
Completed 200 OK in 261ms (Views: 254.4ms | ActiveRecord: 4.7ms)
My Static controller:
class StaticController < ApplicationController
def home
#catalogs = Catalog.all.where(open: true).order('created_at ASC').limit(6)
# #products = Product.all.includes(:catalog, :category).where(open: true).order('created_at DESC').take(8)
end
def about
#catalogs = Catalog.all.where(open: true)
#categories = Category.all.where(open: true)
#products = Product.all.where(open: true)
end
def download_pdf
send_file "#{Rails.root}/app/assets/docs/1_s.pdf", type: "application/pdf", x_sendfile: true
end
end
Note: I have similar problems with other controllers
At the beginning I thought that it's a bag because I didn't add any new code. Please, let me know if you need more code from controllers. Thank you very much for your time and help.
UPDATE
Application Controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :prepare_meta_tags, if: "request.get?"
def prepare_meta_tags(options={})
site_name = "Alvian Imports Inc."
title = "Alvain Imports Inc."
description = "For many years, Alvian imports alcohol accross Florida state and now it's time to grow. Absolutly new team with new products that will be loved by everyone. We have an exclusive partnership with Ponche Caribe and we are starting to deliver our products to Texas, California, Mexico, and Columbia. Our goal is to make alcohol importation better and faster, so our team is working hard to deliver wonderful products to your closest stores."
image = options[:image] || "app/assets/images/brand/logo.png"
current_url = request.url
# Let's prepare a nice set of defaults
defaults = {
site: site_name,
title: title,
image: image,
description: description,
keywords: %w[food food processor food service food and drink f&b food industry food and beverage service food & beverage food processing industry food and beverage manager food and beverage industry food service jobs food beverage beverage industry food service companies f&b service food service worker food industry jobs food service industry food & drink food drink food and beverage management types of food service f&b industry food and beverage department import imports alvian alvianimports miami usa florida],
twitter: {
site_name: site_name,
site: '#IncAlvian',
card: 'The Beverage Company. Ponche Caribe Curacao Blue & Liquors Exclusive Distributor Florida - Texas - California - Colombia Distributor. Must be 21 +',
description: description,
image: image
},
og: {
url: current_url,
site_name: site_name,
title: title,
image: image,
description: description,
type: 'website'
}
}
options.reverse_merge!(defaults)
set_meta_tags options
end
end
Application.html.haml code:
!!!
%html(lang="en-US" class="region--#{controller.controller_name}")
%head
= display_meta_tags
%meta(http-equiv="X-UA-Compatible" content="IE=edge,chrome=1")
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%meta{:charset => "utf-8"}/
%meta{:content => "width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no", :name => "viewport"}/
%meta{:content => "user-scalable=no, width=device-width, initial-scale=1.0", :name => "viewport"}/
%meta{:content => "yes", :name => "apple-mobile-web-app-capable"}/
%meta{:'http-equiv' => "X-UA-Compatible", :content => "IE=edge"}
%meta{:name => "HandheldFriendly", :contnet => "true"}
%meta{:name => "MobileOptimized", :content => "176"}
= render 'application/favicon'
%title #{content_for?(:title) ? yield(:title) : 'Alvian Imports'}
= csrf_meta_tags
= stylesheet_link_tag 'application', media: 'all'
= analytics_init if GoogleAnalytics.valid_tracker?
%body(class = '#{controller.controller_name}')
%div(class="application-wrapper")
= render partial: 'shared/navbar'
= content_tag :main, class: "layout layout-#{controller.action_name}" do
= yield
= render partial: 'shared/footer'
- unless params[:nojs]
= javascript_include_tag 'application'
UPDATE 2
I have 3 models: Catalog, Category, and Products.
Catalog model:
class Catalog < ApplicationRecord
extend FriendlyId
friendly_id :name, use: [:slugged, :history]
mount_uploader :photo, PhotoUploader
has_many :categories, dependent: :delete_all
has_many :products, :through => :categories, :source => :catalog, dependent: :delete_all
# Important fields
validates_presence_of :name
end
Category model:
class Category < ApplicationRecord
extend FriendlyId
friendly_id :name, use: [:slugged, :history]
belongs_to :catalog, :foreign_key => 'catalog_id'
has_many :products, dependent: :delete_all
# Important fields
validates_presence_of :name
def self.active
where(status: 1)
end
end
Product model:
class Product < ApplicationRecord
extend FriendlyId
friendly_id :name, use: [:slugged, :history]
mount_uploader :photo, PhotoUploader
belongs_to :catalog, :foreign_key => 'catalog_id'
belongs_to :category, :foreign_key => 'category_id'
# Important fields
validates_presence_of :name
end
Expected output in the console:
Started GET "/" for 127.0.0.1 at 2018-11-02 16:41:26 -0400
Processing by StaticController#home as HTML
Rendering static/home.html.haml within layouts/application
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? ORDER BY created_at ASC LIMIT ? [["open", "t"], ["LIMIT", 6]]
(0.1ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
CACHE (0.0ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 1
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 1]]
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 1 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 1
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
(0.2ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 2
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 1]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 2 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.1ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 2
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 3
(0.3ms) SELECT COUNT(*) FROM "products" WHERE "products"."catalog_id" = 3
Product Exists (0.3ms) SELECT 1 AS one FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 1]]
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."catalog_id" = 3 LIMIT ? [["LIMIT", 6]]
Catalog Load (0.3ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."id" = 3
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = 2
Rendered static/home.html.haml within layouts/application (44.4ms)
Rendered application/_favicon.html.haml (7.9ms)
Catalog Load (0.2ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_navbar.html.haml (15.8ms)
CACHE Catalog Load (0.0ms) SELECT "catalogs".* FROM "catalogs" WHERE "catalogs"."open" = ? [["open", "t"]]
Rendered shared/_footer.html.haml (8.9ms)
Completed 200 OK in 218ms (Views: 213.2ms | ActiveRecord: 3.1ms)
Home page HTML (HAML), however it has to be mentioned that I get similar problem with other pages that requires queries (for example catalog show pages):
= content_for :navbar_class, "navbar-dark"
%section(class="hero hero-homepage")
%div(class="hh-container")
%div(class="hh-carousel")
- #catalogs.each do |catalog|
%div(class="hhc-item")
= link_to catalog, class: 'hhc-container' do
%div(class="hhc-background" style="background-image: url(#{catalog.photo});")
-# = image_tag(catalog.photo, lazy: true, class: "hhc-background")
%div(class="hhc-caption")
%h4(class="heading heading-1 is-light") #{catalog.name}
- if !catalog.description.empty?
%p(class="text text-2 is-light is-transparent") #{truncate(catalog.description, :length => 112)}
%section(class="section")
- #catalogs.each do |pc|
- #products = Product.all.where(catalog_id: pc)
%div(class="content")
%div(class="header header-hr")
%span
%h4(class="heading heading-4") New #{pc.name}
- if #products.count > 6
%span
= link_to "View all " + #products.count.to_s, pc, class: "link link-secondary link-arrow"
%div(class="row")
- if !#products.empty?
- #products.includes(:catalog, :category).take(6).each do |p|
%div(class="col-xs-6 col-md-4 col-lg-3")
= link_to catalog_category_product_url(p.catalog, p.category, p), class: "block block-product" do
= image_tag p.photo, alt: p.name, class: 'bp-photo', lazy: true
%div(class="bp-desc")
%span
%h5(class="heading heading-5") #{p.name}
%span
%p(class="text text-3")
%span.is-primary #{p.catalog.name}
%span - #{p.category.name}
- else
%div(class="col-xs-12 is-centered")
%h5(class="heading heading-5") Currently this list is empty.
UPDATE 3
Ok, I didn't understand the course of the problem but I decided to recreate the database:
rake db:drop db:create db:migrate
Fixed the problem..
A whole bunch of things and hard to help without actually running the code.
First of all, familiarize yourself with good practice in regards of naming things.
#catalogs.each do |pc| is a no-no and should be #catalogs.each do |catalog|.
if !#products.empty? and #product.count, those trigger two queries and my recommendation is to write the count into #products_count and replace that empty? with #product_count > 0
Use scope in the model to replace things like .where(open: true)
In #products.includes(:catalog, :category) you can remove the catalog because you already walk the products by catalog and can use pc (or as I recommended above: catalog) instead of product.catalog
If catalog_category_product_url doesn't use anything fancy but just the ids (e.g. catalog/5/category/2/product/23) then you can do catalog_category_product_url(product.catalog_id, product.category_id, product) to prevent a few extra queries (especially if you forgot to use eager loading or don't want to load a big chunk of data from the db).

Rails includes vs all?

I am going back to refresh my Rails knowledge by watching some tutorials, and I came across where the tutorial rails app uses includes() on index.
def index
#books = Book.all
end
vs
def index
#books = Book.includes(:author, :genre)
end
As a side note, book belongs_to author and genre. Author has_many books and genre also has_many books.
When all is used, it looks like this when I refresh page:
Rendering books/index.html.erb within layouts/application
Book Load (1.4ms) SELECT "books".* FROM "books"
Author Load (0.3ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
Genre Load (0.3ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
Author Load (0.4ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Genre Load (0.3ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
When includes is used, when I reload the page it shows:
Rendering books/index.html.erb within layouts/application
Book Load (0.4ms) SELECT "books".* FROM "books"
Author Load (0.5ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" IN (2, 1)
Genre Load (0.4ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" IN (2, 3)
I think this makes includes far more efficient than all because it hits the entire model database.
My question is, why do people still use all? Why not completely eradicate all and use includes from now on? Is there any situation where I would prefer to use all and not use includes? I am using Rails 5.0.1.
Let me talk a little bit about includes.
Suppose you need to get the user name of first five post. You quickly write the query below and go enjoy your weekend.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Good. But let's look at the queries
Post Load (0.5ms) SELECT `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
1 query to fetch all posts and 1 query to fetch users for each post results in a total of 6 queries. Check out the solution below which does the same thing, just in 2 queries:
posts = Post.includes(:user).limit(5)
posts.each do |post|
puts post.user.name
end
#####
Post Load (0.3ms) SELECT `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 2)
There’s one little difference. Add includes(:posts) to your query, and problem solved. Quick, nice, and easy.
But don’t just add includes in your query without understanding it properly. Using includes with joins might result in cross-joins depending on the situation, and you don’t need that in most cases.
If you want to add conditions to your included models you’ll have to explicitly reference them. For example:
User.includes(:posts).where('posts.name = ?', 'example')
Will throw an error, but this will work:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Note that includes works with association names while references needs the actual table name.

n + 1 issue when ordering by child's attribute

The following query suffers from the 'n+1' problem of loading each order for each record:
Job.joins('LEFT JOIN orders ON orders.job_id = jobs.id').order("orders.featured")
Same for this:
Job.includes(:order).order("orders.featured")
Removing the .order(...) part removes the n + 1 issue, but then it's not ordered. Any ideas how to fix this? Do I need to create a column in the parent for the 'featured' attribute?
Output:
Order Load (0.4ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 26]]
Rendered jobs/_job.html.erb (1.9ms)
Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 3]]
Rendered jobs/_job.html.erb (2.0ms)
Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 52]]
Rendered jobs/_job.html.erb (1.7ms)
Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 13]]
Rendered jobs/_job.html.erb (1.9ms)
Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 34]]
Rendered jobs/_job.html.erb (1.9ms)
Order Load (0.4ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 64]]
Rendered jobs/_job.html.erb (2.8ms)
Order Load (0.4ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 94]]
Rendered jobs/_job.html.erb (3.2ms)
Order Load (0.4ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 60]]
Rendered jobs/_job.html.erb (3.1ms)
Order Load (0.4ms) SELECT "orders".* FROM "orders" WHERE "orders"."job_id" = $1 LIMIT 1 [["job_id", 29]]
Try using preload for the associated data:
Job.joins('LEFT JOIN orders ON orders.job_id = jobs.id')
.order("orders.featured")
.preload(:orders)
Job.includes(:order).order("orders.featured")
Includes doesn't join the tables together until you call it in the view. It will actually do 2 queries. If you want the 2 tables to be joined to do the order, you need to use eager_load:
Job.eager_load(:order).order("orders.featured")
http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html

Rails 4 - Why does using includes() not make a join between Pins and Replies?

I'm a Rails and Ruby newcomer. I want to optimise SQL queries where I can and I was reading about using includes() to make Rails aware, that I want to eager load and join two tables.
In my show action on the pin controller:
def show
#pin = Pin.includes(:replies, :user).where(id: params[:id]).first
end
If I check the log on the queries, I see the following:
Started GET "/pin/1703704382" for 127.0.0.1 at 2014-06-12 15:30:18 +0100
Processing by PinsController#show as HTML
Parameters: {"id"=>"1703704382"}
Pin Load (0.2ms) SELECT `pins`.* FROM `pins` WHERE `pins`.`id` = 145 ORDER BY `pins`.`id` ASC LIMIT 1
Reply Load (0.1ms) SELECT `replies`.* FROM `replies` WHERE `replies`.`pin_id` IN (145)
User Load (0.1ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (22)
User Load (0.1ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 22 LIMIT 1
Profile Load (0.1ms) SELECT `profiles`.* FROM `profiles` WHERE `profiles`.`user_id` = 22 ORDER BY `profiles`.`id` ASC LIMIT 1
CACHE (0.0ms) SELECT `profiles`.* FROM `profiles` WHERE `profiles`.`user_id` = 22 ORDER BY `profiles`.`id` ASC LIMIT 1 [["user_id", 22]]
Type Load (0.1ms) SELECT `types`.* FROM `types` WHERE `types`.`id` = 1 ORDER BY `types`.`id` ASC LIMIT 1
Skill Load (0.1ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`id` = 3 ORDER BY `skills`.`id` ASC LIMIT 1
Instrument Load (0.2ms) SELECT `instruments`.* FROM `instruments` WHERE `instruments`.`id` = 6 ORDER BY `instruments`.`id` ASC LIMIT 1
Genre Load (0.1ms) SELECT `genres`.* FROM `genres` INNER JOIN `genre_pins` ON `genres`.`id` = `genre_pins`.`genre_id` WHERE `genre_pins`.`pin_id` = 145
Bookmark Load (0.1ms) SELECT `bookmarks`.* FROM `bookmarks` WHERE `bookmarks`.`pin_id` = 145
User Load (0.1ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 22 ORDER BY `users`.`id` ASC LIMIT 1
(0.2ms) SELECT COUNT(*) FROM `bookmarks` WHERE `bookmarks`.`pin_id` = 145
(0.1ms) SELECT COUNT(*) FROM `replies` WHERE `replies`.`pin_id` = 145
Rendered partials/_pin.html.erb (14.3ms)
Pin Load (0.1ms) SELECT `pins`.* FROM `pins` WHERE `pins`.`id` = 145 ORDER BY `pins`.`id` ASC LIMIT 1
CACHE (0.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 22 ORDER BY `users`.`id` ASC LIMIT 1 [["id", 22]]
CACHE (0.0ms) SELECT `profiles`.* FROM `profiles` WHERE `profiles`.`user_id` = 22 ORDER BY `profiles`.`id` ASC LIMIT 1 [["user_id", 22]]
Rendered replies/_reply.html.erb (4.0ms)
Rendered replies/_form.html.erb (1.5ms)
Rendered pins/show.html.erb within layouts/application (21.7ms)
Rendered partials/_meta.html.erb (0.1ms)
Rendered partials/_top.html.erb (1.3ms)
Rendered partials/_tags.html.erb (0.1ms)
Rendered partials/_search.html.erb (1.0ms)
Completed 200 OK in 33ms (Views: 27.2ms | ActiveRecord: 2.0ms | Solr: 0.0ms)
It seems like it is running separate queries to get pins, replies and the user. How can I join these into one query? Surely this could be better optimised.
Thanks for your advice and patience!
It seems like it is running separate queries to get pins, replies and the user. How can I join these into one query? Surely this could be better optimised.
This is not automatically true. Hydration (the fact of creating nested records, etc, since you don't get in a hierarchical structure from your DB) can be very costly with many relations. It's actually often times better for your performance to use only a very simple query to fetch every record of one table.
If you still want to join (with shallow relations, it's probably better), you can use .joins

Resources