Отношение HABTM находит все записи, за исключением некоторых, основанных на ассоциации

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

У меня есть связь между проектами и пользователями. Я пытаюсь найти все проекты, к которым не принадлежит конкретный пользователь, но я не знаю, как это сделать.

Я пробовал такие вещи:

Project.where('project_id != ?', user.id)

Но это тоже явно неправильно.

Я использую рельсы 3.2.x

Во многих ответах, касающихся этого, упоминаются области действия, но я не сталкивался с ними раньше (я все еще очень новичок в Rails).

Я только что нашел этот пост с одним ответом предлагаю: Project.where('id not in (?)', user.projects)

который, кажется, работает, за исключением случаев, когда user.projects пуст. Я пытаюсь Project.where('id not in (?)', (d.projects.empty? ? '', d.projects)) , как это предлагается в ветке комментариев ответа Джозефа Кастро, но это дает мне синтаксическую ошибку во втором d.projects.

Изменить

Фрагмент модели проекта, относящийся к пользователям

class Project < ActiveRecord::Base
  attr_accessible ...
  has_and_belongs_to_many :users, :before_add => :validates_unique

а потом

class User < ActiveRecord::Base
  attr_accessible ...
  has_and_belongs_to_many :projects

person Mike T    schedule 10.08.2013    source источник
comment
Помогает ли вообще использование <>(SQL) вместо !=(Ruby)?   -  person Michael Durrant    schedule 10.08.2013


Ответы (2)


Вы можете разместить область в своей модели Project следующим образом:

scope :not_belonging_to, lambda {|user| joins(:projects_users).where('projects_users.user_id <> ?', user.id) }}

Это предполагает, что имя вашей таблицы соединений соответствует соглашению rails для HABTM ассоциаций.

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

@user = User.find(params[:id]) # example
@unowned_projects = Project.not_belonging_to(@user)

Если подумать, эта область не будет работать, так как она найдет проекты, у которых есть более одного разработчика, если один из них — ваш парень.

Вместо этого используйте следующее:

scope :not_belonging_to, lambda {|user| where('id NOT IN (?)', user.projects.empty? ? '' : user.projects) }
person Matt    schedule 10.08.2013
comment
Как мне тогда его использовать? Я не знаком с областями :\ - person Mike T; 10.08.2013
comment
Сейчас я получаю SQLite3::SQLException: no such table: projects: SELECT "projects".* FROM "projects" projects_users WHERE (projects_users.user_id <> 1). Однако таблица соединений определенно существует. Я чувствую, что сейчас все движется в правильном направлении. - person Mike T; 10.08.2013
comment
Этот SQL не включает объединение, попробуйте изменить имя таблицы на символ в части соединений (и подтвердите правильность имени таблицы). - person Matt; 10.08.2013
comment
Ассоциация с именем «projects_users» не найдена. Не возражаете, если мы возьмем это, чтобы поболтать несколько минут? - person Mike T; 10.08.2013
comment
В качестве альтернативы попробуйте присоединиться непосредственно к таблице пользователей, но не меняйте синтаксис where: scope :not_belonging_to, lambda {|user| joins(:users).where('projects_users.user_id <> ?', user.id) }} Rails должен заполнять соединения с таблицей Projects_users. И, конечно же, болтать! - person Matt; 10.08.2013
comment
давайте продолжим это обсуждение в чате - person Mike T; 10.08.2013
comment
Действительно, самый полезный человек, который помог мне с SO. - person Mike T; 10.08.2013
comment
Мне пришлось сделать user.projects.map(&:id), чтобы обновленный ответ заработал. - person Snowman; 25.06.2016

Из ответа Мэтта выше, который был чрезвычайно полезен.

У меня были проблемы с этим некоторое время. Я попытался использовать следующее:

scope :not_belonging_to, lambda {|developer| where('id NOT IN (?)', developer.projects.empty? ? '' : developer.projects) }

Но я получил следующую ошибку:

SQLite3::SQLException: разрешен только один результат для SELECT, являющегося частью выражения:

Я обнаружил, что мне нужно обновить область действия, добавив .ids в конце. Увидеть ниже:

scope :not_belonging_to, lambda {|developer| where('id NOT IN (?)', developer.projects.empty? ? '' : developer.projects.ids) }
person saundersj    schedule 29.04.2014