Using Rails 7 and Mobility 1.2.9:
# config/initializers/mobility.rb
Mobility.configure do |config|
config.plugins do
backend :table
active_record
reader
writer
backend_reader
query
cache
dirty
presence
end
end
# app/models/content.rb
class Content < ApplicationRecord
extend Mobility
translates :slug, :title
end
How to find contents by slug, instantiate them into Content
objects and query their translated attributes using one single SQL statement (for an unchanging locale)? The examples below with and without eager_loading run 2 SQL statements.
> content = Content.i18n.find_by(slug: "foo")
Content Load (0.7ms) SELECT "contents".* FROM "contents" INNER JOIN "content_translations" "content_translations_en" ON "content_translations_en"."content_id" = "contents"."id" AND "content_translations_en"."locale" = 'en' WHERE "content_translations_en"."slug" = 'foo' LIMIT $1 [["LIMIT", 1]]
> content.title
Content::Translation Load (0.3ms) SELECT "content_translations".* FROM "content_translations" WHERE "content_translations"."content_id" = $1 [["content_id", "..."]]
> content = Content.i18n.eager_load(:translations).find_by(slug: "foo")
SQL (0.6ms) SELECT DISTINCT "contents"."id" FROM "contents" LEFT OUTER JOIN "content_translations" ON "content_translations"."content_id" = "contents"."id" INNER JOIN "content_translations" "content_translations_en" ON "content_translations_en"."content_id" = "contents"."id" AND "content_translations_en"."locale" = 'en' WHERE "content_translations_en"."slug" = 'blog-1-en' LIMIT $1 [["LIMIT", 1]]
SQL (0.8ms) SELECT "contents"."id" AS t0_r0, "contents"."created_at" AS t0_r1, "contents"."updated_at" AS t0_r2, ..., "content_translations"."id" AS t1_r0, "content_translations"."locale" AS t1_r1, "content_translations"."created_at" AS t1_r2, "content_translations"."updated_at" AS t1_r3, "content_translations"."slug" AS t1_r4, "content_translations"."title" AS t1_r5, "content_translations"."content_id" AS t1_r6 FROM "contents" LEFT OUTER JOIN "content_translations" ON "content_translations"."content_id" = "contents"."id" INNER JOIN "content_translations" "content_translations_en" ON "content_translations_en"."content_id" = "contents"."id" AND "content_translations_en"."locale" = 'en' WHERE "content_translations_en"."slug" = 'blog-1-en' AND "contents"."id" = $1 [["id", "..."]]
> content.title
# no DB statement, but there were 2 statements at instantiation
NB: I do not want to pluck attributes but instead to create model instances.