かずきの日記

エンジニア・起業・人生の日記

Ruby on Rails トップページでenumを使ったカラムの値をボタンひと押しで変える仕組み

 

どうもかずきです!

 

今回は

Ruby on Rails トップページでenumを使ったカラムの値をひと押しで変える

という方法を紹介していきます!

 以下のURLの動画ような物をサーバー内で作るイメージです

https://i.gyazo.com/8ce083c08b78da97383ba182141bb926.mp4

「フリー写真 パソコン カフェ」の画像検索結果

 

 

enumとは?

enum

プログラム上での状態や種類などの変数を定数定義してくれて、その定義内であれば勝手にデータを割り当ててくれるのでその値を意識しなくても良くなり、重複防止や可読性の向上が期待される機能です

 

うん、これだと理解しにくいです

例え話で考えていきましょう(カフェのメニュー)

 「カフェメニューフリー写真」の画像検索結果

 

とあるカフェでは

  1. コーヒー
  2. エスプレッソ
  3. ミルクティー

の名前のついた3つのメニューしか取り扱っていないとします(かなり極端ですみません)

そこでお客さんにハイボールください』と言われるとします

しかし先ほどの前置き通り、このカフェでは

1番の”コーヒー”

2番の”エスプレッソ”

3番の”ミルクティー

しか取り扱っていないので当然店員さんは

『申し訳ございません 当店では”ハイボール”というものはお取り扱いしておりません』

という”例外に対する対応”をします

 

このようにサーバー(店内)で定義したもの以外ではこのようなエラー(例外に対する対応)を吐きます

 

逆に、お店で新メニューに"ハイボール"を追加した場合は

  1. コーヒー
  2. エスプレッソ
  3. ミルクティー
  4. ハイボール

と定義順にメニュー内に割り振ってくれるので、

次にお客さんが”ハイボール”を注文し他時は

店員さんは『畏まりました ”ハイボール”ですね ○○円になります』

と行った具合に対応(正常なレスポンス)をしてくれるようになります(居酒屋じゃないんだから、この店のコンセプトブレブレじゃん)

 

Ruby on Railsenum

Railsで使う場合は、データベースのレコードのカラムの情報をモデルに定義するものです

先ほどのカフェのメニューを例にすると

app/model/cafe.rb


enum menu: {
  コーヒー: 1
  エスプレッソ: 2
  ミルクティー: 3 
} 

みたいな感じですね

 

二種類の書き方を紹介するとこんな感じ

app/model/hoge.rb


# 何か特定の値で割り振る場合
enum カラム名: { カラムの中身
a: 固定値1 カラムの中身b: 固定値2 カラムの中身c: 固定値3 }

# 自動的に割り振る場合
enum カラム名: { カラムの中身a,カラムの中身b, カラムの中身c }

 

先ほどのカフェの例だと前者になります

 

本題

冒頭の動画URLで同じものを貼っていますが、今回はトップページにずらっと並んでいるタスク一覧のSTARTボタンを押すとDOING表示になって、これをもう一度押すとSTARTボタンに戻ってくれる動きを作ります

今回はAJAXなどは使わずにボタンを押すとデータ内のカラムの値と表示が変わってくれる仕組みという認識で大丈夫です

 

 

まずはこのボタンをリンクにして、そのリンクを押すと見た目とデータの中身が変わるようにしたいので、パスを作ります

 

ルーティング

config/routes.rb


Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  root 'tasks#index'

  resources :tasks do
    patch :change_status  # こいつを追加
  end
end

 

 一応基本的なルートはすでに作っているのでネストして追加してみます

ちなみにこの場合は部分的更新なのでHTTPメソッドはPATCHにします

 

データベースのカラムの状態確認もしくは修正

db/schema.rb


# 省略    
t.integer "status", default: 0, null: false
# 省略

 

 データはtasksテーブルを作っていてその中のカラムの一つにstatusカラムを作っています ここをいじくります

この意味は型をintegerつまり整数列で管理していて、通常状態を0、このカラムの中身が何もない状態はダメですよと行った感じです

テーブル生成時にこのような制約などを設定するのですが、後から変えることも簡単にできます この記事が参考になるかも?

 モデル

続いてここでenumを使います

app/model/task.rb


class Task < ApplicationRecord
# 省略
enum status: { START: 0, DOING: 1, COMPLETED: 2 } def change_status! if START? DOING! else START! end end end

アソシエーションとかバリデーションについての記述も開発においては大事ですが今回の内容的に関連性があまりなさそうなので省略しました

 

タスクの進捗状況ということで、何も手をつけていないデフォルトの状態がSTART(0)ということになり、DOING(1),COMPLETED(2)と定義できました

 

今回タスク状態を切り替えたいのはSTARTとDOINGなのでchange_status!メソッドを定義して切り替え可能にします

ちなみに『!(感嘆符)』をメソッドにつけることで例外処理を行えるようになります

 コントローラ

app/controller/tasks_controller.rb


class TasksController < ApplicationController

  before_action :task_set, only: [:show, :edit, :update, :destroy, :change_status]
# 省略
def change_status @task.change_status! redirect_to root_path, notice: 'successfully updated.' end # 省略
private def task_set @task = Task.find(params[:task_id]) end def task_params params.require(:task).permit(:name, :text, :limit_date, :status, :level, :priority, :genre_id) end end

 トップページなのでroot_pathにリダイレクトさせるように書いています

細かいところは省いていますがこんな感じです

 

privateメソッドで定義したtask_setですが、特定のidのtaskを持って来る際にparams[:id]だとnilになってしまうのでtask_idにしています

 

ビュー

app/view/tasks/index.html.haml

 マークダウンだとズレが生じるので写真で失礼します

 表示する状態を変数としたいのでtask.status

はじめに作ったパスをリンクにしています

メソッドはpatch

 

if文で分けている理由はSTARTの時とDOINGの時でclass名を変えて、cssで見た目を変えるためです

これに関してはお好みの問題になって来るので割愛します

 

ひとまずこのような流れで作成することができました!

 

それでは