Подстановка имени класса для имени таблицы в запросе ActiveRecord

У меня есть эта строка:

factory.workers.where.not(confirmed_at:nil).where(job_roles: {heavy_lifting:true, sensitive_area: false}).pluck(:work_capacity)

Но таблица ассоциаций job_roles зависит от названия класса фабрики, а у меня 5 типов фабрик. Итак, если factory.class.name == "DistributionCenter", то job_roles на самом деле будет distribution_center_roles, а если factory.class.name == "AutomotiveAssemblyPlant", то job_roles будет automotive_assembly_plant_roles и т. д.

Есть ли способ добавить имя класса в имя таблицы связей в коде запроса ActiveRecord, чтобы вместо job_roles было написано distribution_center_roles или automotive_assembly_plant_roles (и т. д.), в зависимости от имени класса factory?

лиииике

factory.workers.where.not(confirmed_at:nil).where((factory.class.name + "_roles").string_to_tablename_rails_method: {heavy_lifting:true, sensitive_area: false}).pluck(:work_capacity)

или мне нужно сделать:

if factory.is_a?(DistributionCenter)
  factory.workers.where.not(confirmed_at:nil).where(distribution_center_roles: {heavy_lifting:true, sensitive_area: false}).pluck(:work_capacity)
elsif factory.is_a?(AutomotiveAssemblyPlant)
  factory.workers.where.not(confirmed_at:nil).where(automotive_assembly_plant_roles: {heavy_lifting:true, sensitive_area: false}).pluck(:work_capacity)
etc
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если название стола основано на названии модели, вы можете просто подчеркнуть его.

job_roles = :"#{factory.class.name.underscore}_roles"

Если для модели используется какое-то пространство имен, вам, вероятно, также потребуется параметризовать

job_roles = :"#{factory.class.name.undercore.parameterize(separator: '_')}_roles"

Сравнивать:

Asdf::FooBar.name.underscore
# => "asdf/foo_bar"

Asdf::FooBar.name.underscore.parameterize(separator: '_')
# => "asdf_foo_bar"

Если имя таблицы основано на имени таблицы, вы можете таблизировать ее.

job_roles = :"#{factory.class.name.tableize}_roles"

Также можно использовать ActiveRecord::Base::table_name

Это также будет работать, даже если вы переопределите table_name внутри модели или используете пользовательские table_name_prefix / table_name_suffix

job_roles = :"#{factory.class.table_name}_roles"

После этого вы можете применить его к своему запросу.

factory.workers.where.not(confirmed_at:nil).where(job_roles => {heavy_lifting:true, sensitive_area: false}).pluck(:work_capacity)

Хотя это один из способов сделать это, помните, что вы создаете довольно хрупкое решение, поскольку в результате из моделей свисает множество движущихся частей.

max 20.04.2024 16:13
Ответ принят как подходящий

Я бы использовал ActiveModel::Naming и отражение, если вы хотите сделать это менее хакерским способом:

module RoleScoped
  def with_roles(**conditions)
     reflect_on_assocation(:"#{model_name.singular}_roles")
       .compute_class
       .where(conditions)
  end
end

class DistributionCenter < ApplicationModel
  extend RoleScoped
end

class AutomotiveAssemblyPlant < ApplicationModel
  extend RoleScoped
end

factory.workers
       .where.not(confirmed_at:nil) 
       .merge(factory.class.with_roles(heavy_lifting:true, sensitive_area: false))
       .pluck(:work_capacity)

Это позволяет избежать предположений об именах таблиц. Еще лучше было бы назвать ассоциацию одним и тем же в двух классах, чтобы вам вообще не приходилось возиться.

class DistributionCenter
  has_many :roles, class_name: 'DistributionCenterRole'
end

class AutomotiveAssemblyPlant
  has_many :roles, class_name: 'AutomotiveAssemblyPlantRole'
end


factory.workers
       .where.not(confirmed_at:nil) 
       .merge(factory.roles.where(heavy_lifting:true, sensitive_area: false))
       .pluck(:work_capacity)

Второй прекрасен, первый — следующий уровень, о котором мне придется прочитать.

daveasdf_2 20.04.2024 20:18
reflect_on_assocation(:"#{model_name.singular}_roles") на самом деле это просто способ получить метаданные об ассоциации. И затем compute_class получает целевой класс ассоциации.
max 21.04.2024 13:00

Другие вопросы по теме