模型设计:用户拥有用户

时间:2015-12-10 17:39:40

标签: ruby-on-rails data-modeling

我希望在追求这种关联之前确保我的方法是正确的。实施听起来太复杂了,所以我认为我的计划肯定有问题。我正在使用结构化(SQL)数据存储,符合rails存储约定。我所拥有的是用户模型,它在模式中有一个电子邮件地址password_digest和名称。

class User < ActiveRecord::Base
  has_many :posts
end

我想与朋友集合实现has_many关联,以便用户可以belong_to用户(作为朋友)。我希望能够在正确构建和填充后User.last.friends.last返回User对象。

我相信我可以为这种协会创建一个模型,如:

Class Friend < ActiveRecord::Base
  belongs_to :user
  belongs_to :friendlies, class: 'User'
end
Class User < ActiveRecord::Base
  has_many :posts
  has_many :friends
  has_many :friendly, class: 'Friend'
end

但我认为这需要我使用User.last.friends.last.user添加关于模型和查询的内容所以我在想的是这是一个has_and_belongs_to_many关系。我可以逃避以下(或类似的事情):

class User < ActiveRecord::Base
  has_and_belongs_to_many :friends, class: 'User'
end

我找到this

class User < ActiveRecord::Base
  has_many :user_friendships
  has_many :friends, through: :user_friendships


class UserFriendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, class_name: 'User', foreign_key: 'friend_id'

this(自称'标准'):

has_many :friendships, :dependent => :destroy
has_many :friends, :through => :friendships, :dependent => :destroy
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id", :dependent => :destroy
has_many :inverse_friends, :through => :inverse_friendships, :source => :user, :dependent => :destroy

我假设需要Friendship模型。我觉得我不需要友谊模特。我认为class UserFriendship方法看起来正确,但它需要一个额外的模型。现在回答问题:

  1. 我可以与将用户与用户朋友关联的表格建立has_and_belongs_to_many关系,而不会产生额外的模型吗?

  2. 谨慎使用额外的模型“以防万一”以后会出现额外的要求吗?

3 个答案:

答案 0 :(得分:7)

您正在寻找的是self referential join,这意味着您可以使用不同的关联引用相同的model

#app/models/user.rb
class User < ActiveRecord::Base
   has_and_belongs_to_many :friendships,
      class_name: "User", 
      join_table:  :friendships, 
      foreign_key: :user_id, 
      association_foreign_key: :friend_user_id
end

您必须创建一个habtm联接表以获得参考:

$ rails g migration CreateFriendshipsTable

#db/migrate/create_friendships_table____.rb
class CreateFriendShipsTable < ActiveRecord::Migration
   def change
      create_table :friendships, id: false do |t|
        t.integer :user_id
        t.integer :friend_user_id
      end

      add_index(:friendships, [:user_id, :friend_user_id], :unique => true)
      add_index(:friendships, [:friend_user_id, :user_id], :unique => true)
   end
end

$ rake db:migrate

这里有一个很好的参考:Rails: self join scheme with has_and_belongs_to_many?

  

是否谨慎使用其他型号以防“以后会出现其他要求?”

只有当你知道时才会有额外的属性。如果没有,您可以根据需要随时使用habtm

答案 1 :(得分:5)

你可以试试这个

- friendship.rb

class Friendship < ApplicationRecord
  belongs_to :user
  belongs_to :friend, :class_name => 'User'
end

- user.rb

class User < ApplicationRecord
  has_many :friendships
  has_many :friends, through: :friendships
end

- db migrate xxxx_create_friendship.rb

class CreateFriendships < ActiveRecord::Migration[5.0]
  def change
    create_table :friendships do |t|
      t.belongs_to :user
      t.belongs_to :friend, class: 'User'
      t.timestamps
    end
  end
end

答案 2 :(得分:1)

Rich的答案是一个很好的资源。我设法通过遵循这个惯例颠覆了几个步骤:

# app/model/user.rb
has_and_belongs_to_many :friends,
  class_name: "User", 
  join_table: :friends_users, 
  foreign_key: :user_id, 
  association_foreign_key: :friend_id

此迁移已足够(不修改生成的代码):

rails g migration CreateFriendlyJoinTable users friends

使用rails generate migration -h

找到了JoinTable语法