复杂,重命名为Has Many Through关系

时间:2014-08-13 20:48:28

标签: sql ruby-on-rails ruby-on-rails-3 activerecord ruby-on-rails-4

我正在尝试创建一个Wiki风格的应用程序。现在的基本模型是User和Wiki。她创建的用户has_many Wiki,以及用户的Wiki belongs_to。到目前为止这么容易。现在是复杂的。

我希望Wiki能够拥有无限制的合作用户。这区分了Wiki的所有者协作者,但两者都是用户。我认为这对于Has Many Through关系来说是个好例子,所以我创建了一个连接表:Collaboration。

以下是我的迁移生成器(我没有偏离)。第一个维基:

rails g model Wiki body:text title:string owner_id:integer

然后用户:

rails g model User name:string

然后协作:

rails g model Collaboration wiki_id:integer collaborator_id:integer

我的想法是,我应该可以致电wiki.ownerwiki.collaborators,以及user.owned_wikisuser.collaborated_wikis。通过硬编码我自己的方法,我已经完成了大部分工作。也就是说,这非常有效:

class User < ActiveRecord::Base
  def owned_wikis
    Wiki.where(owner_id: id)
  end

  def collaborations
    Collaboration.where(collaborator_id: id)
  end

  def collaborated_wikis
    collaborations.wikis
  end
end

class Collaboration < ActiveRecord::Base
  def self.collaborators
    User.where(id: pluck(:collaborator_id))
  end

  def self.wikis
    Wiki.where(id: pluck(:wiki_id))
  end

  def wiki
    Wiki.where(id: wiki_id)
  end

  def collaborator
    User.where(id: collaborator_id)
  end
end

class Wiki < ActiveRecord::Base
  def owner
    User.where(id: owner_id)
  end

  def collaborations
    Collaboration.where(wiki_id: id)
  end

  def collaborators
    collaborations.collaborators
  end
end

我可以把它留在那里,但这会使某些事情(比如,wiki.collaborators << User.create(name: 'Whatever')难以/不可能。我喜欢用AR关系做这一切,但我遇到了麻烦。这就是我的地方:

class User < ActiveRecord::Base
  has_many :owned_wikis, class_name: 'Wiki', foreign_key: 'owner_id'
  has_many :collaborations, foreign_key: 'collaborator_id'
  has_many :collaborated_wikis, class_name: 'Wiki', through: :collaborations
end

class Collaboration < ActiveRecord::Base
  belongs_to :wiki
  belongs_to :collaborator, class_name: 'User'

  # The issue here is that relations of Collaborations don't respond to `collaborators` or `wikis`
end

class Wiki < ActiveRecord::Base
  belongs_to :owner, class_name: 'User'
  has_many :collaborations
  has_many :collaborators, class_name: 'User', through: :collaborations
end

它正在做一些基本的事情user.owned_wikiswiki.ownerw.collaborations等,但不是 w.collaborators或{{1} }。

对于这两个人,我得到了这些错误。 u.collaborated_wikis

w.collaborators

User Load (0.9ms) SELECT "users".* FROM "users" INNER JOIN "collaborations" ON "users"."id" = "collaborations"."collaborator_id" WHERE "collaborations"."wiki_id" = $1 [["wiki_id", 1]] PG::UndefinedFunction: ERROR: operator does not exist: integer = character varying LINE 1: ...sers" INNER JOIN "collaborations" ON "users"."id" = "collabo... ^ HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. : SELECT "users".* FROM "users" INNER JOIN "collaborations" ON "users"."id" = "collaborations"."collaborator_id" WHERE "collaborations"."wiki_id" = $1

u.collaborated_wikis

任何想法如何更好地做到这一点?我希望有一个完全成熟的多任务关系,以便我可以ActiveRecord::HasManyThroughSourceAssociationNotFoundError: Could not find the source association(s) :collaborated_wiki or :collaborated_wikis in model Collaboration. Try 'has_many :collaborated_wikis, :through => :collaborations, :source => <name>'. Is it one of :wiki or :collaborator? wiki.collaborators << user。在here描述的那种,但所有这些奇怪的重命名扭结。

任何想法如何将其串起来?

已解决 - 以下答案产生的最终版本:

user.collaborated_wikis << wiki

1 个答案:

答案 0 :(得分:2)

提供:来源选项

has_many :collaborated_wikis, through: :collaborations, source: :wiki

has_many :collaborators, through: :collaborations, source: :colaborator

但是我只是将colaborator_id更改为Collaboration模型上的user_id,因为您已经有了#34; Collaborate&#34;此模型本身的命名空间,这将允许您更多地使用rails默认值。