Отношения в Ruby on Rails между 4 моделями

Я пытаюсь установить некоторые продвинутые отношения в своих моделях RoR.

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

Теперь я хочу, чтобы пользователь, который «зарегистрировался» в проекте, теперь мог «зарегистрироваться» для задач в этом проекте.

Кратко о моих текущих занятиях:

class AdminUser < ActiveRecord::Base
 has_and_belongs_to_many :projects
 has_and_belongs_to_many  :tasks
 has_many :admin_users_projects

[...]


class AdminUsersProject < ActiveRecord::Base

  belongs_to :admin_user
  has_and_belongs_to_many :project
  has_many :tasks

[...]

class Project < ActiveRecord::Base

  has_many :tasks
  has_and_belongs_to_many :admin_users
  has_and_belongs_to_many :admin_users_projects

[...]

class Task < ActiveRecord::Base

  belongs_to :project
  has_and_belongs_to_many :admin_users
  belongs_to :admin_users_project

[...]

Схема выглядит так:

 create_table "admin_users", :force => true do |t|
    t.string   "first_name",      :limit => 25
    t.string   "last_name",       :limit => 50
    t.string   "email",           :limit => 100, :default => "", :null => false
    t.string   "hashed_password", :limit => 40
    t.datetime "created_at",                                     :null => false
    t.datetime "updated_at",                                     :null => false
    t.string   "username",        :limit => 25
    t.string   "salt",            :limit => 40
  end

  add_index "admin_users", ["username"], :name => "index_admin_users_on_username"

  create_table "admin_users_projects", :force => true do |t|
    t.integer "admin_user_id"
    t.integer "project_id"
  end

  add_index "admin_users_projects", ["admin_user_id", "project_id"], :name =>     "index_admin_users_projects_on_admin_user_id_and_project_id"

  create_table "projects", :force => true do |t|
    t.string   "name"
    t.integer  "position"
    t.boolean  "visible",    :default => false
    t.datetime "created_at",                    :null => false
    t.datetime "updated_at",                    :null => false
  end

  create_table "tasks", :force => true do |t|
    t.integer  "project_id"
    t.string   "permalink"
    t.integer  "position"
    t.boolean  "visible"
    t.datetime "created_at",    :null => false
    t.datetime "updated_at",    :null => false
    t.string   "name"
    t.integer  "admin_user_id"
    t.integer  "progress"
  end

  add_index "tasks", ["permalink"], :name => "index_tasks_on_permalink"
  add_index "tasks", ["project_id"], :name => "index_tasks_on_project_id"

end

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

Моя точка зрения на «admin_user_projects» вкратце такова:

    <% @admin_users_projects.each do |admin_users_projects| %>
    <tr>
        <td><%= admin_users_projects.admin_user_id %></td>
        <td><%= admin_users_projects.admin_user.username  %></td>
        <td><%= admin_users_projects.project_id %></td>
        <td><%= admin_users_projects.project.name  %></td>
    </tr>
    <% end %>

Это показывает идентификатор пользователя, имя пользователя, идентификатор проекта и имя проекта. Теперь я хочу добавить строку, показывающую, на сколько задач пользователь «зарегистрирован» для этого проекта. я пытался

        <td><%= admin_users_projects.tasks.size  %></td>

Но получите следующее:

Mysql2::Error: Unknown column 'tasks.admin_users_project_id' in 'where clause': SELECT COUNT(*) FROM `tasks`  WHERE `tasks`.`admin_users_project_id` = 1

У кого-нибудь есть идеи, как заставить эти отношения работать эффективно?


person user1900791    schedule 23.02.2013    source источник


Ответы (2)


Мое предложение таково:

class AdminUser < ActiveRecord::Base
  has_and_belongs_to_many :projects
  has_many :assigned_tasks
  has_many :tasks, through: :assigned_tasks
end

class AssignedTask < ActiveRecord::Base
  belongs_to :user
  belongs_to :task

  validate :user_assigned_to_project

  private

  def user_assigned_to_project
    unless user.projects.include? task.project
      errors.add(:project, "is not valid")
    end
  end
end

class Project < ActiveRecord::Base
  has_and_belongs_to_many :admin_users
  has_many :tasks
end

class Task < ActiveRecord::Base
  has_many :assigned_tasks
  has_many :users, through: :assigned_tasks
  belongs_to :project
end


class GiantMigration < ActiveRecord::Migration
  create_table :admin_users do |t|
    # whatever
  end
  create_table :projects do |t|
    # whatever
  end
  create_table :assigned_tasks do |t|
    t.integer :admin_user_id, null: false
    t.integer :task_id, null: false
  end
  create_table :tasks do |t|
    # whatever
    t.integer :project_id
  end
  create_table :admin_users_projects, id: false do |t|
    t.integer :admin_user_id, null: false
    t.integer :project_id, null: false
  end
end

Некоторые общие замечания:

  • Вам нужно выбрать, собираетесь ли вы использовать чистую таблицу соединений (HABTM) или модель соединения (has_many :through). Прямо сейчас вы смешиваете два.
  • Не используйте force: true в своих миграциях по умолчанию.
  • Придерживайтесь соглашений Rails: has_and_belongs_to_many :projects (вы использовали проект в единственном числе)
person Jesper    schedule 23.02.2013

У тебя нет отношений

class AdminUsersProject < ActiveRecord::Base
  has_many :tasks

если в таблице задач нет внешнего ключа с именем admin_users_project_id.

Я подозреваю, что у вас не так много задач для связывающей записи AdminUsersProjects.

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

Пока вы не уточните, чего хотите, никто не сможет вам помочь. Как только вы поймете, чего хотите, вы сможете найти ответ самостоятельно.

person Marlin Pierce    schedule 23.02.2013
comment
У проектов есть задачи, у пользователей есть проекты, а у пользователей есть задачи. Я пытаюсь создать отношения между ними, чтобы передать проекты пользователей и их задачи для этих проектов. - person user1900791; 24.02.2013
comment
Да, но когда вы запрашиваете задачи админ-пользователей-проектов, какие задачи вы запрашиваете? Уточнение этого поможет вам написать запрос. - person Marlin Pierce; 24.02.2013
comment
Иными словами, для задач проектов получите объект проекта, и они будут project.tasks. Для пользователей получите пользовательский объект, и их задачи будут user.tasks. Достаточно просто, если это не совсем то, что вы хотите, и в этом случае вам нужно переопределить то, что вы хотите. - person Marlin Pierce; 24.02.2013
comment
Да, это имеет смысл. Но мне нужны не только user.tasks. Это user.tasks для текущего выбранного представления проекта или чего-то еще. - person user1900791; 24.02.2013
comment
Бывают ли проекты без пользователей? Бывают ли у пользователей задачи без проектов? Если нет, то единственное место, где вы хотите, чтобы задачи принадлежали ProjectUsers. Если задачи могут быть только для пользователей, или могут быть только для проектов, или могут быть для комбинации, тогда вам нужен полиморфизм. Если вы прокомментируете, как вы хотите выполнять задачи, я напишу еще один ответ и все решу. - person Marlin Pierce; 24.02.2013
comment
Спасибо за помощь, Марлин. В проектах есть задачи без пользователей, затем пользователи могут зарегистрироваться в этом проекте, а затем выполнить задачи для этого проекта. - person user1900791; 24.02.2013