具有多态关联的多对多并不能在两个方向上起作用

时间:2016-05-15 13:53:18

标签: ruby-on-rails polymorphism has-many-through polymorphic-associations

我正在实施一个系统,使用户能够遵循"可跟随"(在我的情况下,这些可能是一个事件,地点或其他用户)。

我的想法:

关注模型包含user_id,followable类型和followale_id(连接表)

class Follow < ActiveRecord::Base
  belongs_to :user
  belongs_to :followable, polymorphic: true
end

事件

class Event < ActiveRecord::Base    
  has_many :follows, as: :followable
  has_many :users, through: :follows
end

放置

class Place < ActiveRecord::Base
  has_many :follows, as: :followable
  has_many :users, through: :follows    
end

用户

class User < ActiveRecord::Base
  has_many :follows
  has_many :events, through: :follows, source: :followable, source_type: "Event"
  has_many :places, through: :follows, source: :followable, source_type: "Place"
  has_many :users, through: :follows, source: :followable, source_type: "User"
end

问题在于,这种情况只能在一个方向发挥作用,我能做到:

user.follows.create(followable:event1) #follow event1
user.follows.create(followable:place1) #follow place1
user.follows.create(followable:user1)  #follow user1
user.follows # displays all following relations user has established

但是,我做不到

event1.follows #return follow objects(some user - event1 pairs)
event1.users #return all of the users that follow this event
user1.users  #return all of the users that user1 follows, the most confusing part..

所有上述内容均为零。

我应该如何建立关系以使其在两个方向上发挥作用?
另外,我想听听一些关于如何改进这个想法的评论,这是我第一次玩更复杂的现实。 提前谢谢。

1 个答案:

答案 0 :(得分:1)

让我们从最熟练的用户模型开始:

class User < ActiveRecord::Base
  has_many :follows, source: :user
  has_many :follows_as_fallowable, 
                    class_name: 'Follow',
                    as: :followable

  has_many :followers, through: :follows_as_fallowable,
                       source: :user

  # other users the user is following                     
  has_many :followed_users, through: :follows,
                            source: :followable,
                            source_type: 'User'
end

请注意,我们需要与follows建立两种不同的关系,因为用户可以位于任一列中,具体取决于用户是关注者还是被关注的对象。

我们现在可以做一个简单的测试来检查关系是否设置正确:

joe = User.create(name: 'Joe')
jill = User.create(name: 'Jill')
joe.followers << jill
jill.followed_users.include?(joe) # true
joe.followers.include?(jill) # true

然后设置用户和您可以执行的可跟随模型之间的双向关系:

class Event < ActiveRecord::Base
  has_many :follows, as: :followable
  has_many :followers, through: :follows,
                       source: :user
end

class User < ActiveRecord::Base
  # ...
  has_many :followed_events, through: :follows,
                             source: :followable,
                             source_type: 'Event'
end

后续模型(事件)中的关系在每个模型中几乎相同,因此您可以轻松地将其提取到模块中以供重用:

# app/models/concerns/followable.rb
module Followable
  extend ActiveSupport::Concern

  included do
    has_many :follows, as: :followable
    has_many :followers, through: :follows,
                         source: :user
  end
end

class Event < ActiceRecord::Base
  include Followable
end

class Place < ActiceRecord::Base
  include Followable
end