はじめに
Qiitaを見ているとこちらの記事が目に入りました。
本当の初心者のためのenumを使った状態管理(クリック一つで状態変遷させるやつ)の実装 rails - Qiita
「ふんふん、なるほど~」と思いながら読んでいたら、GETでデータを変更しようとしていることに気づきました。
データを変更するのであれば、GET以外のHTTPメソッド(POST、PATCH、PUT、DELETE)を使う方がWebアプリケーションとして適切です。
最初は「GETを使わない方がいいですよ~」とコメントして終わろうかと思ったのですが、記事の最後の方に「初心者はview controller model route 全て具体例がないと実装できません(泣)」と書いてあります。
たしかに。
上級者なら自力で埋められる情報の溝(不足している情報)も、初心者の人にとってはなかなか乗り越えるのが難しかったりします。
それならば、ということで「こうやれば実装できますよ」というのをrails newするところから動画に撮って説明してみようと思いました。
この記事ではその動画のポイントを説明していきます。
動画はこちらです
サンプルアプリケーションを作成する様子はこちらに載せています。
Railsでenumの状態を変更するリンクの作り方 - YouTube
良くも悪くもノーカットです
ちなみに、完全ノーカットでトータル36分あります。
最初は10分ぐらいあればできるでしょー、と高をくくっていたんですが、途中でenumを使ったフォームの作り方で試行錯誤してしまい、時間を食ってしまいました。
(言い訳すると、僕は普段enumerize gemを使うことが多く、Rails標準のenumは使ったことがないんですよね。。)
試行錯誤の時間が結構長いので、さっさと先に進みたい方は11:30~19:50のあたりをスキップしてください。
あと、どっちみち長いので動画は1.5倍速ぐらいで見た方が良いと思います。
RubyMineを使ってます!
動画の中ではRubyMineを使って開発しています。
RubyMineを使ったRails開発に興味がある人も参考にしてみてください。
今回作成する画面
こんな感じでStatusをクリックすると"draft"と"published"が切り替わるリンクを作成します。
コードはこちらです
今回作成したサンプルアプリケーションは以下のGitHubリポジトリに置いています。
ここを見れば、ViewもControllerもModelもRoutesも全部チェックできます。
アプリの簡単な解説
Migration
statusがenumになるカラムです。
カーディナリティが低く(=データの散らばりが少ない)、インデックスは付けても効果がなさそうなので、付けていません。
class CreateArticles < ActiveRecord::Migration[5.1]
def change
create_table :articles do |t|
t.string :title, null: false
t.text :content, null: false
t.integer :status, null: false, default: 0
t.timestamps
end
end
end
Model
モデルの実装はこんな感じです。
statusを切り替えるためのtoggle_status!
メソッドを用意しました。
class Article < ApplicationRecord
enum status: { draft: 0, published: 1 }
validates :title, :content, :status, presence: true
validates :status, inclusion: { in: Article.statuses.keys }
def toggle_status!
if draft?
published!
else
draft!
end
end
end
Routes
既存のデータを書き換えるので、PATCHでtogle_statusアクションを定義しました。
Rails.application.routes.draw do
resources :articles do
patch :toggle_status
end
end
View
今回はshowの画面でstatusを変更できるようにしました。
link_to
メソッドにmethod: :patch
のオプションが付いている点に注目してください。
<!-- 省略 -->
<p>
<strong>Status:</strong>
<%= link_to @article.status, article_toggle_status_path(@article), method: :patch %>
</p>
<!-- 省略 -->
Controller
Scaffoldで用意されるアクションに加えて、toggle_status
アクションを追加しています。
before_action
に:toggle_status
を追加することと、set_article
メソッドの中で|| params[:article_id]
を追加することも必要になるので注意してください。
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy, :toggle_status]
# 省略
def toggle_status
@article.toggle_status!
redirect_to @article, notice: 'Article was successfully updated.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
@article = Article.find(params[:id] || params[:article_id])
end
# 省略
end
System test
念のため、簡単なテストも書いておきました。
リンクをクリックしたらstatusが切り替わることを検証しています。
require "application_system_test_case"
class ArticlesTest < ApplicationSystemTestCase
test 'toggle status' do
visit article_path(articles(:one))
assert_link 'published'
click_link 'published'
assert_link 'draft'
click_link 'draft'
assert_link 'published'
end
end
まとめ
こんな感じにすると、enumの状態を変更するリンクを作ることができます。
データを変更する場合はGET以外のHTTPメソッドを使う!
これがWebアプリケーションのセオリーですので、あまり意識していなかった人は気をつけるようにしてください。