Помощь в сложном запросе ActiveRecord, который имеет слишком много объединений - PullRequest
0 голосов
/ 27 мая 2011

У меня есть следующие модели

class User < ActiveRecord::Base
  has_many :occupations,     :dependent => :destroy
  has_many :submitted_jobs,  :class_name => 'Job', :foreign_key => 'customer_id'
  has_many :assigned_jobs,   :class_name => 'Job', :foreign_key => 'employee_id'
end

class Job < ActiveRecord::Base
  belongs_to :customer, :class_name => 'User', :foreign_key => 'customer_id'
  belongs_to :employee, :class_name => 'User', :foreign_key => 'employee_id'
  belongs_to :field
end

class Occupation < ActiveRecord::Base
  belongs_to :user
  belongs_to :field
  belongs_to :expertise
end

вместе с Field (только имя и идентификатор) и Expertise (имя и целое число).

Мне нужно создать фильтр, который работает как следующий псевдокод

select * from jobs where employee_id == current_user_id
or employee_id == 0
  and current_user has occupation where occupation.field == job.field
  and if job.customer has occupation where occupation.field == job.field
    current_user.occupations must include an occupation where field == job.field
      and expertise.rank > job.customer.occupation.expertise.rank

Вы можете видеть, как я быстро исчерпал свои знания SQL с помощью запроса такого комплекса.

Как бы вы это сделали? Хороший SQL был бы хорош, но если человек из Rails может указать мне правильный путь сделать это с помощью методов ActiveRecord, это тоже замечательно. Или, может быть, я не очень хорошо структурирую свои модели; Я открыт для всевозможных предложений.

Спасибо!

1 Ответ

2 голосов
/ 28 мая 2011

Возможно, я что-то пропустил и не изучал рефакторинг моделей, но вот кое-что, что могло бы помочь вам получить полное решение или как переформулировать ваш запрос

Код не проверен и не проверен синтаксис

@jobs = Job.
    joins(:employee,:occupation).
    includes(:customer => {:occupations => :expertise}).
    where(:employee_id => current_user.id).
    where("occupations.field_id = jobs.field_id").all

user_occupations = current_user.occupations.include(:expertise)

user_occupations_by_field_id = user_occupations.inject({}) do |hash,oc|
    hash[oc.field_id] = oc
    hash
end

@jobs.reject! do |j|
  common_occupations = j.customer.occupations.select do |oc|
    if c = user_occupations_by_field_id[oc.field_id]
        !user_occupations.select do |eoc|
            c.field_id == eoc.field_id && c.expertise.rank > oc.expertise.rank
        end.empty?
    else
        true
    end
  end

end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...