タグのタイトルを動的に出力

♡app/helpers/application_helper.rbに必要な内容を記載

♡app/views/layouts/application.html.erbで全体に反映する

♡各viewに反映する

①app/helpers/application_helper.rbに必要な内容を記載

module ApplicationHelper
  def page_title(page_title = '')
    base_title = 'タイトル'
    page_title.empty? ? base_title : "#{page_title} | #{base_title}"
  end
end

以下のようにしたところ

Prefer string interpolation to string concatenation.

とRubocopで弾かれた。

def page_title(page_title = '')
  base_title = 'タイトル'
  page_title.empty? ? base_title : page_title + ' | ' + base_title
end

②app/views/layouts/application.html.erbで全体に反映する

<head>
  <title><%= page_title(yield(:title)) %></title>
</head>

③各viewに反映する

app/views下に

<%= content_for(:title, t('.title')) %>

を追加していく。

掲示板詳細画面のタグは閲覧している掲示板名を表示するため、

<% content_for(:title, @board.title) %>

にする。

 

 

コメントの編集・削除ボタン表示の判定ロジック(モデルに記載)

今回の実装ではコメントの編集・削除ボタンが表示されるのは、コメントを投稿した本人のみにしたい。

判定ロジックを用いるが、今後メンテナンスをするときのためにmodelのみにまとめて記載する。

♡判定ロジックはUserモデルにまとめて記載する等、自分で決めておくと良いらしい。

♡クラスメソッドに定義して引数に判定に必要なオブジェクトをすべて記載するのではなく、インスタンスメソッドとして記載する

→クラスメソッドにしてしまうと判定用のオブジェクトを全て記載しなければいけなくなるため。

self.my_comment?(current_user, comment)
  current_user == comment.user
end

とした場合、

if User.my_comment?(current_user, @comment)

としなければならなくなる。

インスタンスメソッドで記載した場合、

if current_user.my_comment?(@comment)

となり、引数の記載がシンプルになる。

♡comment.user→ belongs_to :user の定義により使えるようになるアソシエーションメソッド。

♡commentモデルにある user_id を使うよう指定してしまうと、Usersテーブルから対象のレコードを取ってきてしまい、SQLが発行される。

♡comment.user_idであれば、commentインスタンスが持っている user_id を使って比較しているに過ぎないのでSQLが発行されない。

♡selfレシーバは省略して記載するのが一般的。(Rubocopにも引っかかった)

(なので理想的な形は以下のようになるそう)

 

app/model/user.rbの場合

def my_comment?(comment)
  self == comment.user
end

# 表示したいview側で以下のように記載
# if current_user.my_comment?(@comment) 
def my_comment?(comment)
  comment.user_id == id
  # comment.user_id == self.id の省略形
end

最も汎用性の高い記載方法↓

def own?(object)
  object.user_id == id
end

view側で以下のように記述する。

<% if current_user.own?(comment) %>

 

 

 

 

 

routes/controllerへの追記(コメント機能の追加)

♡config/routes.rbへの追記

♡app/boards.controller.rbへの追記(詳細画面の追加)

♡app/comments.controller.rbの設定

①config/routes.rbへの追記(ネストする)

resources :boards, only: %i[index new create show] do
    resources :comments, only: %i[create], shallow: true

shallowオプションを用いてcommentsをboardsを入れ子の形にする。

あくまでも浅いネストにするため、深いネストにならないよう、idを用いないアクションのみを親のスコープ下で生成する。

idを用いるアクション→show、edit、update、destroy等

 

②app/boards.controller.rbへの追記(詳細画面の追加)

showアクションの追記をする。

☆N+1問題を解消するため.includes(:user)を追記する。

belongs_toやhas_manyでアソシエーションを組んでいるため、異なるテーブルから逐一データを取得してしまう。解消して無駄をなくす。

☆作成したコメントが降順で表示されるよう、.order(created_at: :desc)を記入する。

desc = descendingの略。

def show
  @board = Board.find(params[:id])
  @comment = Comment.new
  @comments = @board.comments.includes(:user).order(created_at: :desc)
end

③app/comments.controller.rbの作成

rails g controller comments

のコマンドでコントローラーを作成。

class CommentsController < ApplicationController
  def create
    comment = current_user.comments.new(comment_params)
    if comment.save
      redirect_to board_path(comment.board), success: t('.success')
    else
      redirect_to board_path(comment.board), danger: t('.fail') 
    end
  end

  private

  def comment_params
    params.require(:comment).permit(:body).merge(board_id: params[:board_id])
  end
end

☆ストロングパラメーター

requireの引数 = モデル名

permitの引数 = カラム名

☆merge部分について

.merge(board_id: params[:board_id])

merge = 結合

board_id: params[:board_id]はルーティングをネストしており、URLにboard.idが含まれているため。

idはユーザーが記入しているわけではないが、作成している側がDBに保存しておきたいため、mergeを用いることで同時にboard.idについても保存することができるようにしている。

※コメント登録失敗時に、renderを用いていないのは今後実装する内容に関わってくるため。

 

 

コメントのDB作成と紐付け

<手順>

♡コメントのデータベースの作成し、DB側に制約をかける

♡userとboardモデルに紐付けをする

♡コメントモデルに制約を追加する

 

①コメントのデータベースを作成

rails g model Comment body:text user:references board:references

 

外部キー制約をする際はreferencesを用いるので、作成時のコマンドに入れる

文字数制限を60000字(仮)にする→limit: 60000を追記

bodyすなわち本文の入力なしでは登録できないようにする→null:falseを追記

 

class CreateComments < ActiveRecord::Migration[5.2]
  def change
    create_table :comments do |t|
      t.text :body, limit: 60000, null:false
      t.references :user, foreign_key: true
      t.references :board, foreign_key: true

      t.timestamps
    end
  end
end

②userとboardモデルに紐付けていく

☆app/models/comment.rb

①でgenerateした際に、referencesを用いたため、

自動的にbelongs_to :userbelongs_to :board

が作成されている。

class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :board
end

app/models下のuser.rbとboard.rbに

has_many :comments, dependent: :destroy

を追加し、以下のようにする。

☆app/models/user.rb

class User < ApplicationRecord
  authenticates_with_sorcery!
  has_many :boards, dependent: :destroy
  has_many :comments, dependent: :destroy
end

☆app/models/board.rb

class Board < ApplicationRecord
  belongs_to :user
  has_many :comments, dependent: :destroy
end

board.rbもuser.rbと紐付いているのでこんがらがる…。

③コメントモデルにバリデーションを追加する

class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :board
  validates :body, presence: true, length: { maximum: 60_000 }
end

エラーメッセージのパーシャル作成

ユーザーの新規登録や掲示板の作成時に、「○○を入力してください」というフラッシュメッセージを表示したいが、複数のビュー画面で表記したい。

効率的に表記するためにパーシャルを作成する。

すでにモデルにバリデーションは記載してあるので、続きからの手順をメモしておく。

 

 

<手順>

♡(今回は事前に行っている状態だが、モデルにバリデーションを設定しておく)

♡エラーメッセージのパーシャル作成

♡表示したいビューに埋め込んでいく

 

 

①モデルにバリデーションの設定がなされているか確認

app/models/board.rb

class Board < ApplicationRecord
  belongs_to :user
  mount_uploader :board_image, BoardImageUploader
  validates :title, presence: true, length: { maximum: 255 }
  validates :body, presence: true, length: { maximum: 65_535 }
end
     

設定できているので、次にすすむ

 

②エラーメッセージのパーシャルを作成する

    

<% if object.errors.any? %>
  <div id="error_explanation" class="alert alert-warning">
    <ul>
      <% object.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>

 

③表示したいビューに埋め込んでいく

 新規登録画面と掲示板作成画面に以下のように埋め込む。

 

 

 

 object: f.objectとすることで、流用する際にそのまま使えて便利になる。

 

 

 

 

 

 

 

 

 

掲示板(作成機能)

サイトに登録している人がboardを作成できるよう機能を作る。

 

①ビュー側から入力された情報を保存する

   app/controllers/boards_controller.rb

   のcreateに以下のように定義する。

 

  def create

      @board = current_user.boards.new(board_params)

      if @board.save 

 

current_user.boards.newで、

・初期化することができる

・viewで入力フォームに入ってきた情報のオブジェクトを作成することができる

 

②ストロングパラメーターの記載

   boards_controller.rbのpraivate下に、

  def board_params

      params.require(:board).permit(:title, :body)

  end

 

を記載する。

  

 

 

 

ストロングパラメーター(復習)

①ストロングパラメーターとは

web上から入力されるパラメーターが安全なものか検証し、取得する仕組み。

メソッドに受け付けるカラム名(id,name等列にあたる部分)を事前に指定しておく。

指定されていないカラムデータが送られてきた場合、弾くことができる。

 

 

②実際に記載してみる

適用したい、今回はapp/controllers下のusers.controller.rbに以下のように記載する。

 

 

private

def user_params
params.require(:user).permit(:email, :password, :password_confirmation,
:name)
end