medBouzid
medBouzid

Reputation: 8372

Self join association has_many and belongs_to (one)

I would like to make a self join association which has two relationships

has_many and belongs_to (one)

I've found 2 ways to do this but I am not sure which one is more accurate, for example in this answer has_many and belongs_to within same model there is a relation between employee and manager, manager has_many employees, and employee belongs_to manager

the solution was to add a field called manager_id, so if the user is a manager then the manager_id will be null, if an employee then manager_id will be the id of the manager.

The associations look like this :

has_many :employees, class_name: "User", foreign_key: :manager_id
belongs_to :manager, class_name: "User", foreign_key: :manager_id

The SECOND solution which I found here Rails Associations - has_many => :through - but same model has the following relation : post has_many related_posts and related_post belongs_to post

The solution here was to create two separate tables, one for posts and one for related_posts like this :

create_table "posts", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "related_posts", :force => true do |t|
    t.integer  "post_id"
    t.integer  "related_post_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

and the associations look like this :

class Post < ActiveRecord::Base
  has_many :related_posts_association, :class_name => "RelatedPost"
  has_many :related_posts, :through => :related_posts_association, :source => :related_post
  has_many :inverse_related_posts_association, :class_name => "RelatedPost", :foreign_key => "related_post_id"
  has_many :inverse_related_posts, :through => :inverse_related_posts_association, :source => :post
end

class RelatedPost < ActiveRecord::Base
  belongs_to :post
  belongs_to :related_post, :class_name => "Post"
end

Now I am not sure which way to go, the first solution looks simple and the idea was to add an additional field called manager_id (or can be post_id if we are working with posts) which will be null for all the managers people, I imagine having a lot of records with null value on that field which seems not correct...

the second solution looks good but the wrong thing I feel about it is the relation has_many :inverse_related_posts_association which seems like a related_post has also other related posts / or maybe a related_post belongs to many posts (I am not sure).

In my case I want something like post has_many related_posts and a related_post belongs_to (one) post

Upvotes: 1

Views: 816

Answers (1)

Baradzed
Baradzed

Reputation: 578

I'd go with the first option, unless you have a very compelling reason to take second approach. It is simple and obvious. And you can always refactor your code later.

There's nothing particularly bad about having nulls in a column, as long as the column is relevant for all records. In your case, NULL in manager_id would mean 'this person does not have a manager'. Is NULL value relevant here? My answer is yes.

NULL means the value is unknown or no value. Rails statement @person.manager.present? will properly return true for people who have manager defined, and false for those who don't have a manager. When looking at a database record for any particular person, NULL in the manager_id field will convey the same meaning.

Upvotes: 1

Related Questions