Rails имеет много и принадлежит одному

У меня есть модель User, которая имеет много projects, и модель Project, которая может иметь много users, но также принадлежит одному пользователю (то есть пользователю, который создал этот проект). Он должен принадлежать User. Он также позволяет связать с ним список пользователей, подумайте о совместной работе.

Имея это в виду, мои модели выглядят так:

class User < ActiveRecord::Base
  has_many :assigned_projects
  has_many :projects, :through => :assigned_projects
end

class Project < ActiveRecord::Base
  belongs_to :user
  has_many :assigned_projects
  has_many :users, :through => :assigned_projects
end

class AssignedProject < ActiveRecord::Base
  belongs_to :user
  belongs_to :project
end

Теперь, когда я хочу создать новый проект через User, я бы сделал это так:

user = User.create(:name => 'injekt')
user.projects.create(:name => 'project one')

Теперь я знаю, что projects предоставляется через модель соединения AssignedProject, поэтому project.user возвращает nil. Что я изо всех сил пытаюсь понять, так это лучший способ назначить создателя проекта (который, кстати, не обязательно должен быть user, это может быть creator или что-то еще описательное, если так как он имеет тип User).

Идея состоит в том, чтобы создать метод для возврата projects_created из User, который будет выбирать только проекты, созданные этим пользователем. Где user.projects, конечно, вернет ВСЕ проекты, с которыми связан пользователь.

Предполагая, что такие ассоциации достаточно распространены, как лучше всего добиться того, чего я хочу? Любое направление приветствуется.


person Lee Jarvis    schedule 30.06.2011    source источник


Ответы (2)


Добавьте столбец Creator_id в таблицу проектов для отношения создателя, а затем добавьте ассоциации к моделям:

class User < ActiveRecord::Base
  has_many :assigned_projects
  has_many :projects, :through => :assigned_projects

  has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end

class Project < ActiveRecord::Base
  belongs_to :user
  has_many :assigned_projects
  has_many :users, :through => :assigned_projects

  belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many

person Pavling    schedule 30.06.2011
comment
Спасибо за ваш ответ, это была не моя проблема. Это было: Что я изо всех сил пытаюсь понять, так это лучший способ назначить создателя проекта (который, кстати, не обязательно должен быть пользователем, это может быть создатель или что-то еще описательное, если он имеет тип User). - person Lee Jarvis; 30.06.2011
comment
@Nuby уверен в чем? Уверен, что я изо всех сил пытаюсь понять, как автоматически назначать пользователя/создателя проекту? да - person Lee Jarvis; 30.06.2011
comment
Если я неправильно понял ответ @Pavling (и ваш вопрос), он предлагает создать вторую связь с таблицей User, называемую «Creator». Затем вы можете вызвать Project.creator, чтобы получить связанного пользователя из ассоциации CreatedProjects. Это решит (я думаю) вашу проблему. Что касается того, как его назначить, вы можете сделать хук before_create в модели, чтобы назначить это пользователю, вошедшему в систему, или какому-либо другому пользователю (в зависимости от логики вашего проекта). - person Nuby; 30.06.2011
comment
@injekt - да, извините, этот код устанавливает отношения - то, как вы их назначаете, зависит от работы вашего кода. Лично у меня была бы строка в действии создания ProjectsController, которая устанавливает @project.creator = current_user (или любой другой вспомогательный метод, который у вас есть для получения вошедшего в систему пользователя) - person Pavling; 30.06.2011
comment
Ну, это неловко. Установка создателя — это нормально, если вы думаете, что просто делать это в действии создания моего контроллера — это нормально, я думаю, что искал ненужную магию, которую обычно предоставляет Rails. Одна вещь, которую я действительно ошибся, заключалась в том, что у меня было has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id, но в проекте у меня было belongs_to :creator, :class_name => 'User' без внешнего ключа, я думаю, я предполагал, что это сработает из ссылки :creator. Большое спасибо, ребята! - person Lee Jarvis; 30.06.2011
comment
@ Павлинг, разве belongs_to :user в Project не является избыточным после добавления belongs_to :creator, :class_name => "User", :foreign_key => :creator_id? В моем случае я думаю изменить имя столбца Project user_id на creator_id. - person BenU; 25.03.2013
comment
Вероятно/Возможно; только вы знаете, является ли это избыточным в вашем коде - и если это так, удалите его :-) Я просто добавил новые ассоциации, чтобы показать, что будет необходимо. Если какой-то старый код больше не нужен (например, отдельная ассоциация :users в Project), то нет смысла его сохранять. - person Pavling; 25.03.2013

Я хотел немного улучшить дизайн. На самом деле нам не нужна промежуточная модель, потому что она не содержит никаких дополнительных столбцов, кроме reference_ids, поэтому здесь лучше всего подходит ассоциация HABTM.

class User < ActiveRecord::Base
  has_and_belongs_to_many :projects, :join_table => :assigned_projects
  has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end

class Project < ActiveRecord::Base
  has_and_belongs_to_many :users, :join_table => :assigned_projects
  belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end
person Sandip Ransing    schedule 26.02.2012
comment
Действительно? Вам все равно, какая роль назначена пользователю в данном проекте, или какая дата его назначения, или любая другая информация, относящаяся к участию этого пользователя в этом конкретном проекте? Вы будете реорганизовывать этот HABTM в HMT до конца месяца ;-) - person Pavling; 26.02.2012
comment
@Pavling, о каком пользователе role ты говоришь? я не пойму тебя на этом. Нужна ли дата, когда задание по проекту было выполнено? Если там будут дополнительные столбцы, то has_many through может быть хорошим выбором. - person Sandip Ransing; 26.02.2012
comment
В одном проекте пользователь может взять на себя роль технического руководителя, в другом — UI-тестера. Вам может не понадобиться эта конкретная информация (или дата назначения) - это просто пример; но вам потребуется больше информации, чем просто кто участвует в проекте. Конечно, отношения типа HABTM имеют место быть, но на самом деле это будет HMT. - person Pavling; 27.02.2012