Выбор модели с предложением where, включающим объединенную таблицу с ActiveRecord

#ruby-on-rails #activerecord #where-clause

#ruby-on-rails #activerecord #where-предложение

Вопрос:

проекты == has_many ==> <== has_many == этапы проекта_stages

Я пытаюсь выбрать те проекты, в которых stage.name = ‘завершено’, поэтому я подумал, что сработает одно из следующих действий:

 Project.joins(:stages).where(stages: { name: 'completed' })
Project.where(stage: Stage.find_by(name: 'completed'))
 

Нет кубиков.


Модели:

 class Project < ApplicationRecord
  ...
  has_many :project_stages
  has_many :stages, through: :project_stages
  ...
end
 
 class ProjectStage < ApplicationRecord
  belongs_to :project
  belongs_to :stage
end
 
 class Stage < ApplicationRecord
  has_many :project_stages
end
 

Комментарии:

1. Project.joins(project_stages: :stages).where(stages: { name: 'completed' }).distinct должно работать для вас, хотя в зависимости от того, как вы собираетесь использовать эти данные Project.includes(:project_stages).where(project_stages: {stage_id: Stages.find_by_name('complete').id}) , может быть более эффективным

2. Выдает мне эту ошибку: ActiveRecord::ConfigurationError: Can't join 'ProjectStage' to association named 'stages'; perhaps you misspelled it? (одинаково для обоих)

3. Какой SQL-запрос генерируется из той первой строки, которую вы пробовали?

4. @Daniel причина, по которой вы получили сообщение об ошибке, опубликованное @engineersmnky, заключается в том, что существует небольшая ошибка в том, что этапы множественны в joins методе, когда этого не должно быть. Это будет работать: Project.joins(project_stages: :stage).where(stages: {name: 'completed'})

5. Прибил его! Работает безупречно. У вас случайно нет ресурса по этому вопросу, который вы могли бы порекомендовать?

Ответ №1:

Я думаю scopes , они хорошо подходят для этого:

 scope :search_by_stages, ->(param){
    joins(:stages).where(Stage.arel_table[:name].lower.eq(param.downcase))
  }
 

Вы можете добавить scope указанное выше в свою Project модель, где param указано имя (этот поиск не чувствителен к регистру, вы можете удалить lower и downcase , если хотите, чтобы он учитывал регистр).

Вы можете использовать его следующим образом (на случай, если вы не знакомы с областями): Project.search_by_stages('name')

Надеюсь, что вышесказанное поможет! 👍