코드캐더미로 배우는 레일즈 기초 3부

23 May 2015

코드캐더미로 배우는 레일즈 기초 2부에서 두 개의 모델을 사용하여 데이터를 저장하는 앱을 만들었다. 데이터 간에 one-to-many 관계를 만들기 위해 has_many / belongs_to 를 사용하였다.

MovieApp

영화는 배역을 맡은 많은 배우가 있고, 각 배우는 역시 출연한 많은 영화가 있다. 이러한 데이터를 모델링하기 위해서는 many-to-many 관계가 필요하다. 영화 웹사이트를 위한 레일즈앱을 만들어 보자.

    rails new MovieApp
    cd MovieApp
    bundle install

Model

Movie, Actor, Part 모델을 제너레이트한다.

    rails generate model Movie
    rails generate model Actor
    rails generate model Part

app/models/movie.rb에 다음 매서드를 추가한다:

has_many :parts 
has_many :actors, through: :parts

Movie 모델과 Actor 모델을 Part 모델을 통해서 연결하기 위해 has_many :through를 사용한다. has_many :through가 영화와 배우 간의 many-to-many 관계를 만든다.

app/models/actor.rb에 다음 매서드를 추가한다:

has_many :parts 
has_many :movies, through: :parts

app/models/part.rb에 다음 매서드를 추가한다:

belongs_to :movie 
belongs_to :actor

계속해서 db/migrate/ 안의 movies 테이블을 위한 마이그레이션 파일에 다음 컬럼을 추가한다:

t.string :title
t.string :image
t.string :release_year
t.string :plot

actors 테이블을 위한 마이그레이션 파일에 다음 컬럼을 추가한다:

t.string :first_name
t.string :last_name
t.string :image
t.string :bio

parts 테이블을 위한 마이그레이션 파일에 다음을 추가하여 영화와 배우 테이블을 가리키는 foreign keys를 추가한다:

t.belongs_to :movie, index: true 
t.belongs_to :actor, index: true

세 가지 테이블로 데이터베이스를 업데이트한다:

    rake db:migrate
    rake db:migrate:status // 세 모델이 만들어졌는지 상태를 확인할 수 있다.

미리 준비된 seed.rb로 영화와 배우에 대한 데이터를 공급한다:

    rake db:seed

Route

    rails generate controller Movies

라우터 파일 config/routes.rb/movies URL을 Movies 컨트롤러의 index 액션을 매핑한다:

get '/movies' => 'movies#index'

Movies 컨트롤러 안에 모든 영화를 보여주는 index 액션을 추가한다:

def index
    @movies = Movie.all
end

app/views/movies/index.html.erb를 만들고 뷰에 해당하는 코드를 입력한다:

<div class="hero">
  <div class="container">
    <h2>Interstellar</h2>
    <p>Former NASA pilot Cooper (Matthew McConaughey) and a team of researchers travel across the galaxy to find out which of three planets could be mankind's new home.</p>
    <a href="#">Read More</a>
  </div>
</div>

<div class="main">
  <div class="container">
  <h2>Popular Films</h2>

    <% @movies.each do |m| %>
    <div class="movie">
      <%= image_tag m.image %>
      <h3><%= m.title %></h3>
      <p><%= m.release_year %></p>
    </div>
    <% end %>
  </div>
</div>

스타일링을 위해 applcation.css를 입력한다.

이제 http://localhost:3000/movies을 방문하면 아래와 같은 멋진 앱이 뜬다.

라우트 파일에 /movies/1과 같은 URL에 대한 요청을 Movie 컨트롤러의 show 액션으로 보내고, 이 라우트를 “movie”라고 부른다:

get '/movies/:id' => 'movies#show', as: :movie

Movies 컨트롤러 파일에 특정 영화와 그 배우들을 보여주는 show 액션을 추가한다.

  • id로 영화를 찾기 위해 Movie.find를 먼서 사용하고,
  • 영화에 속한 모든 배우를 가져와서, @actors에 저장한다:
def show
  @movie = Movie.find(params[:id])
  @actors = @movie.actors
end

app/view/movies/show.html.erb를 만들고 다음을 입력한다:

<div class="main movie-show">
  <div class="container">
    <div class="movie">
      
      <!-- Display the movie's info here -->
      <div class="info">
        <%= image_tag @movie.image %>
        <h3 class="movie-title"><%= @movie.title %></h3>
        <p class="movie-release-year"><%= @movie.release_year %></p>
        <p class="movie-plot"><%= @movie.plot %></p>
      </div>
    </div>

    <h2>Cast</h2>
    <% @actors.each do |actor| %>
    <div class="actor">
      <%= image_tag actor.image %>
      <h3 class="actor-name"><%= actor.first_name %> <%= actor.last_name %></h3>
      <p class="actor-bio"><%= actor.bio %></p>
    </div>
    <% end %>
  </div>
</div>

app/views/movies/index.html.erb의 movie’s plot 밑에 link_to를 이용하여 “Learn more” 텍스트 링크를 만들고, show 라우트를 “movie”로 명명하였기 때문에 레일즈가 만들어주는 movie_path 헬퍼 매서드를 사용하여 각 영화의 패스로 URL을 제너레이트해주는 것을 이용한다:

<p><%= movie.plot %></p>
<%= link_to "Learn more", movie_path(movie) %>
  • 여기서 m 변수를 movie 변수로 갑자기 바꿨는데, 가독성이 좀 더 나은 것 같아서 그대로 다 변경하였다.

이제 “Learn more”를 클릭하면 영화 정보와 배우들의 정보를 볼 수 있다:

이제 배우가 출연한 모든 영화를 볼 수 있도록 해보자.

“Actors”라는 컨트롤러를 제너레이트한다:

  rails generate controller Actors

라우트 파일에 /actors URL을 Actors 컨트롤러의 index 액션에 매팅하는 라우트를 추가한다:

  get '/actors' => 'actors#index'

컨트롤러에 모든 배우 목록을 보여주는 index 액션을 추가한다.

def index
  @actors = Actor.all
end

app/views/actors/index.html.erb를 만들고 다음을 입력한다:

<div class="main actor-index">
  <div class="container">
    <div class="row">
      <% @actors.each do |actor| %>
       <div class="actor col-xs-2">
         <%= image_tag actor.image %>
         <h3><%= actor.first_name + " " + actor.last_name %></h3>
        <p><%= actor.bio %></p>
      </div>
      <% end %>
  </div>
</div>

라우트 파일로 돌아가서 /actors/1과 같은 URL에 대한 요청을 Actors 컨트롤러의 show 액션으로 보내주는 라우트를 추가하고, “actor”로 명명한다:

get '/actors/:id' => 'actors#show', as: :actor

그리고 컨트롤러에 각 배우와 출연한 영화를 보여주는 show 액션을 추가한다. id로 배우를 먼저 찾고, 배우가 출연한 모든 여와를 보여준다:

def show
  @actor = Actor.find(params[:id])
  @movies = @actor.movies
end

app/views/actors/show.html.erb를 만들고 다음을 입력한다:

<div class="main actor-show">
  <div class="container">
    
    <!-- Display an actor's info here -->
    <div class="actor">
      <%= image_tag @actor.image %>
      <div class="info">
        <h3 class="actor-name"><%= @actor.first_name + " " + @actor.last_name %></h3>
        <p class="actor-bio"><%= @actor.bio %></p>
      </div>
    </div>

    <h2>Movies</h2>
    <!-- Display each movie's info here -->
    <% @movies.each do |movie| %>
    <div class="movie">
      <%= image_tag movie.image %>
      <h3 class="movie-title"><%= movie.title %></h3>
      <p class="movie-release-year"><%= movie.release_year %>/p>
      <p class="movie-plot"><%= movie.plot %></p>
    </div>
    <% end %>
  </div>
</div>

마지막으로 app/views/actors/index.html.erb를 만들고 “Learn more” 이름의 링크를 link_to를 사용하여 만들고 actor_path를 이용한다:

<%= link_to "Learn more", actor_path(actor) %>

소스코드의 위치와 내용을 깃허브에 올려놓았다.

배우와 영화가 many-to-many 관계를 사용하여 모델링할 수 있다 레일즈에서는 has_many:through를 사용하는 것도 제공된다. has_many:through 관계는 세번째 모델을 이용하여 두 모델을 조인한다.

축하한다! 코드캐더미 레일즈 코스를 다 마친 것이다.

맺음말

코드캐더미의 레일즈 강좌는 레일즈의 MVC 속성을 쉬운 앱부터 시작하여 여러 형태의 앱을 반복해서 만들어 볼 수 있다. 비슷한 코드를 계속해서 입력하게 하기 때문에 나름대로 처음 접한 MVC의 이해도를 높을 수 있었다. 그런데 3개의 글을 그냥 읽기만하는 블로그 독자에게는 매우 지루한 일일수도 있을 것 같다는 생각이 든다. 직접 강좌를 하면서 참고용으로 삼기 바란다=3=3=3

추천 링크

Share this:

comments powered by Disqus