経緯
やっぱり映画関連のアプリ作るなら公式情報を利用して作りたいよね~
てことで、「The Movie DataBase(TMDB)」のAPIを使っていきます。
初学者ゆえ、かなり脳筋な実装となっております。
TMDBって?
Let's talk about TMDB
The Movie Database (TMDB) is a community built movie and TV database. Every piece of data has been added by our amazing community dating back to 2008. TMDB's strong international focus and breadth of data is largely unmatched and something we're incredibly proud of. Put simply, we live and breathe community and that's precisely what makes us different.
要はコミュニティによって作られた映画やテレビ番組のデータベースという感じですかね。
このTMDBが出しているAPIを使って映画の公式情報を取得していきます。
この記事でできる事
1.映画の情報を取得&検索できる。
2.選択した映画の情報を利用しながら感想などを付け加えて投稿できる
3.映画の取得件数の調整やページネーション
完成イメージ
映画関連のMVCとしてMovieを用意
本記事で取得する映画情報は以下の通り
(取得したい情報→それに対応するAPI内の映画情報
)
タイトル→title
ポスター→poster_path
あらすじ→overview
公開日→release_date
その他に欲しい映画情報は以下を参照するなり用意してください。
選択した映画を投稿するMVCとしてPostを用意
本記事ではAPIで取得した映画情報を投稿する為にそれぞれに対応したカラムを用意して投稿できる仕様なので、以下の様なカラムを用意。
公開日の投稿はしない事にしました。
(API内の映画情報→対応させるため用意したカラム名:データ型
)
title→title:string
poster_path→image:string
overview→overview:text
これらのカラムに加え映画に自分のコメントを残せるよう、contents:text
も用意した。
手順
1.APIの登録
2.映画用のMVC作成
3.投稿用のMVC作成
1-1.APIの登録
こちらにてアカウント登録とAPIの登録(申請をしましょう)
APIの登録は以下を参考にしてみてください
※すべて英語ですがスクショ等あるので翻訳機能等を活用しましょう
古い記事ですがこちらも参考までに
API登録に関してポイント
1.Application URL
は適当に入れていても恐らく問題ないが、心配だったら先にリリースしてURLを貼っておく。
2.Application Summary
は英語で書く。
もしかしたらテキトーに登録してもいけるかもですが、一応ね!
取得できたAPIキーは忘れずメモしておきましょう!
サイトからAPIキーを確認したい時は 「右上ユーザーアイコン→プロフィール編集→左側サイドバーのAPI」 をクリックすると確認できます。
1-2.APIの登録(環境変数にする)
APIキーが外部に公開されるのを防ぐために
gemのdotenv-rails
を利用します。
①gemfileに以下を追加・gemのインストール
gem 'dotenv-rails'
bundle install
②app直下の階層に.env
ファイルを作成
③作成した.envファイルに追記
TMDB_API=取得した自分のTMDB APIキー
TMDB_API
に自分のAPIキーを代入しています。
スペースを空けずに先ほど取得したAPIキーをコピペしましょう。
④.gitignoreに追記
/.env
2.映画用のMVC作成
①moviesコントローラーの作成
rails g controller movies index show
②routes.rbの修正
※-と書かれてる列は削除 +と書かれている列は追記の意
rootは別途で作成している場合は追記しなくてもよい
Rails.application.routes.draw do
- get 'movies/index'
- get 'movies/show'
+ resources :movies, only: [:index ,:show]
+ root 'movies#index'
end
③movies_controller.rbの記述
class MoviesController < ApplicationController
def index
if params[:looking_for]
movie_title = params[:looking_for]
url = "https://api.themoviedb.org/3/search/movie?api_key=#{ENV['TMDB_API']}&language=ja&query=" + URI.encode_www_form_component(movie_title)
else
url = "https://api.themoviedb.org/3/movie/popular?api_key=#{ENV['TMDB_API']}&language=ja"
end
@movies = JSON.parse(Net::HTTP.get(URI.parse(url)))
end
def show
movie_id = params[:id]
url = "https://api.themoviedb.org/3/movie/#{movie_id}?api_key=#{ENV['TMDB_API']}&language=ja"
@movie = JSON.parse(Net::HTTP.get(URI.parse(url)))
end
end
詳しい説明は書き始めると長くなるのでここでは省きます。
気になる方はこちらを参考にしてみてください。
④index.html.erbの記述
映画の一覧と検索フォームの記述です
<div class="search">
<%= form_tag(root_path, method: :get) do %>
<%= search_field_tag :looking_for, nil, placeholder: 'Movie Title...' , :size => "40*40" %>
<%= submit_tag 'search' %>
<% end %>
</div>
<div class = "movies-container">
<% @movies.each do |movie| %>
<div class = "movie-data">
<p><%= movie['title'] %></p>
<%= link_to movie_path(movie['id']) do %>
<% if movie['poster_path'] %>
<p><%= image_tag 'https://image.tmdb.org/t/p/w200' + movie['poster_path'],class: "card-img" %></p>
<% end %>
<% end %>
<p><%= link_to "詳細へ", movie_path(movie['id']) %></p>
</div>
<% end %>
</div>
⑤show.html.erbの記述
投稿ページへのリンクは現地点ではエラーが出るので、コメントアウトしています。
リンク先のcrudが完成したらコメントアウトを外してください。
<div class="movie-detail">
<p><%= @movie['title'] %></p>
<p><%= @movie['release_date'] %></p>
<% if @movie['poster_path'] %>
<p><%= image_tag 'https://image.tmdb.org/t/p/w200' + @movie['poster_path'],class: "card-size" %></p>
<% end %>
<p><%= @movie['overview'] %></p>
<%#= link_to "投稿ページへ", new_post_path(movie_id: @movie['id']) %>
</div>
3.投稿用のMVC作成
通常のCRUDを実装しましょう。
カラムの関係上Postモデルの作成コマンドは表記していますが、Postモデルに対応するpostsコントローラーやルーティングの記述もCRUDが問題なく作動するように完成している前提で以降の説明は進めます。
①Postモデルの作成
rails g model post title:string image:string overview:text contents:text
②Postsコントローラーのnewアクションに追記
class PostsController < ApplicationController
def index
@posts = Post.all
end
def new
@post = Post.new
+ movie_id = params[:movie_id]
+ url = "https://api.themoviedb.org/3/movie/#{movie_id}?api_key=#{ENV['TMDB_API']}&language=ja"
+ @movie = JSON.parse(Net::HTTP.get(URI.parse(url)))
end
def create
post = Post.new(post_params)
if post.save
redirect_to :action => "index"
else
redirect_to :action => "new"
end
end
def show
@post = Post.find(params[:id])
end
def edit
@post = Post.find(params[:id])
end
def update
post = Post.find(params[:id])
if post.update(post_params)
redirect_to :action => "show", :id => post.id
else
redirect_to :action => "new"
end
end
def destroy
post = Post.find(params[:id])
post.destroy
redirect_to action: :index
end
private
def post_params
params.require(:post).permit(:title, :contents ,:image ,:overview)
end
end
③new.html.erbの記述
取得した映画情報が変更されないようhidden_field
を使います。
<h1>posts#new</h1>
<%= form_for @post do |f| %>
<div class="field">
<p><%= f.label :title %>:<%= @movie['title']%></p>
<p><%= f.hidden_field :title, :size => 140, value: @movie['title']%></p>
<p><%= image_tag 'https://image.tmdb.org/t/p/w200' + @movie['poster_path'] %></p>
<p><%= f.hidden_field :image, value: 'https://image.tmdb.org/t/p/w200' + @movie['poster_path'] %></p>
<p><%= f.label :overview %>:<%= @movie['overview']%></p>
<p><%= f.hidden_field :overview, :size => 140, value: @movie['overview'] %></p>
<%= f.label :contents,"感想" %>
<p><%= f.text_area :contents, :size => "20x5"%></p>
</div>
<%= f.submit "postする" %>
<% end %>
<%= link_to "post一覧に戻る", posts_path %>
以上で投稿まで実装できているかと思います。
おまけ
実は今の状態だと映画は20件までしか取得できていない状態です。
100件ぐらいは取得しときたいですよね!
ついでにgem kaminari
を用いて映画一覧のページネーションも実装しちゃいましょう!
①gemfileに以下を追加・gemのインストール
gem 'kaminari'
bundle install
②movies_controller.rbのindexアクションの内容を変更
下記内容に全て書き換えましょう
def index
if params[:looking_for]
movie_title = params[:looking_for]
movies = []
(1..5).each do |page|
url = "https://api.themoviedb.org/3/search/movie?api_key=#{ENV['TMDB_API']}&language=ja&query=" + URI.encode_www_form_component(movie_title) + "&page=#{page}"
response = Net::HTTP.get_response(URI.parse(url))
if response.code == "200"
result = JSON.parse(response.body)
movies.concat(result["results"])
end
end
else
movies = []
(1..5).each do |page|
url = "https://api.themoviedb.org/3/movie/popular?api_key=#{ENV['TMDB_API']}&language=ja&page=#{page}"
response = Net::HTTP.get_response(URI.parse(url))
if response.code == "200"
result = JSON.parse(response.body)
movies.concat(result["results"])
end
end
end
@movies = Kaminari.paginate_array(movies).page(params[:page]).per(20)
end
作品数を変えたい場合は(1..5).each do |page|
の(1..5)
の数字を変更してください。
1ページあたり20作品、本記事では5ページ目までと指定しているので100作品分取得しているという感じです。
kaminariの仕様については以下を参照してください。
以上です!
ここまでの差分はこちら
参考記事
今回もたくさんの先人たちのおかげで実装することが出来ました。
https://qiita.com/kazuhito_nakayama/items/c9cf578058d1e4f078a1
https://weblion303.net/1262
https://developers.themoviedb.org/3
https://github.com/kaminari/kaminari
https://docs.ruby-lang.org/ja/3.0/class/Net=3a=3aHTTPResponse.html