多个has_many通过关系

时间:2012-09-26 18:55:27

标签: ruby-on-rails ruby has-many-through named-scope nested-includes

我正在建立一个协作式写作平台。用户可以具有项目集,其中任何项目可以在任何集合中并且属于任何用户。这导致了一些问题。

这些是我的模特关系:

class Association < ActiveRecord::Base
  belongs_to :user
  belongs_to :set
  belongs_to :item
end  

class Set < ActiveRecord::Base
  has_many :associations
  has_many :users, through: :associations
  has_many :items, through: :associations 
end

class Item < ActiveRecord::Base
  has_many :associations
  has_many :users, through: :associations
  has_many :sets, through: :associations 
end

我无法弄清楚正确处理此问题的“轨道方式”。

问题1:

创建新项目时,仅存储集合/项目关联,而不是用户:

class ItemsController < ApplicationController
  def create
    @set = current_user.sets.find(params[:set_id])
    @set.where(title: params[:item][:title]).first_or_create!
  end
end   

* 更新 *

要解决问题1,我能想到的最好的方法是执行以下操作:

@set  = current_user.sets.find(params[:set_id])
@item = Item.where(name: params[:item][:title]).first_or_create!
Association.where(item_id: @item.id, set_id: @set.id, user_id: current_user.id).first_or_create!

虽然感觉非常错误!

问题2:

假设从问题1正确填充了关联表,以下控制器将返回该集拥有的所有项目,但忽略用户所有权:

class SetsController < ApplicationController
  def index
    @sets = current_user.sets.includes(:items)
  end
end 

*的 更新 *

仍然没有运气找到答案。 为了更好地解释这个问题:

以下内容仅返回属于当前用户的集合

@sets = current_user.sets.all

但是,以下内容仅返回用户的集合,但即使它们不属于当前用户,也会包含集合的所有项目。换句话说,用户范围被删除。

@sets = current_user.sets.includes(:items)

我一直在努力解决这个问题,似乎无法找到领导

2 个答案:

答案 0 :(得分:2)

您的第一个问题是确保您的实例变量是相同的。一个是资本化的。应该是这样的:

class ItemsController < ApplicationController
  def create
    @set = current_user.sets.find(params[:set_id])
    @set.where(title: params[:item][:title]).first_or_create!
  end
end    

答案 1 :(得分:2)

这是什么意思? 用户可以拥有许多项目。 用户可以拥有多套。

项目可以属于多个用户。 一个项目可以属于多个集合。

如果是这种情况,则需要多个连接模型。

Class UserItemAssociation < ActiveRecord::Base
  belongs_to :user
  belongs_to :item
end

Class SetItemAssociation < ActiveRecord::Base
  belongs_to :set
  belongs_to :item
end

Class Item < ActiveRecord::Base
  has_many :user_item_associations
  has_many :users, through: :user_item_associations

  has_many :set_item_associations
  has_many :sets, through :set_item_associations
end

Class Set < ActiveRecord::Base
  belongs_to :user
end

在控制器中:

@set = current_user.sets.find_or_create_by(params[:set_id])
@item = @set.items.where(title: params[:item][:title]).first_or_create!
current_user.items << @item

然而,这是另一种看待它的方式。

在用户模型中,添加此方法。

  def items
    self.sets.collect{|set| set.items}.flatten
  end

这样,您只需要Association模型即可将用户加入集合,但您现在仍然可以访问user.items。