もた日記

くだらないことを真面目にやる

Railsメモ(17) : コントローラとビューを更新する

Artistモデルを作成し、SongモデルとArtistモデルの間に多対多のリレーションを作成したので、コントローラとビューも更新する。
最初に下記コマンドでひな形を作成する。今回はArtistの一覧を表示するindexページとArtist個別のshowページを作成する。

$ rails g controller Artists index show
      create  app/controllers/artists_controller.rb
       route  get 'artists/show'
       route  get 'artists/index'
      invoke  erb
      create    app/views/artists
      create    app/views/artists/index.html.erb
      create    app/views/artists/show.html.erb
      invoke  helper
      create    app/helpers/artists_helper.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/artists.coffee
      invoke    scss
      create      app/assets/stylesheets/artists.scss


続いてconfig/routes.rbを書き換える。
resourcesを指定すると7つの基本アクションが追加されるが、以下のようにonlyで使用するアクションだけを指定することができるようだ。

Rails.application.routes.draw do
  #get 'artists/index'
  #get 'artists/show'
  resources :artists, only: [:index, :show]
$ rake routes
 Prefix Verb URI Pattern            Controller#Action
artists GET  /artists(.:format)     artists#index
 artist GET  /artists/:id(.:format) artists#show
 …省略…

コントローラの編集


コントローラーのapp/controllers/artists_controller.rbは下記のようにした。indexでは全アーティストを、showでは個別のアーティストを取得する。ここでbefore_actionはアクションコールバックと呼ばれるもので各アクションの前で実行したい共通の処理を記述することができる。今回は、Navbarに検索用フォームを作成しているのでbefore_actionを使用して対応した(他にもっとよい方法があるのかも知れないが)。

class ArtistsController < ApplicationController
  before_action :navbar_ransack

  def index
    @artists = Artist.page(params[:page])
  end

  def show
    @artist = Artist.find(params[:id])
  end

  private
  def navbar_ransack
    @q = Song.ransack(params[:q])
  end
end

ビューの編集(views/artists)


app/views/artists/index.html.erbは以下のようにアーティスト名と曲数を一覧で表示するようにする。アーティスト名にはリンクは貼り、曲数はartist.songs.sizeで取得してみる。

<table class="table table-striped table-hover">
  <thead>
    <tr>
      <th>Name</th>
      <th>Songs</th>
    </tr>
  </thead>
  <tbody>
    <% @artists.each do |artist| %>
    <tr>
      <td><%= link_to artist.name, artist_path(artist) %></td>
      <td><%= artist.songs.size %></td>
    </tr>
    <% end %>
  </tbody>
</table>
<%= paginate @artists %>

図は実際の出力例。
f:id:wonder-wall:20150816145137p:plain

app/views/artists/show.html.erbは、そのアーティストが関連する曲をリスト表示する。@artist.songs.eachでループをまわせば図のような出力になる。

<table class="table table-striped table-hover">
  <thead>
    <tr>
      <th>Title</th>
      <th>Display artist</th>
      <th>ranking</th>
      <th>year</th>
    </tr>
  </thead>
  <tbody>
    <% @artist.songs.each do |song| %>
    <tr>
      <td><%= song.title %></td>
      <td><%= song.display_artist %></td>
      <td><%= song.ranking %></td>
      <td><%= song.year %></td>
    </tr>
    <% end %>
  </tbody>
</table>

f:id:wonder-wall:20150816145551p:plain

ビューの編集(views/songs)


app/views/songs/index.html.erbも編集して、図のように複数アーティスト名がある文字列に対して個別にアーティストへのリンクを貼るようにしてみる。

f:id:wonder-wall:20150816145919p:plain

いろいろと書き方はありそうだが、とりあえず以下のようにgsub!で変換した後にhtml_safeで出力する方法にしてみた。

 …省略…
<% @songs.each do |song| %>
<tr>
  <td><%= song.title %></td>
  <td>
    <% song.artists.each do |artist| %>
      <% song.display_artist.gsub!(/#{artist.name}/) {link_to artist.name, artist_path(artist)} %>
    <% end %>
    <%= song.display_artist.html_safe %>
  </td>
  <td><%= song.ranking %></td>
  <td><%= song.year %></td>
</tr>
<% end %>
 …省略…

ビューの編集(views/layouts)


最後に、NavbarにArtist一覧表示のリンクを追加し、検索フォームを右端に表示するようにして終了。

 …省略…
<div class="navbar navbar-default navbar-fixed-top">
  <div class="container">
    <div class="navbar-header">
      <%= link_to 'Billboard', root_path, class: 'navbar-brand' %>
    </div>
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li><%= link_to 'Artist', artists_path %></li>
      </ul>
      <%= search_form_for @q, html: { class: 'navbar-form navbar-right' } do |f| %>
        <%= f.input :title_cont, label: false, placeholder: 'title' %>
        <%= f.input :display_artist_cont, label: false, placeholder: 'display_artist' %>
        <%= f.button :submit %>
      <% end %>
    </div>
  </div>
</div>
 …省略…

f:id:wonder-wall:20150816151757p:plain

これでアーティスト関連のページが表示できるようになったが、ログを見てみると大量のSQL文が実行されているので次ステップで対応してみる。

f:id:wonder-wall:20150816152212p:plain

パーフェクト Ruby on Rails

パーフェクト Ruby on Rails