#ruby-on-rails #ruby #mobility
Вопрос:
У меня простая проблема с драгоценным камнем мобильности. У меня есть простое соотношение в моих моделях. Допустим, в компании много сотрудников, и у сотрудников есть переведенный атрибут :job_function
, который используется backend: :table
.
class Company < ApplicationRecord
has_many :employees
end
class Employee < ApplicationRecord
extend Mobility
translates :job_function, type: :string, locale_accessors: true, backend: :table
end
Если я попытаюсь сделать:
Company.first.employees.map(amp;:job_function)
Я понимаю проблему n 1. Каждый из переводов :job_function загружается индивидуально.
Как мне сказать Mobility, чтобы он загрузил их все за один раз, прежде чем я начну сопоставлять коллекцию?
Я не смог найти ни одного примера этого в документации…
Комментарии:
1. Я верю, что вы можете сделать:
Company.first.employees.pluck(:job_function)
.
Ответ №1:
Вы можете просто использовать pluck
, что поддерживается мобильностью:
Company.first.employees.i18n.pluck(:job_function)
Комментарии:
1. я пытался, но
pluck
отдача нулевая2. но
Company.first.employees.i18n.pluck(:job_function)
работа. ты промахнулсяi18n
3. Спасибо! Это правильно, обновил ответ.
4. Зальцберге, у вас было какое-нибудь простое решение на случай, если мы захотим предварительно загрузить сотрудников их переводами (и избежать N 1)?, я имею в виду, что, возможно, оператору не только нужно запросить функции перевода, но и нужно что-то сделать с сотрудниками, отвага не позволит загружать сотрудников.
Ответ №2:
Вы могли includes
бы перевести сотрудников их job_function, это n 2 запроса
вот моя демонстрационная версия, модель продукта содержит множество версий модели, которая была настроена для атрибута name, соответствующих вашей компании, сотруднику, функции job_function соответственно.
class Version < ApplicationRecord
belongs_to :product
extend Mobility
translates :name, locale_accessors: [:en, :ja], backend: :table
end
class Product < ApplicationRecord
has_many :versions
has_many :translation_versions, -> {
i18n{name.not_eq(nil)}
.select("versions.*,
version_translations_#{Mobility.locale}.name AS translate_name")
}, class_name: "Version"
end
С языковым стандартом по умолчанию :en
Product.includes(:translation_versions).first.translation_versions
.map(amp;:translate_name)
# SELECT "products".* FROM "products" ...
# SELECT versions.*, version_translations_en.name AS translate_name
# FROM "versions" LEFT OUTER JOIN "version_translations" "version_translations_en"
# ON "version_translations_en"."version_id" = "versions"."id"
# AND "version_translations_en"."locale" = 'en'
# WHERE "version_translations_en"."name" IS NOT NULL AND "versions"."product_id" = ? ...
# => ["v1", "v2"]
С локализацией :ja
Mobility.locale = :ja
Product.includes(:translation_versions).first.translation_versions
.map(amp;:translate_name)
# ...
# => ["ja v1", "ja v2"]
Так что всего один вопрос.
В случае, если ваш backend
параметр имеет значение KeyValue, таблицы перевода разделяют не только locale
, но и type
(Строка, текст,…), но вы уже решили, какой тип для атрибута, верно ? например: имя:строка. Так что вам все равно нужно только настроить динамическую локаль.
class Product < ApplicationRecord
has_many :translation_versions, -> {
i18n{name.not_eq(nil)}
.select("versions.*,
Version_name_#{Mobility.locale}_string_translations.value AS translate_name")
}, class_name: "Version"
end
запрос такой же, как и выше.
Конечно, вы могли бы сделать translation_versions
это в более общем плане, разделив его на модуль, заменив Version
именем класса, name
целевым атрибутом и сделав динамическую функцию чем-то вроде translation_#{table_name}
.