dsp_099 dsp_099 - 4 months ago 9
Ruby Question

How to set up this belongs_to association in Rails / ActiveRecord?

I have

User
and
Review
models. A review can have an
author
and a
subject
, both pointing to a
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


This works fine and now I can assign two separate
User
objects to the
Review
object to represent who wrote the review against whom.

The user though, doesn't "know" how many reviews he's associated with either as a subject or the author. I added
has_and_belongs_to_many :users
on reviews and vice-versa, and though doable, isn't exactly what I want.

How do I set up the associations to be able to do the following:

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


In other words, how do I see how many times a
User
has been saved as an author or subject for a model with
belongs_to
?


Answer

IF you want to use has_many association on users side, you need to define two separate has_many relations like

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

Now with this you can simply use

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 []>

Comment: subject_reviews is not a good name :), change it to your requirements.

Comments