Rails 掲示板一覧機能 手順 (自分用)
#Bordモデルを作成する
$ bundle exec rails generate model board title:string body:text user:references
・モデルとマイグレーションファイルが作られる。
・掲示板を作るにあたってBordモデルを作る。その際に「user:references」をつけることで、Userモデルを参照してくれるようになる。(Bordモデルには「belongs_to :user」が追加され、マイグレーションファイルには、「t.references :user, foreign_key: true」が追加される。*後で説明)
#BoardモデルとUserモデルの関連付けと、バリデーションの設定
has_many :bords, dependent: :destroy
・has_manyはテーブル同士を関連づけるもの。そのクラス(ここではUser)のidを外部キーとして抱える他のクラス(ここではBord)があり、UserはBordを複数登録可能であるということ。*has_many(User)はbelongs_to(Bord)を何個も投稿できるよ!みたいなイメージ。
・「dependent: :destroy」オプションをつけることによって「boardに紐づいたuserが消されたら該当boardも削除」という作業を行なってくれる。親にあたるuserが削除された際に、子にあたるbordだけが残ると「board(子)があるのにuser(親)がいない」ということになり、整合性が取れずバグの原因になる為、「dependent: :destroy」を使う。
class Board < ApplicationRecord
belongs_to :user
validates :title, presence: true, length: { maximum: 255 }#「presence: true」で入力必須。「length: { maximum: }」は文字数制限のバリデーション。今回は、255字以内という制限。
validates :body, presence: true, length: { maximum: 65_535 }#文字数制限が65文字以上535文字以下。
end
・belongs_toはそのクラス(ここではBord)が、ある別のクラス(ここではUser)に従属しており、従属先のクラスのid(ここではuser_id)を外部キーとして抱えているということ。
#マイグレーションファイル
class CreateBoards < ActiveRecord::Migration[5.2]
def change
create_table :boards do |t|
t.string :title, null: false
t.text :body, null: false
t.references :user, foreign_key: true
t.timestamps
end
end
end
・titleとbodyにnull: falseを追加
・t.references :user, foreign_key: trueは、bordテーブルに「user_id」という外部キーカラムを追加するもの。*掲示板に投稿した際に、user_idカラムがあることで、削除や、編集を自分以外が出来ないようにする為。
$ rails db:migrate
・マイグレートする。
#掲示板一覧のコントローラーを実装
・bordに対応するコントローラーを作成
$ bundle exec rails generate controller boards
・コントローラ、view、decoratorが作成される。
#####生成されたBoardsControllerに、掲示板の一覧をDBから取得する処理を追加。
class BoardController < ApplicationController
def index
@boards = Board.all.includes(:user).order(created_at: :desc)#includesメソッド
end
end
#####includesメソッド
class BoardController < ApplicationController
def index
@boards = Board.all.order(created_at: :desc)
end
end
・includesメソッドを使わない場合、bord(投稿)の数だけuserテーブルにアクセスすることになり、データ取得に時間がかかる。その結果、アプリケーションのパフォーマンスが下がる。これを「N+1問題」という
・これを解決するためにincludesメソッドを使用する。
モデル名.includes(:アソシエーションで紐付くモデル名)
・includesメソッドは、引数に指定された関連モデルを1度のアクセスでまとめて取得するメソッド
・bordテーブルに対して1回、Userテーブルに対しても1回のアクセスで全ての情報を取得できるようになる。
#掲示板作成のrouteを追加
Rails.application.routes.draw do
root 'static_pages#top'
get 'login', to: 'user_sessions#new'
post 'login', to: 'user_sessions#create'
delete 'logout', to: 'user_sessions#destroy'
resources :users, only: %i[new create]
resources :boards, only: %i[index new create]#この部分を追加
end
#掲示板一覧のViewを実装する
<div class="container pt-3">
<div class="row">
<div class="col-lg-10 offset-lg-1">
<!-- 検索フォーム -->
<form>
<div class="input-group mb-3">
<input class="form-control" placeholder="検索ワード" type="search" />
<div class="input-group-append">
<input type="submit" value="検索" class="btn btn-primary" />
</div>
</div>
</form>
</div>
</div>
<!-- 掲示板一覧 -->
<div class="row">
<div class="col-12">
<div class="row">
<% if @boards.present? %>
<%= render @boards %> #下記で説明
<% else %>
<p><%= t('.no_result') %></p>
<% end %>
</div>
</div>
</div>
</div>
・ 「<%= render partial: 'board', locals: { board: @board }%>」の省略形は「<%= render 'board', { board: @board } %>」となっており、さらにインスタンス変数名(@board)とファイル名(_board.html.erb)が同じ場合「<%= render @boards %>」のような省略形にすることができる。
<div class="col-sm-12 col-lg-4 mb-3">
<div id="board-id-<%= board.id %>">
<div class="card">
<%= image_tag 'app/assets/images/に配置した写真のデータ名', class: 'card-img-top', size: '300x200' %>
<div class="card-body">
<h4 class="card-title">
<a href="#">
<%= board.title %>
</a>
</h4>
<div class='mr10 float-right'>
<a href="#"><%= icon 'fas', 'trash', class: 'pr-1' %></a>
<a href="#"><%= icon 'fa', 'pen' %></a>
</div>
<ul class="list-inline">
<li class="list-inline-item">
<%= icon 'far', 'user' %>
<%= board.user.decorate.full_name %>
</li>
<li class="list-inline-item">
<%= icon 'far', 'calendar' %>
<%= l board.created_at, format: :long %>
</li>
</ul>
<p class="card-text"><%= board.body %></p>
</div>
</div>
</div>
</div>
#ヘッダーに掲示板一覧ページへのリンクを追加
<div class="dropdown-menu dropdown-menu-right">
<%= link_to t('boards.index.title'), boards_path, class: 'dropdown-item' %>
<%= link_to '掲示板作成', 'new_board_path', class: 'dropdown-item' %>
</div>
・掲示板一覧のリンクをboards_pathに変更