Ruby on Rails

コントローラー

Ruby on Rails

アクション・params・before_action・レスポンス

コントローラーの基本

アクション・params・strong parameters・レスポンス

app/controllers/posts_controller.rb ruby
class PostsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_post, only: [:show, :edit, :update, :destroy]
  before_action :authorize_post!, only: [:edit, :update, :destroy]

  def index
    @posts = Post.published.recent
                 .includes(:user, :tags)
                 .page(params[:page]).per(params[:per] || 20)
    respond_to do |format|
      format.html
      format.json { render json: @posts }
    end
  end

  def show
    @comment = @post.comments.build  # フォーム用
  end

  def new
    @post = current_user.posts.build
  end

  def create
    @post = current_user.posts.build(post_params)
    if @post.save
      redirect_to @post, notice: '投稿しました'
    else
      render :new, status: :unprocessable_entity
    end
  end

  def update
    if @post.update(post_params)
      redirect_to @post, notice: '更新しました'
    else
      render :edit, status: :unprocessable_entity
    end
  end

  def destroy
    @post.destroy!
    redirect_to posts_path, notice: '削除しました', status: :see_other
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  # Strong Parameters
  def post_params
    params.require(:post).permit(:title, :body, :status, tag_ids: [])
  end

  def authorize_post!
    redirect_to root_path, alert: '権限がありません' unless @post.user == current_user
  end
end

フィルターとコンサーン

before_action・ApplicationController・Concern

app/controllers/application_controller.rb ruby
class ApplicationController < ActionController::Base
  include Authenticatable
  include Paginatable

  # 例外ハンドリング
  rescue_from ActiveRecord::RecordNotFound do |e|
    respond_to do |format|
      format.html { render 'errors/not_found', status: :not_found }
      format.json { render json: { error: e.message }, status: :not_found }
    end
  end

  rescue_from ActionPolicy::Unauthorized do
    render json: { error: '権限がありません' }, status: :forbidden
  end

  private

  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end

  def authenticate_user!
    redirect_to login_path unless current_user
  end
end

# Concern(共通処理の分離)
module Authenticatable
  extend ActiveSupport::Concern

  included do
    helper_method :current_user, :logged_in?
  end

  def logged_in?
    current_user.present?
  end

  def require_admin!
    render json: { error: 'forbidden' }, status: :forbidden unless current_user&.admin?
  end
end

パラメーターとレスポンス

params・flash・redirect・render・ステータスコード

params_responses.rb ruby
# params の操作
params[:id]                          # URL パラメーター
params[:user][:name]                 # ネストしたパラメーター
params.require(:user).permit(:name, :email)  # Strong Parameters
params.permit!                       # 全許可(非推奨)

# Strong Parameters の詳細
def user_params
  params.require(:user).permit(
    :name, :email, :password,
    :avatar,                          # ファイルアップロード
    preferences: [:theme, :lang],     # ネストしたハッシュ
    role_ids: [],                     # 配列
    address_attributes: [:street, :city, :_destroy]  # nested attributes
  )
end

# レスポンス
render :show                          # ビューを描画
render 'posts/show'
render template: 'posts/show'
render partial: 'form', locals: { post: @post }
render json: @post
render json: @post, status: :created
render json: { error: 'Not found' }, status: :not_found
render nothing: true, status: :no_content
head :ok                              # ボディなし
head :not_found

# redirect
redirect_to @post
redirect_to posts_path
redirect_to posts_path, notice: '作成しました'
redirect_to posts_path, alert: 'エラーが発生しました'
redirect_back fallback_location: root_path
redirect_to @post, status: :see_other  # POST→GETのリダイレクト(303)

# flash
flash[:notice] = '作成しました'
flash[:alert]  = 'エラーが発生しました'
flash.now[:notice] = '現在のリクエストのみ'  # redirect しない場合

# HTTPステータスコード(シンボルで指定可)
# :ok(200) :created(201) :no_content(204)
# :not_modified(304) :see_other(303)
# :bad_request(400) :unauthorized(401) :forbidden(403) :not_found(404)
# :unprocessable_entity(422) :too_many_requests(429)
# :internal_server_error(500)