DEV Community

sarisgar28
sarisgar28

Posted on • Edited on

HAS_MANY THROUGH

HAS_MANY THROUGH ASSOCIATIONS!

I finally got to Rails!... I personally feel has_many through associations need a deeper explanation than what you find in https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

As my project has these types of associations, I thought it would be of great value to whoever reads my blog posts.
Here is my schema:

ActiveRecord::Schema.define(version: 2020_11_23_171000) do

create_table "landmarks", force: :cascade do |t|
t.string "name"
t.string "city"
t.string "country"
t.text "description"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end

create_table "reviews", force: :cascade do |t|
t.string "review"
t.integer "landmark_id"
t.integer "user_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end

create_table "users", force: :cascade do |t|
t.string "username"
t.string "email"
t.string "password_digest"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end

end

What has_many through does is create a join table by connecting, in this case, three models which will work as many to many relations. In my join table above is “REVIEWS” containing a “landmark_id” and “user_id” as attributes which are called FOREIGN KEYS. These keys are many to many relations to my other two models “USERS” and “LANDMARKS”.

Once you have your migrations set up, you move into your models by creating the association itself.

LANDMARK CLASS:

class Landmark < ApplicationRecord
has_many :reviews, dependent: :destroy
has_many :users, through: :reviews
scope :find_name, -> (name) {find_by(name: name)}

validates :name, presence: true
validates :city, presence: true
validates :country, presence: true
validates :description, presence: true

end

REVIEW CLASS:

class Review < ApplicationRecord
belongs_to :user
belongs_to :landmark
validates :review, presence: true

end

USER CLASS:

class User < ApplicationRecord

has_secure_password

has_many :reviews
has_many :landmarks, through: :reviews

validates :username, presence: true, uniqueness: :true
validates :email, presence: true, uniqueness: :true

end

The drawing above is my migrations representation, which is what I expressed on my schema.
Active Record is pretty magical and by doing this association, when you see the model USER has_many :landmarks through reviews means that the instances of our USER now responds to a method called Landmarks. This will return a collection of LANDMARKS that share a REVIEW with the USER.

HAPPY CODING!

Top comments (0)