在Rails中定义两个模型之间的多个(相似)关系

时间:2015-06-08 04:22:28

标签: ruby-on-rails activerecord migration associations

我一直在尝试其他(非常)类似答案的排列,但是没有得到这个点击,我觉得我很接近。

我想以两种不同的方式将用户模型与类别模型联系起来,具体取决于用户对每个类别所需的通知渠道(文本或电子邮件)。用户可以有许多类别,反之亦然。

期望的结果:

>>@user.textcategories =&gt; #<ActiveRecord::Associations::CollectionProxy []>类别。

>> @user.emailcategories =&gt; #<ActiveRecord::Associations::CollectionProxy []>类别。

>> @user.emailcategories << Category.first

>> @user.textcategories << Category.third

当前代码:

class User < ActiveRecord::Base
  has_many :emailcategories 
  has_many :categories, through: :emailcategories

  has_many :textcategories
  has_many :categories, through: :textcategories
end

class Category < ActiveRecord::Base
  has_many :emailcategories 
  has_many :users, through: :emailcategories

  has_many :textcategories 
  has_many :users, through: :textcategories
end

class Emailcategory < ActiveRecord::Base
  belongs_to :user
  belongs_to :category
end

class Textcategory < ActiveRecord::Base
  belongs_to :user
  belongs_to :category
end

迁移/架构:

create_table "emailcategories" do |t|
      t.integer :user_id
      t.integer :category_id
      t.datetime "created_at",       null: false
      t.datetime "updated_at",       null: false
    end

    create_table "textcategories" do |t|
      t.integer :user_id
      t.integer :category_id
      t.datetime "created_at",       null: false
      t.datetime "updated_at",       null: false
    end

    create_table :users do |t|
      t.string :name
    end

    create_table :categories do |t|
      t.string :name
    end

当前的错误讯息: >> @user.emailcategories << Category.first ActiveRecord :: AssociationTypeMismatch:Emailcategory(#70239513207200)预期,得到分类(#70239513077640)

Github克隆并尝试:https://github.com/Grantimus9/TestRels

谢谢!

2 个答案:

答案 0 :(得分:0)

你做错了。你应该这样做:

@user.emailcategories.create! category: Category.first
@user.textcategories.create! category: Category.third

答案 1 :(得分:0)

关于您现有的代码,上述答案是正确的。但是,如果要使用<<语法,则应在连接表上使用STI。 (我也认为这是一个更清洁的解决方案,尽管这可能是个人偏好。)

# db/schema.rb
create_table "categories", force: :cascade do |t|
  t.string   "name"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

create_table "category_users", force: :cascade do |t|
  t.integer  "category_id"
  t.integer  "user_id"
  t.string   "type"
  t.datetime "created_at",  null: false
  t.datetime "updated_at",  null: false
end

create_table "users", force: :cascade do |t|
  t.string   "name"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

# app/models/user.rb
class User < ActiveRecord::Base
  has_many :email_category_users
  has_many :email_categories, through: :email_category_users, source: :category
  has_many :text_category_users
  has_many :text_categories, through: :text_category_users, source: :category

  # If you also need to get all categories on a user
  has_many :category_users
  has_many :categories, through: :category_users
end

# app/models/category_user.rb
class CategoryUser < ActiveRecord::Base
  belongs_to :user
  belongs_to :category
end

# app/models/email_category_user.rb
class EmailCategoryUser < CategoryUser
end

# app/models/text_category_user.rb
class TextCategoryUser < CategoryUser
end

# app/models/category.rb
class Category < ActiveRecord::Base
  has_many :category_users 
  has_many :users, through: :category_users
end

此解决方案允许您使用OP中概述的所有语法来创建/访问类别(尽管它是@user.text_categories等,请注意下划线)