如何在Rails中创建“双方”多对多关系?
-
20-09-2019 - |
题
假设我们有一个摄影网站。任何作者都可以订阅以接收来自任何其他作者的更新。显然,如果作者 A 订阅了作者 B,并不意味着 B 订阅了 A。所以我们建立模型
class Author < ActiveRecord::Base
has_many :subscriptions
has_many :subscribed_by_author, :through => :subscriptions, :source => :subscribed_to
end
class Subscription < ActiveRecord::Base
belongs_to :author
belongs_to :subscribed_to, :class_name => "Author", :foreign_key => "subscribed_to"
end
这样我们就可以使用
- some_author.subscribed_by_author -- some_author 订阅的作者列表。
- 对于任何订阅,我们都可以知道两端(谁订阅了谁)
但问题是如何仅使用 Rails(不使用普通 SQL)获取订阅某个作者的人员列表,即得到以下问题的答案:“谁订阅了 some_author?”
问题:Rails 是否有能力让双方的关系发挥作用,即不只是写作 some_author.subscribed_BY_author
但有 some_author_subscribed_TO_author
?如果有的话,那是什么?
附:显而易见的解决方案是
- 更改数据库设计,添加名为“direction”的列
- 每次创建订阅时创建 2 条记录
添加到作者模型
has_many :subscribed_BY_author, :through => :subscriptions, :source => :subscribed_to, :conditions => "direction = 'by'"
has_many :subscribed_TO_author, :through => :subscriptions, :source => :subscribed_to, :conditions => “方向 = 'to'”
但我想知道是否有一种不改变数据库设计的解决方案。
解决方案
# Author model
has_many :subscriptions_to, :class_name => "Subscription", :foreign_key => "subscribed_to"
has_many :subscribed_to_author, :through => :subscriptions_to, :source => :author
据我所知 - 它有效!:)
其他提示
我会使用普通的 HABTM 来做这样简单的事情,但无论如何你都需要一个连接表。
create_table :subscriptions do |t|
t.column :author_id, :integer
t.column :subscriber_id, :integer
end
将作者指向它:
class Author < ActiveRecord::Base
has_and_belongs_to_many :subscribers
:class_name => "Author",
:join_table => "subscriptions",
:association_foreign_key => "subscriber_id"
def subscriptions # "subscribers" is already included above
self.subscribers.find(:all, :subscriber_id=>author.id) # hopefully not too
end # much SQL
end
如果您确实致力于您的方法名称:
def subscribed_to_author
subscribers
end
def subscribed_by_author(author)
self.subscribers.find(:all, :subscriber_id=>author.id)
end
创建一些连接(我会让 SubscriptionsController 成为 RESTy)
SubscriptionsController < ApplicationController
def create
@author = Author.find(params[:author_id] # author to be subscribed to
@user = current_user # user clicking the "subscribe" button
@author.subscribers << @user # assuming authors should only
@author.save # be able to subscribe themselves
end
end
显示名称或其他任何内容
@author.subscribers.each do |s|
s.name
end
# ...or...and...also...
<%= render :partial => @author.subscribers -%>
<%= render :partial => @author.subscriptions -%>
不隶属于 StackOverflow