【问题标题】:Relationships in Ruby on Rails across 4 modelsRuby on Rails 中跨 4 个模型的关系
【发布时间】:2013-02-23 21:16:14
【问题描述】:

我正在尝试在我的 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 %>

这显示了用户 ID、用户名、项目 ID 和项目名称。我现在想添加一行,显示用户为该项目“注册”了多少任务。我试过了

        <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

有没有人知道如何让这些关系有效运作?

【问题讨论】:

    标签: mysql ruby-on-rails ruby-on-rails-3 foreign-keys active-relation


    【解决方案1】:

    我的建议是这样的:

    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(您使用的是单数项目)

    【讨论】:

      【解决方案2】:

      你们没有关系

      class AdminUsersProject < ActiveRecord::Base
        has_many :tasks
      

      除非任务表有一个名为 admin_users_project_id 的外键。

      我怀疑您对于 AdminUsersProjects 链接记录没有太多任务。

      相反,我认为您需要管理员用户的任务或项目的任务。

      在您明确自己想要什么之前,没有人可以帮助您。一旦明确了自己想要什么,或许就能自己找出答案。

      【讨论】:

      • 项目有任务,用户有项目,用户有任务。我正在尝试创建这些之间的关系,以传达用户项目及其对这些项目的任务。
      • 是的,但是当您要求 admin-user-projects 的任务时,您要求哪些任务?澄清这将有助于您编写查询。
      • 换句话说,对于项目的任务,获取项目对象,它们将是project.tasks。对于用户,获取用户对象,他们的任务将是 user.tasks。很简单,除非那不是你真正想要的,在这种情况下你需要重新定义你想要的。
      • 是的,这是有道理的。但这不仅仅是我想要的 user.tasks。它是当前选定项目视图的 user.tasks 或其他。
      • 项目有没有用户的任务?用户是否有没有项目的任务?如果不是,那么您希望任务的唯一位置是属于 ProjectUsers。如果任务可以只针对用户,或者可以只针对项目,或者可以针对组合,那么您需要多态性。如果您评论您想要的任务,我会写另一个答案并全力以赴。
      猜你喜欢
      • 1970-01-01
      • 2018-04-05
      • 2011-10-05
      • 2015-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多