N7. N:N관계

2020. 7. 5. 16:46Rails 5 on aws c9

1:N 이 가장 많이 쓰이는 관계이다

N:N관계도 있다. 이는 게시물과 #해시태그의 관계가 있을 수 있다

하나의 게시물은 여러개의 해시태그를 가질 수 있고

해시태그는 여러 게시물을 가질 수 있다.

게시물의 좋아요도 그렇게 구현할 수 있다.

User ← 1:N → Like ← N:1 → Post

두개의 태이블을 Join하면 N:N을 얻을 수 있다. (join table)

하나의 유저가 여러개의 포스트를 좋아요 할 수 있고

하나의 포스트가 여러개의 좋아요를 받을 수 있다.

이럴 경우

User has many liked_posts through likes

Post has many liked_users through likes

ubuntu:~/environment/noar (master) $ rails g model Like

Running via Spring preloader in process 1583
      invoke  active_record
      create    db/migrate/20200621131036_create_likes.rb
      create    app/models/like.rb
      invoke    test_unit
      create      test/models/like_test.rb
      create      test/fixtures/likes.yml
class CreateLikes < ActiveRecord::Migration[5.0]
  def change
    create_table :likes do |t|
      #like모델은 유저와 포스트 둘다 부모로 가진다.
      t.belongs_to :user
      t.belongs_to :post

      t.timestamps
    end
  end
end
ubuntu:~/environment/noar (master) $ rake db:migrate
== 20200621131036 CreateLikes: migrating ======================================
-- create_table(:likes)
   -> 0.0062s
== 20200621131036 CreateLikes: migrated (0.0073s) =============================

이제 모델의 관계설정을 해줘야한다.

User ← 1:N → Like ← N:1 → Post

에서

User ← 1:N → Like

라이크와 유저사이의 관계를 설정해주고

Like ← N:1 → Post

라이크와 포스트 간의 관계설정을 해 준 이후

유저입장에서 좋아하는 포스트의 리스트를 가져올 수 있는 관계설정을 할 것이다.

라이크모델부터 살펴보자

class Like < ApplicationRecord
    #어떤 하나의 Like를 찾아오면
    #어떤 사용자가 어떤 글을 좋아했는지 알 수 있다.
    belongs_to :user
    belongs_to :post
end
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :posts
  has_many :liked

  # 1:N 관계인 likes를 이용해서 Post와 N:N 관계를 구현 
  # 특정 유저가 좋아요를 누른 posts를 얻을 수 있음. 
  # ex) user.likes_posts

  #유저입장에서 좋아하는 글을 가져오는데,
  #가져올 때 Likes를 토대로 찾게되고,
  #그 속에서 post만 묶어서 보여준다.(그 출처는 post다)
  has_many :liked_posts, through: :likes, source: :post

end
class Post < ApplicationRecord
    belongs_to :user
    has_many :likes

    # 1:N 관계인 likes를 이용해서 User와 N:N 관계를 구현 
    # 특정 글에 좋아요를 누른 users를 얻을 수 있음. 
    # ex) post.liked_users
    has_many :liked_users, through: :likes, source: :user
end

콘솔에서 확인해보자.

**ubuntu:~/environment/noar (master) $ rails c**

Running via Spring preloader in process 2533
Loading development environment (Rails 5.0.7.2)

**2.6.3 :001 > User.all**
  User Load (1.2ms)  SELECT "users".* FROM "users"
 => #<ActiveRecord::Relation [#<User id: 1, email: "comp-er@daum.net", name: "정형찬", created_at: "2020-06-16 07:21:14", updated_at: "2020-06-16 07:55:00">, #<User id: 2, email: "asd@asd.com", name: "asd", created_at: "2020-06-21 13:30:36", updated_at: "2020-06-21 13:30:36">]> 

**2.6.3 :002 > Post.all**
  Post Load (0.2ms)  SELECT "posts".* FROM "posts"
 => #<ActiveRecord::Relation [#<Post id: 1, content: "첫번째 글 입니다", user_id: 1, created_at: "2020-06-17 01:27:51", updated_at: "2020-06-17 01:27:51">, #<Post id: 2, content: "수정을 해봅시다.\r\n엔터가 적용되나 봅시다.\r\n 잘 수정됩니다.", user_id: 1, created_at: "2020-06-17 01:44:39", updated_at: "2020-06-17 04:59:36">, #<Post id: 4, content: "asd입니다", user_id: 2, created_at: "2020-06-21 13:30:44", updated_at: "2020-06-21 13:30:44">]>

이제 좋아요를 해보자.

**** 유저 아이디가 1번인 유저가 4번 글을 좋아함 ****
**2.6.3 :004 > Like.create(user_id: 1, post_id: 4)**

   (0.1ms)  begin transaction
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Post Load (0.1ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ?  [["id", 4], ["LIMIT", 1]]
  SQL (1.7ms)  INSERT INTO "likes" ("user_id", "post_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["user_id", 1], ["post_id", 4], ["created_at", "2020-06-21 13:33:10.587067"], ["updated_at", "2020-06-21 13:33:10.587067"]]
   (4.7ms)  commit transaction
 => #<Like id: 1, user_id: 1, post_id: 4, created_at: "2020-06-21 13:33:10", updated_at: "2020-06-21 13:33:10">
**** post 변수에 4번째 글 할당 ****
**2.6.3 :011 > post = Post.find(4)**
  Post Load (0.1ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ?  [["id", 4], ["LIMIT", 1]]
 => #<Post id: 4, content: "asd입니다", user_id: 2, created_at: "2020-06-21 13:30:44", updated_at: "2020-06-21 13:30:44"> 

**** 4번째 글을 좋아했던 유저 찾기 ****
**2.6.3 :012 > post.liked_users**
  User Load (0.2ms)  SELECT "users".* FROM "users" INNER JOIN "likes" ON "users"."id" = "likes"."user_id" WHERE "likes"."post_id" = ?  [["post_id", 4]]
 => #<ActiveRecord::Associations::CollectionProxy [#<User id: 1, email: "comp-er@daum.net", name: "정형찬", created_at: "2020-06-16 07:21:14", updated_at: "2020-06-16 07:55:00">]>

'Rails 5 on aws c9' 카테고리의 다른 글

N9. 댓글 기능 구현  (0) 2020.07.05
N8. 좋아요 기능 UI 구현하기  (0) 2020.07.05
N6. Post 수정과 삭제  (0) 2020.07.05
N5-1. post 결과물을 json으로 응답받기  (0) 2020.07.05
N5. Post 리스트와 생성  (0) 2020.07.05