【问题标题】:In RoR, how do I create TWO one to one relationship between two tables?在 RoR 中,如何在两个表之间创建两个一对一的关系?
【发布时间】:2023-03-25 03:31:01
【问题描述】:

在 RoR3 中,

我有用户和技能,每个技能都是由用户创建的。我想记录下来,所以我创建了一对多的关系。

class User < ActiveRecord::Base
  has_many :skills
end

class Skill < ActiveRecord::Base
  belongs_to :user
end

然而,每个用户也有很多技能,用户“Bob”创造了技能“Kung Fu”,用户“Charlie”创造了技能“Karate”,用户“Bob”都创造了并且能够做到这两点”功夫”和“空手道”

我应该如何用 ActiveRecord 来表示它?我应该只创建一个新表“user_skills”,其中有_many:skills?和belong_to :user?

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    这里有两种不同的关联。第一个是一对多关联。用户可以是任意数量技能的创造者。第二种是多对多关联,一个用户可以有很多技能,一个技能可以有很多用户。

    第一个是简单的belongs_to &lt;-&gt; has_many 声明。对于第二个,您要么在两个模型中都需要一个 has_and_belongs_to_many 声明和一个相关的连接表,要么需要一个专用连接模型和一个 has_many :through 声明。让我们尝试第一个:

    方法一:HABTM

    class User < ActiveRecord::Base
      has_many :created_skills, :class_name => 'Skill', :inverse_of => :creator
      has_and_belongs_to_many :skills
    end
    
    class Skill < ActiveRecord::Base
      belongs_to :creator, :class_name => 'User', :inverse_of => :created_skills
      has_and_belongs_to_many :users
    end
    

    这需要一个名为“skills_users”的连接表,其中包含名为user_idskill_id 的列

    方法2:多通(Join模型)

    第二个类似,但增加了一个模型作为中间人。这有一个额外的好处,您可以在连接模型中包含其他列,例如技能级别。

    class User < ActiveRecord::Base
      has_many :created_skills, :class_name => 'Skill', :inverse_of => :creator
      has_many :user_skills
      has_many :skills, :through => :user_skills
    end
    
    class Skill < ActiveRecord::Base
      belongs_to :creator, :class_name => 'User', :inverse_of => :created_skills
      has_many :user_skills
      has_many :users, :through => :user_skills
    end
    
    class UserSkill < ActiveRecord::Base
      belongs_to :user
      belongs_to :skill
    end
    

    【讨论】:

      【解决方案2】:

      拥有这两个模型

      class User < ActiveRecord::Base 
         has_and_belongs_to_many :skills
       end
      
       class Skill < ActiveRecord::Base  
         has_and_belongs_to_many :users
       end
      

      您必须创建一个额外的迁移(没有模型)

       rails generate migration CreateSkillsUsersJoin 
      

      这会给你

           class CreateSkillsUsersJoin < ActiveRecord::Migration
               def self.up
                  create_table :skills_users, id => false do |t|
                      t.references "user"
                      t.references "skill"
                   end
                   add_index :skills_users,["user_id","skill_id"]
               end
               def self.down
                  drop_table :skills_users
               end
            end
      

      self.up 和 self.down 方法,你可以添加它们

      【讨论】:

        【解决方案3】:

        使用像 acts_as_taggable_on 这样的 gem 会很好地为您服务,您可以简单地设置并在您的用户模型中使用它,例如:

        acts_as_taggable_on :skills

        老实说,他们已经弄清楚了所有这些东西,因为它不像你想要做的那样简单,或者我应该改写一下,你想要做的是公开的“复杂”,而这颗宝石允许您继续,在设置后继续。

        阅读自述文件。

        【讨论】:

        • 看起来不错!我可能有一些后来的要求,这让我很警惕。如果我想将标签名称从“karate”更改为“Japanese Karate”怎么办?我必须编写一个方法来重命名所有标签,是吗?另外,如果我想有“空手道”是“武术”的分层标签怎么办?
        猜你喜欢
        • 2018-03-06
        • 1970-01-01
        • 1970-01-01
        • 2017-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多