Association
레일즈에서는 정말로 이해하기 쉬운 관계설정들이 존재한다. 이해할 필요도 없이 보는순간 딱알겠는 부분들이 대부분이다. 하지만 단 두가지는 순간적으로 뭐지? 싶은 관계(다대다 m:n)설정이라서 정리해 보았다.
has_and_belongs_to_many
하나의 수업이 여러명의 학생을 가질 수 있고 한 학생이 여러개의 수업을 들을 수 있다.
가장 일반적인 다대다 관계를 표현하는 방법이다. 이러한 관계를 표한하기 위해서는 관계를 표현할 두개의 테이블(수업, 학생) 그리고 한개의 중간테이블이 필요하다.
관계를 표현할 두개의 테이블
학생테이블과 수업테이블을 만들것이다. (왠지 class
라고하면 예약어 문제가 생길것같은 괜한 거부감에 classroom
으로 했다.)
rails g model student
rails g model classroom
각 모델 파일에 들어가 has_and_belongs_to_many
관계를 명시해주고, rake db:migrate
해준다.
#student.rb
class Student < ApplicationRecord
has_and_belongs_to_many :classrooms
end
#classroom.rb
class Classroom < ApplicationRecord
has_and_belongs_to_many :students
end
한개의 중간테이블
두 테이블 사이에서 관계설정을 도와줄 테이블이다. 별도의 모델을 만들 필요없이 테이블만 설정해주면 된다. (이름은 알파벳순으로 해준다.)
rails g migration CreateJoinTableClassroomStudent classroom student
아래와 같은 migrate 파일이 생성되면 rake db:migrate
해준다.
class CreateJoinTableClassroomUser < ActiveRecord::Migration
def change
create_join_table :classrooms, :users do |t|
t.index [:classroom_id, :student_id]
# t.index [:student_id, :classroom_id]
end
end
end
확인하기
rails c
로 콘솔에 접근한뒤 student 와 classroom의 관계를 확인해보자.
> s = Student.new
> s.save
> c = Classroom.new
> c.save
> c.users << s
> c.users
#<ActiveRecord::Associations::CollectionProxy [#<Student id: 1, created_at: "2017-07-26 09:05:29", updated_at: "2017-07-26 09:05:29">]>
> s.classrooms
<ActiveRecord::Associations::CollectionProxy [#<Classroom id: 1, created_at: "2017-07-29 10:24:37", updated_at: "2017-07-29 10:24:37">]>
has_many through
사용자는 여러개의 영화 리뷰를 작성할 수 있다. 영화는 여러개의 리뷰를 가질 수 있다.
다대다 관계에서는 has_and_belongs_to_many
관계처럼 직접적이지 않은 관계도 있다.
#user.rb
class User < ActiveRecord::Base
has_many :reviews
has_many :movies
end
#movie.rb
class Movie < ActiveRecord::Base
has_many :reviews
has_many :users
end
#comment.rg
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :movie
end
Movie모델과 User모델은 직접적인 관계는 없지만, 공통적으로 Comment 모델과의 관계를 갖고있다. 이런 경우 Comment를 통해서(through
) 각모델을 접근할 수 있다.
#user.rb
class User < ActiveRecord::Base
has_many :reviews
has_many :movies, through: :reviews
end
#movie.rb
class Movie < ActiveRecord::Base
has_many :reviews
has_many :users, through: :reviews
end
user = User.first
user.comments[0].movie #원래는 이런식으로 Movie에 접근했지만,
user.movies #comments를 생략하고 접근이 가능하다.