假设我们有一个摄影网站。任何作者都可以订阅以接收来自任何其他作者的更新。显然,如果作者 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

这样我们就可以使用

  1. some_author.subscribed_by_author -- some_author 订阅的作者列表。
  2. 对于任何订阅,我们都可以知道两端(谁订阅了谁)

但问题是如何仅使用 Rails(不使用普通 SQL)获取订阅某个作者的人员列表,即得到以下问题的答案:“谁订阅了 some_author?”

问题:Rails 是否有能力让双方的关系发挥作用,即不只是写作 some_author.subscribed_BY_author 但有 some_author_subscribed_TO_author?如果有的话,那是什么?

附:显而易见的解决方案是

  1. 更改数据库设计,添加名为“direction”的列
  2. 每次创建订阅时创建 2 条记录
  3. 添加到作者模型

    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 -%>
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top