2017-02-08 2 views
0

У меня есть работа, принадлежащая клиенту. Работы обновляются ежегодно (но иногда не принимаются). Мне нужно областей на работу, чтобы определить следующее:Rails: Области для поиска записей, где существуют предыдущие годы с теми же записями клиентов

class Customer < ApplicationRecord 
    has_many :jobs 
end 

class Job < ApplicationRecord 
    belongs_to :customer 

    self.new_job # => Customer has no jobs from previous years 
    where(customer.jobs.count == 1) # => Best guess/pseudocode 
    end 

    self.current # => Customer has a job from the previous year 
    where(
     customer.jobs.where("year >= ? and year <= ?", 1.year.ago, 2.years.ago).exists? 
    ) # => Best guess/pseudocode 
    end 

    self.lapsed # => Customer has jobs from previous years, but not last year 
    where(
     customer.jobs.not(:current).where(year >= 2.years.ago).exists? 
    ) # => Best guess/pseudocode 
    end 
end 

Пытаюсь/в надежде, что эти примеры, приведенные выше объяснения, что я ищу, чтобы достигнуть.

Я искал и думал об этом некоторое время, но я все еще не могу собрать, как бы я это сделал. В основном области, которые позволят мне запрашивать задания на основе, если у них есть задания предыдущего года от того же самого клиента, которые существуют или нет.

Должен ли я добавить/мне нужно отношение has_many/belongs_to для предыдущих лет/будущих лет в модели заданий? Я продолжаю думать, что нет необходимости добавлять другой столбец базы данных, так как я могу просто запросить вместо него задания клиента?

Тогда я мог бы сделать что-то вроде этого, чтобы выполнить существует (?):

includes(:previous_jobs).where(# more constraints).where.not(previous_jobs): { id: nil }) 

Могу ли я сделать предыдущие задания belongs_to/HAS_MANY (самоссылающиеся?) Основаны от идентификатора клиента, или будет Мне нужно добавить внешний ключ и написать сценарий для назначения предыдущего/следующего идентификатора задания существующим записям?

+1

Перезапись метода '.new' с такой областью, что это действительно плохая идея. '.new' в Ruby всегда должен быть фабричным методом, который возвращает новый экземпляр. Все остальное - действительно плохое нарушение принципа наименьшего удивления. – max

+0

Oooh! Хорошая точка @max – gregblass

ответ

1

К сожалению, ваш подход не соответствует действительности - обзор Customer не должен быть в классе Job.

Что вы можете сделать вместо этого создать контекстные ассоциации:

class Customer 
    has_many :jobs 
    has_many :current_jobs, class_name: 'Job', 
    -> { where(created_at: 1.year.ago..Time.now) } 
    has_many :lapsed_jobs, class_name: 'Job', 
    -> { where('created_at >= ?', 1.year.ago) } 
end 

class Job 
    belongs_to :customer 
end 

Все они ссылаются на тот же jobs.customer_id столбца, так что никаких изменений в схему не нужны.

С помощью LEFT INNER JOIN вы можете ограничить Customer найденных записей без учета, так как только строки, которые имеют по крайней мере один матч в присоединяемой таблицы возвращаются:

Customer.joins(:jobs) # only customers with jobs 
Customer.joins(:current_jobs) # has a job which is not older than a year 
Customer.joins(:lapsed_jobs) # has a job older than one year 

Чтобы получить работу, где клиент не создал работа в прошлом году вы бы сделали это с помощью подзапроса:

Job.where.not(customer: Customer.joins(:current_jobs)) 
+0

Я думал об этом, но прецедент: «Дайте мне все задания, у которых нет рабочих мест у одного и того же клиента в предыдущем году» – gregblass

+0

Этот пример использования даже не имеет смысла с вашей моделью - работа не имеет работы - клиенты делают. – max

+0

Точно. Это мой вопрос. Как я могу настроить самореляционную ассоциацию, где у задания есть другие задания, основанные на том же клиенте. – gregblass

Смежные вопросы