gakuseis コントローラの作成(1) - 不定期刊 Rails App を作る(24)

RailsApp Rails 2018年 12月 6日

(12/11 修正) 当初書いていた gakuseis_controller での記述だと edit の form_with の記述が Rails 風ではない気がしました. kurasus/gakuseis_controller での記述に修正します.

gakuseis コントローラの追加

  1. generator で kurasus/gakuseis コントローラを作成する.
  2. $ bin/rails g controller kurasus/gakuseis
    Running via Spring preloader in process 27571
          create  app/controllers/kurasus/gakuseis_controller.rb
          invoke  haml
          create    app/views/kurasus/gakuseis
          invoke  rspec
          invoke  assets
          invoke    js
          invoke    css
  3. generator で integration_test を作成する. ただし,kurasus/gakuseis で作成すると,雛形が kurasus_gakuseis というモデルに対するものを作成してしまった. そこで,gakuseis で spec を作成後にフォルダを移動することにする.
  4. $ bin/rails g integration_test gakuseis
    Running via Spring preloader in process 52130
          invoke  rspec
          create    spec/requests/gakuseis_spec.rb
  5. spec/requests の下に kurasus フォルダを作成する.
  6. mkdir -p spec/requests/kurasus
  7. gakuseis_spec.rb を spec/requests/kurasus の下に移動する.
  8. mv spec/requests/gakuseis_spec.rb spec/requests/kurasus
  9. routes に kurasus/gakuseis の項目を追加する.
  10. Rails.application.routes.draw do
      (中略)
      resources :kurasus do
        resources :gakuseis, controller: 'kurasus/gakuseis'
      end
  11. view を修正した時に integration_test が実行されるように Guardfile も修正しておく
  12.   watch(rails.view_dirs)     { |m| [rspec.spec.call("features/#{m[1]}"), rspec.spec.call("requests/#{m[1]}")] }

gakusei_spec の記述(index のみ)

  1. spec/requests/kurasus/gakusei_spec.rb を修正する. ひな形からほぼ自動で作成されるので,index 以外の場所を if false で実行しないようにしておく. kurasus スコープ内の gakuseis コントローラなので,パス名は kurasu_gakuseis_path(kurasu, ...) のようになる. gakuseis の前は kurasu と単数であることに注意する(kurasu を一つ指定しているので単数扱いであるためと思われる). 以下のようなテストができればよい
    • 編集モードでない場合には編集モードに入る画面となる.
    • 編集モードでは学生の一括登録のリンクを表示する.
    • ログインしていない場合には,リダイレクトする(kurasus_controller と同じ).
  2. RSpec.describe :Gakuseis, type: :request do
      include Devise::Test::IntegrationHelpers
      let!(:object) { gakusei_factory :foo2301 }
      let!(:others) { gakusei_factory :bar2302 }
      let(:not_mine) { gakusei_factory :baz3301 }
      let!(:kurasu) { object.kurasu }
    
      let(:return_path) { kurasu_gakuseis_path(kurasu, edit_mode: true) }
      context 'login by hkob' do
        teacher_login :hkob
    
        describe 'GET #index' do
          context 'for my kurasu' do
            context 'normal mode' do
              subject { -> { get kurasu_gakuseis_path(kurasu) } }
              it_behaves_like :response_status_check, 200
              it_behaves_like :response_body_includes, %w[2300 2301 2302 編集モードに入る]
            end
    
            context 'edit mode' do
              subject { -> { get kurasu_gakuseis_path(kurasu, edit_mode: true) } }
              it_behaves_like :response_status_check, 200
              it_behaves_like :response_body_includes, %w[2300 2301 2302 学生の一括登録]
            end
          end
    
          context 'for not my kurasu' do
            subject { -> { get kurasu_gakuseis_path(not_mine) } }
            it_behaves_like :response_status_check, 302
            it_behaves_like :response_body_not_includes, %w[3300 3301 学生の一括登録]
          end
        end
    
        if false
          (中略)
        end
      end
    
      context 'not login' do
        describe 'GET #index' do
          subject { -> { get kurasu_gakuseis_path(kurasu) } }
          it_behaves_like :response_status_check, 302
          it_behaves_like :response_body_not_includes, %w[2300]
        end
      end
    end

kurasus/gakuseis_controller の記述(index のみ)

  1. app/controllers/kurasus/gakuseis_controller.rb を記述する. クラス一覧描画のために @kurasus を取得しているくらいで kurasus_controller とほぼ同様の内容である.
  2. class GakuseisController < ApplicationController
      before_action :authenticate_teacher!
      before_action :get_kurasu
    
      def index
        redirect_to(kurasus_path, alert: t('.not_my_kurasu')) and return if @kurasu.nil?
        @edit_mode = true if params[:edit_mode]
        @kurasus = current_teacher.kurasus.order_name
        @gakuseis = @kurasu.gakuseis.order_number
      end
    
      def get_kurasu
        @kurasu = current_teacher.kurasus.find_by_id(params[:kurasu_id])
      end
      private :get_kurasu
    end

index の view を作成

  1. app/views/gakuseis/index.html.haml を記述する. ほぼ kurasus/index と同じだが,「編集モードに入る」の文字列はどのコントローラでも同じなので,locale の トップレベルに移動した. また,クラスを選択していない場合や,他のクラスを表示したい時のために,下部にクラス移動用のリンクを用意している.
  2. - content_for :title do
      - @title = "#{@kurasu.try(:name)}#{t '.title'}"
    
    %table
      %caption
        - if @edit_mode
          = link_to t('kurasus.gakuseis.new.title'), new_kurasu_gakusei_path(@kurasu)
        - else
          = link_to t('enter_edit_mode'), kurasu_gakuseis_path(@kurasu, edit_mode: true)
      %thead
        %tr
          - t_ars(Gakusei, %i[number name]).each do |w|
            %th= w
          %th= t('control')
      %tbody
        - @gakuseis.each do |g|
          %tr
            %td= g.number
            %td= g.name
            %td
              = link_to t('kurasus.gakuseis.show.title'), kurasu_gakusei_path(@kurasu, g)
              - if @edit_mode
                = link_to t('kurasus.gakuseis.edit.title'), edit_kurasu_gakusei_path(@kurasu, g)
                = link_to t('.destroy'), kurasu_gakusei_path(@kurasu, g), method: :delete, data: {confirm: t('.confirm')}
    
    = t '.select_kurasu'
    %table
      %tbody
        - @kurasus.each do |k|
          %tr
            %td= link_to k.name, kurasu_gakuseis_path(k, edit_mode: @edit_mode.presence)

locale 文字列の用意

  1. view には locale 用のキーワードしか書いていないので,それらの文字列を config/locales/views.ja.yml に追加しておく. すでに kurasus の locale を用意しており,その下に階層的に gakuseis を追加する形になる.
  2. ja:
      (中略)
      control: 制御
      enter_edit_mode: 編集モードに入る
      (中略)
      kurasus:
        gakuseis:
          index:
            title: 学生一覧
            select_kurasu: クラス選択
            destroy: 学生削除
            confirm: 学生を削除してよろしいですか?
            not_my_kurasu: このクラスは担当していません.
          show:
            title: 学生表示
          new:
            title: 学生の一括登録
          edit:
            title: 学生編集

guard の結果

  1. guard の結果は以下のようになった
  2. Gakuseis
      login by hkob
        GET #index
          for my kurasu
            normal mode
              behaves like response_status_check
                response should be 200
              behaves like response_body_includes
                response body includes ["2300", "2301", "2302", "編集モードに入る"]
            edit mode
              behaves like response_status_check
                response should be 200
              behaves like response_body_includes
                response body includes ["2300", "2301", "2302", "学生の一括登録"]
          for not my kurasu
            behaves like response_status_check
              response should be 302
            behaves like response_body_not_includes
              response body does not include ["3300", "3301", "学生の一括登録"]
      not login
        GET #index
          behaves like response_status_check
            response should be 302
          behaves like response_body_not_includes
            response body does not include ["2300"]

長くなったので今日はここまで