Help us understand the problem. What is going on with this article?

【動画付き】Railsでenumの状態を変更するリンクの作り方

More than 1 year has passed since last update.

はじめに

Qiitaを見ているとこちらの記事が目に入りました。

本当の初心者のためのenumを使った状態管理(クリック一つで状態変遷させるやつ)の実装 rails - Qiita

「ふんふん、なるほど~」と思いながら読んでいたら、GETでデータを変更しようとしていることに気づきました。

データを変更するのであれば、GET以外のHTTPメソッド(POST、PATCH、PUT、DELETE)を使う方がWebアプリケーションとして適切です。

最初は「GETを使わない方がいいですよ~」とコメントして終わろうかと思ったのですが、記事の最後の方に「初心者はview controller model route 全て具体例がないと実装できません(泣)」と書いてあります。

たしかに。
上級者なら自力で埋められる情報の溝(不足している情報)も、初心者の人にとってはなかなか乗り越えるのが難しかったりします。

それならば、ということで「こうやれば実装できますよ」というのをrails newするところから動画に撮って説明してみようと思いました。

この記事ではその動画のポイントを説明していきます。

動画はこちらです

サンプルアプリケーションを作成する様子はこちらに載せています。

Railsでenumの状態を変更するリンクの作り方 - YouTubeScreen Shot 2017-09-27 at 8.50.11.png

良くも悪くもノーカットです:droplet:

ちなみに、完全ノーカットでトータル36分あります。
最初は10分ぐらいあればできるでしょー、と高をくくっていたんですが、途中でenumを使ったフォームの作り方で試行錯誤してしまい、時間を食ってしまいました。
(言い訳すると、僕は普段enumerize gemを使うことが多く、Rails標準のenumは使ったことがないんですよね。。)

試行錯誤の時間が結構長いので、さっさと先に進みたい方は11:30~19:50のあたりをスキップしてください。

あと、どっちみち長いので動画は1.5倍速ぐらいで見た方が良いと思います。

RubyMineを使ってます!

動画の中ではRubyMineを使って開発しています。
RubyMineを使ったRails開発に興味がある人も参考にしてみてください。

今回作成する画面

こんな感じでStatusをクリックすると"draft"と"published"が切り替わるリンクを作成します。

7UM4exZ64a.gif

コードはこちらです

今回作成したサンプルアプリケーションは以下のGitHubリポジトリに置いています。

https://github.com/JunichiIto/enum-sandbox

ここを見れば、ViewもControllerもModelもRoutesも全部チェックできます。

アプリの簡単な解説

Migration

statusがenumになるカラムです。
カーディナリティが低く(=データの散らばりが少ない)、インデックスは付けても効果がなさそうなので、付けていません。

db/migrate/20170926222713_create_articles.rb
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!メソッドを用意しました。

app/models/article.rb
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アクションを定義しました。

config/routes.rb
Rails.application.routes.draw do
  resources :articles do
    patch :toggle_status
  end
end

View

今回はshowの画面でstatusを変更できるようにしました。
link_toメソッドにmethod: :patchのオプションが付いている点に注目してください。

app/views/articles/show.html.erb
<!-- 省略 -->

<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が切り替わることを検証しています。

test/system/articles_test.rb
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アプリケーションのセオリーですので、あまり意識していなかった人は気をつけるようにしてください。

jnchito
SIer、社内SEを経て、ソニックガーデンに合流したプログラマ。 「プロを目指す人のためのRuby入門」の著者。 http://gihyo.jp/book/2017/978-4-7741-9397-7 および「Everyday Rails - RSpecによるRailsテスト入門」の翻訳者。 https://leanpub.com/everydayrailsrspec-jp
https://blog.jnito.com/
sonicgarden
「お客様に無駄遣いをさせない受託開発」と「習慣を変えるソフトウェアのサービス」に取り組んでいるソフトウェア企業
http://www.sonicgarden.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした