如何在Rails / ActiveRecord中设置这个belongs_to关联?

时间:2016-07-12 00:46:25

标签: ruby-on-rails ruby activerecord migration associations

我有UserReview个型号。评论可以包含authorsubject,两者都指向User

class Review < ApplicationRecord
  belongs_to :subject, class_name: 'User', optional: true
  belongs_to :author, class_name: 'User', optional: true
end   
class CreateReviews < ActiveRecord::Migration[5.0]
  def change
    create_table :reviews do |t|
      t.references :subject
      t.references :author
    end
  end
end

这很好用,现在我可以为User对象分配两个单独的Review对象,以表示谁对谁写了评论。

但是,用户并不“知道”他作为主题或作者与他有多少评论。我在评论中添加了has_and_belongs_to_many :users,反之亦然,尽管可行,但这并不是我想要的。

如何设置关联以便能够执行以下操作:

review.author = some_other_user
review.subject = user2
another_review.author = some_other_user
another_review.subject = user2

user2.a_subject_in.count
#=> 2
user2.a_subject_in
#=> [#<Review>, #<Review>]
some_other_user.an_author_in.count
#=> 2

换句话说,如何查看将User保存为belongs_to模型的作者或主题的次数?

2 个答案:

答案 0 :(得分:4)

如果您想在用户端使用has_many关联,则需要定义两个单独的has_many关系,例如

class User < ApplicationRecord
  has_many :reviews, foreign_key: :author_id
  has_many :subject_reviews, class_name: 'Review', foreign_key: :subject_id
end

现在可以使用

irb(main):033:0> s.reviews
  Review Load (0.2ms)  SELECT "reviews".* FROM "reviews" WHERE "reviews"."author_id" = ?  [["author_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Review id: 1, comment: "random", subject_id: 2, author_id: 1, created_at: "2016-07-12 01:16:23", updated_at: "2016-07-12 01:16:23">]>
irb(main):034:0> s.subject_reviews
  Review Load (0.2ms)  SELECT "reviews".* FROM "reviews" WHERE "reviews"."subject_id" = ?  [["subject_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy []>

评论: subject_reviews 不是一个好名字:),根据您的要求进行更改。

答案 1 :(得分:0)

我认为您正在寻找此查询:

class User
  def referenced_in
    # this fetches you all the reviews that a user was referenced
    Review.where("reviews.author_id = :user_id OR reviews.subject_id = :user_id", user_id: id).distinct
  end
end

User.first.referenced_in #should give you all records a user was referenced