プログラミング学習 備忘録

Railsを学習していく上での技術メモ。学んだことや解決したエラーなどを記録していきます。

12/17 今日学んだこと(RSpec復習)

本日からは既存のアプリのエラーをRSpecを書きながら修正していきますので、学んだことを記録していこうと思います。



RSpec

権限の扱い

管理者権限を持つユーザーをFactoryBotで作るときは、無闇にadmin属性を持つユーザーが作られないようにtraitを使うと良い。
デフォルトで作られるユーザーは、一般属性にするべし。

FactoryBot.define do
  factory :user do
    sequence(:name) { |n| "user_#{n}" }
    password { "password" }
    password_confirmation { "password" }
    role { :writer }
    
    trait :admin do
      sequence(:name) { |n| "admin-#{n}" }
      role { :admin }
    end
    trait :editor do
      sequence(:name) { |n| "editor_#{n}" }
      role { :editor }
    end
    trait :writer do
      sequence(:name) { |n| "writer_#{n}" }
      role { :writer }
    end
  end
end



わかりやすく書く

システムスペックファイルの名前は、何のテストか一目でわかるものにする。また、テストコードのdescribeやcontextも具体的に記載する。 また、テストするユーザーの権限に合わせて、letで定義するオブジェクトの名前も変えると良い。

最初のコード

#articles_spec.rb

RSpec.describe "Articles", type: :system do
  describe 'ログイン後' do
    describe '管理者でログイン' do
      let(:user){ FactoryBot.create(:user) }
      before { login_as(user) }
        context '画像が未選択' do
          fit 'プレビューが正しく表示される' do
            visit new_admin_article_path
            fill_in 'タイトル', with: 'title'
            fill_in 'スラッグ', with: 'slag'
            fill_in '概要', with: 'body'
            click_on '登録する'
            click_on 'ブロックを追加する'
            click_on '画像'
            click_on 'プレビュー'
            expect(page).to have_content 'Blog'
            expect(page).to have_content 'title'
          end
        end
    end
  end
end

ファイル名も曖昧だしコードもごちゃごちゃで何をテストしたいかわかりづらい。

理想コード

#admin_articles_previews_spec/rb

RSpec.describe "AdminArticlesPreviews", type: :system do
  let(:admin){ create :user, :admin }
  describe '記事作成画面で画像ブロックを追加' do
    context '画像を選択せずにプレビューを閲覧' do
      fit 'プレビューが正常に表示される' do
        login_as(admin)
        visit new_admin_article_path
        fill_in 'タイトル', with: 'title'
        fill_in 'スラッグ', with: 'slag'
        fill_in '概要', with: 'body'
        click_on '登録する'
        click_on 'ブロックを追加する'
        click_on '画像'
        click_on 'プレビュー'
        expect(page).to have_content 'Blog'
        expect(page).to have_content 'title'
      end
    end
  end
end



エラー集

LoginMacrosが動かない。うまくfill_inできない。

初期データが投入されていないのでそもそもページができていない。 テスト環境にシードデータを入れることで解決

 config.before :suite do
    SeedFu.seed
  end

こうすることでspecを走らせるたびにシードデータが投入されるようになる。

【RSpec】システムスペックを実装してみた②

今回もRSpecのシステムスペックについてです。前回は新規でコードを実装しましたが、今回は既存のコードの修正を行いました。 その過程で学んだことについて記します。



FactoryBotのtraitについて

FactoryBotの以下のコードを使って、taskの編集に関するテストで使用するtaskオブジェクトを定義する場合

FactoryBot.define do
  factory :task do
    association :project
    title { 'Task' }
    status { rand(2) }
    from = Date.parse("2019/08/01")
    to   = Date.parse("2019/12/31")
    deadline { Random.rand(from..to) }
task = FactoryBot.create(:task, project_id: project.id, status: :done, completion_date: Time.current.yesterday)

このようになりだいぶ冗長になってしまう。 そのため、FactoryBotのtrait機能を使ってDRYにする。

FactoryBot.define do
  factory :task do
    association :project
    title { 'Task' }
    status { rand(2) }
    from = Date.parse("2019/08/01")
    to   = Date.parse("2019/12/31")
    deadline { Random.rand(from..to) }

    trait :done do
      status { :done }
      completion_date { Time.current.yesterday }
    end
  end
end
task = FactoryBot.create(:task, :done, project_id: project.id)

このように、引数に:doneと渡してやるだけで実装できる。


別タブに移動した後の動作をテストする場合

windows = page.driver.browser.window_handles
page.driver.browser.switch_to.window(windows.last)

このように書くことで、別タブをスコープにテストを実行できる。
なお、この場合カレントタブは変わらずそのままである。

カレントタブも移動する場合は

switch_to_window(windows.last)

で移動できる。


テストの中でアラートメッセージを押す

削除機能テストなどで、confirmウィンドウを操作したいときは

#承認するとき
page.driver.browser.switch_to.alert.accept

#拒否するとき
page.driver.browser.switch_to.alert.dismiss

で実装できる。

【RSpec】システムスペックを実装してみた

今回はRSpecのシステムスペックを実装しました。
学んだことを簡単に箇条書き。



学んだ事

beforeについて

before do
    visit edit_task_path(task)
end

は、

before { visit edit_task_path(task) }

と1行で書く事ができる。

select_fieldのテスト

select ‘doing’, from: ‘Status’

Statusのラベルをもつselect_fieldから、doingを選んでくれる。

confirmダイアログのテスト

expect(page.accept_confirm).to eq “Are you sure?”

このように書く事で、自動的にOKも押してくれる。

letとlet!の違い

簡単にいうと、letは定義された定数が呼び出されない限り発動しない。 それに対して、let!は常にその定数が発動している状態になる。
そのため・・・

    describe 'タスクの削除', focus: true  do
      let!(:task) { create(:task, user: user) }

      it 'タスクの削除が成功する' do
        visit tasks_path
        click_link 'Destroy'
        expect(page.accept_confirm).to eq "Are you sure?"
        expect(page).to have_content "Task was successfully destroyed."
        expect(current_path).to eq tasks_path
        expect(page).not_to have_content task.title
      end
    end


上のタスク削除のテストは、letだと動作しない!!
(letだと、そもそもtask自体が作られずDestroyへのlinkも作成されず、Unable to find link "Destroy"のエラーが表示される。)

【RSpec】バリデーションテストを実装してみた

掲示板アプリで一通りのことを学んだので、12月からRSpecを学び始めました。
RSpec用のsample_appに、これから色々なテストを実装していきます。
掲示板アプリを作成したときと同様、学んだことやエラーの解決方法を順番に備忘録として残していきます。



バリデーションテストで学んだこと

rails_helperに設定を追加すればFactory_Botの記述を消す事が可能

#spec/rails_hepler内
config.include FactoryBot::Syntax::Methods

・unique属性を持ってるものはsequenceで記述する

#spec/factories/tasks.rb内

FactoryBot.define do
  factory :task do
    association  :user 
# associationの記述だけでuserとの紐付けが完了する

    sequence(:title, "title_1")
#unique属性を持ってるものはsequenceで記述する
#このようにブロックではない第二引数を渡した場合でも、末尾に.nextが呼ばれて末尾の数字が自動的に増えていく。

    content { "count drinks" }
    status { :todo }
# statusなどのenumで別の属性を付与しているものは、文字列ではなくシンボルで記述するとよい。

    deadline { 1.week.from_now }
# deadlineなどは、時間を決め打ちするのではなく相対表記にする。
# 決め打ちしていると、将来的に過去の時間になってしまう。

  end
end

sequence(:title, “title_1”)といった感じでブロックを渡さずに第二引数を渡すと、 .next が呼ばれる。つまり末尾の数字が増えていく。

・statusなどのenumで別の属性を付与しているものは、文字列ではなくシンボルで記述するとよい。

・deadlineは相対表現にする。時間を決め打ちしてしまうと時間が経った後にテスト結果が変わってしまう。(将来的に過去の日付になってしまう)

・バリデーションテスト時の変数は、一目で何のテスト用かわかるようにする bad: task good: task_without_title

・バリデーションのテストコードは、基本buildでかく。createだとデータベースに保存を試みてしまうので、テスト用の欠陥データがバリデーションに引っかかってテストすらできない。

#spec/models/task_spec.rb内

it 'is invalid with a duplicate title' do
    task = create(:task)
# まずはcreateで最初のデータをデータベースに保存している

    task_with_duplicate_title = build(:task, title: task.title)
    expect(task_with_duplicate_title).to be_invalid
# be_invalidのテストコードを書かないとエラーが起こる

    expect(task_with_duplicate_title.errors[:title]).to eq ["has already been taken"]
  end

例外処理とSlack通知の実装

掲示アプリ制作の締め括りに、例外処理及び500エラーが出た際にSlackに通知が飛ぶようにしました。 実装を通して学んだことを記します。

参考にさせていただいた記事
slack-notifierでrailsからSlackへ簡単にメッセージを送る - Qiita
【Rails】500番エラーをslack通知する - Qiita
Railsアプリの例外ハンドリングとエラーページの表示についてまとめてみた - Qiita



学んだ事

Credentialsについて

Rails5.2から追加された機密情報を保持する仕組み。 Credential.yml.encという秘匿情報を記録するファイルと、 Master.keyという秘匿情報を閲覧したり、編集したりするための鍵となるファイルが要

$ EDITOR='vi' bundle exec rails credentials:editコマンドでmaster.keyを使ってviでcredential.yml.encを開く事ができる。

参考にさせていただいた記事
credentials.ymlの書き方 - annzuwatanuki’s diary
Railscredentials.yml.encについてまとめる - Qiita


開発環境でエラーを表示させる

開発環境ではデフォルトではそのままのエラー文が表示されている config/environments/development.rb内のconfig.consider_all_requests_local: truefalseに変える事で本番環境用のエラーviewを表示できるようになる。

エラーの継承関係

エラーにも継承関係が存在し、exceptionが全ての親クラスである。

アプリケーション全体にエラーを適用したいときは、rescue_fromメソッドを使う。

# application_controller内

  unless Rails.env.development?
    rescue_from Exception, with: :error_500
    rescue_from ActiveRecord::RecordNotFound, with: :error_404
  end

  def error_404
    render file: Rails.root.join('public', '404.html'),
           layout: false, status: :not_found
  end

  def error_500(error)
    logger.error error
    logger.error error.backtrace.join("\n\n")
    render file: Rails.root.join('public', '500.html'),
           layout: false, status: :internal_server_error
  end

このとき、rescue_fromは必ず親クラスから記載する。これは、例外処理の際に下のコードから順に読み込むためであり、親クラスの例外処理であるrescue_from Exception, with: :error_500を下に書いてしまうと全てerror_500として処理されてしまうため。

#この書き方でも同じように実装できる
def error_404
    render file: Rails.root.join('public', '404.html'),
           layout: false, status: :not_found
  end

 def error_500(error)
    logger.error error
    logger.error error.backtrace.join("\n\n")
    render file: Rails.root.join('public', '500.html'),
           layout: false, status: :internal_server_error
  end

ルーティングの記載

404_errorと500_errorのviewを表示させるためにルーティングを書く必要がある。このとき、必ずroutesの一番下に書く事!!
上の方に書いてしまうとほとんど全てのページで404エラーや500エラーが表示されてしまう。

#routes.rb内
.
.
.
 get '*path', to: 'application#error_404'
 get '*path', to: 'application#error_500'

エラー解決

存在しないページのURLに飛んだ際に、本来404_errorにならないといけないのに500_errorが表示されてしまうエラーが発生

アクセスしたページは、localhost:3000/boards/1000 config.consider_all_requests_local: trueに戻してエラー内容を見てみるとNo_method_errorになっている。

NoMethodError in BoardsController#show
undefined method `comments' for nil:NilClass

404エラーにするためには、ActiveRecord::RecordNotFoundにしないといけない。
これはどうやら、 @board = Board.find_by(params[:id])でfind_byメソッドを使っていた事が原因らしい。
find_byはidが存在しない場合はnilを返すため、@boardがnilになってしまっていたらしい。 @board = Board.find(params[:id])に変更する事で無事ActiveRecord::RecordNotFoundを表示させる事ができた。


Railsチュートリアルの時からnilの概念と重要性について聞いてはいたが、結局はうまく動くか動かないかの2つだと考えていたのであまり気にした事がなかった。 今回の例外処理の実装を通してようやく点と点が繋がった。

Admin-LTE3を使用した管理画面の実装③(掲示板/ユーザーのCRUD)

前回に続いて、Admin-LTE3を使った管理画面の実装を進めていきました。 その中で学んだ事をまとめました。



enum_helpを使用したプルダウンのセレクトボックスの実装

セレクトボックスの実装で少し詰まったので、色々な記事を参考にして自分なりに解釈し、わかりやすくまとめてみた。

#権限選択画面のコード
<%= f.select :role_eq, User.roles_i18n.invert.map{|key, value| [key, User.roles[value]]}, { include_blank: t(‘defaults.unspecified’) }, { class: ‘form-control mr-1’ } %>

User.roles_i18n.invert.map{|key, value| [key, User.roles[value]]}の部分が非常にややこしいので順に読み解いていく。

まずはenum_helpを使って日本語化する前のコード

<%= f.select :role_eq, User.roles.values %>
#rails console内
User.roles
=> {"general"=>0, "admin"=>1}

User.roles.values
=> [0, 1]

User.roles.valuesにより、roleカラムの値を配列として取得できる。 これを、enum_helpを使用しi18nで日本語化する。

#rails.console内
User.roles_i18n
=> {"general"=>"一般", "admin"=>"管理者"}

User.roles_i18n.values
=> ["一般", "管理者"]
# admin/users/index.html.erb内
<%= search_form_for(@q, url: admin_users_path, method: :get) do |f| %>
  <div class="input-group mb-3">
      <%= f.label :role_eq, '権限' %>
      <%= f.select :role_eq, User.roles_i18n.values, include_blank: '指定なし' %>
  </div>
<% end %>

しかし、このコードだと発行されるSQLが常に”role” = 0となってしまい正常に動作しない。

Processing by Admin::UsersController#index as HTML
  Parameters: {"utf8"=>"✓", "q"=>{"first_name_or_last_name_cont"=>"","role_eq"=>"管理者"}, "commit"=>"検索"}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 8], ["LIMIT", 1]]
  ↳ vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
  Rendering admin/users/index.html.erb within layouts/admin_application
  User Load (0.3ms)  SELECT DISTINCT "users".* FROM "users" WHERE "users"."role" = 0 ORDER BY "users"."created_at" DESC
  ↳ app/views/admin/users/index.html.erb:23

どうやらこれは、ransackがそもそもenumに対応していない事が原因で、status_idが常に0になってしまうというバグらしい。

参考記事
RansackはRailsのenumに対応していないっぽい | 地方でリモートワーク

そこで、invertメソッドとmapメソッドを組み合わせてstatus_idを正しく取得できるようにする。

Invertメソッドとmapメソッドの挙動について

#rails.console内
User.roles_i18n
=> {"general"=>"一般", "admin"=>"管理者"}

User.roles_i18n.invert
=> {"一般"=>"general", "管理者"=>"admin"}

User.roles_i18n.invert.map{|key,value| [key, User.roles[value]]}
=> [["一般", 0], ["管理者", 1]]

3つ目の挙動が少し難しいかもしれないが、これは、 “一般” “管理者”というキーが key に、”general” “admin”という値が valueにそれぞれ代入され、mapメソッドによってそれぞれに対して処理が行われている。

参考記事
ハッシュのキー、値の配列を取得する (keys, values) | まくまくRubyノート

#rails.console内
User.roles["general"]
=> 0

User.roles["admin"]
=> 1

この結果、一般タブが選択されるとvalue=“0”が、管理者タブが選択されるとvalue="1"が選択されるようになり、正常に動作するようになった。

#発行されているhtml

<select name="q[role_eq]" id="q_role_eq"><option value="">指定なし</option>
<option value="0">一般</option>
<option value="1">管理者</option></select>



ransackのカスタムpredicateについて

Ransackでは様々な検索機能がある。また、検索に使うpredicate(デフォルトで用意されている検索用のメソッドのようなもの)は、カスタムすることも可能である。 今回の日付範囲検索は、デフォルトpredicateのcreated_at_lteqだと、0:00までとなってしまい、正しく検索する事ができないので、created_at_lteq_end_of_dayというカスタムpredicateを作る必要がある。

Config/initializerに、ransack.rbというファイルを作って以下のコードを記述する

# config/initializers/ransack.rb
Ransack.configure do |config|
  config.add_predicate ‘lteq_end_of_day’,
                       arel_predicate: ‘lteq’,
                       formatter: proc { |v| v.end_of_day }
end

arel_predicate: ‘lteq’でカスタマイズしたいpredicateを指定し、 formatter: proc { |v| v.end_of_day }の箇所で、23:59:59までを指定している。

class=“active”を動的にして、サイドバーのアクティブ機能を実装する

Admin/boardsコントローラーのアクションが実行されているときは、「掲示板一覧」が、Admin/usersコントローラーのアクションが実行されているときは「ユーザー一覧」がアクティブになるようにする。

Application.helerにこのように記述し、

タグの中に組み込む。 当初の自分のコード

  def active?(controller_name)
    return 'active' if controller_name == params[:controller]
  end

これはあまり綺麗ではない。三項演算子を使って、else時の返り値も明示してあげた方が良い。

修正後のコード

def active_if(path)
  path == controller_path ? 'active' : ''
end
# _sidebar.html.erb内
<%= link_to admin_boards_path, class: "nav-link #{active_if('admin/boards')}" do %>

Admin-LTE3を使用した管理画面の実装②(新しい知識と学んだ事)

今回の実装を通して学んだことをまとめていきます



◆Userに権限を付与する

一般ユーザーと管理者ユーザーを分けるために、Usersテーブルに、roleという名前のカラムを作成する。(名前はわかればなんでもおk)

データ型はintegerにして、enumオプションを使用し「0: 一般、1: 管理者」という風に別名をつける。

#migrationファイル内
class AddRoleToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :role, :integer, default: 0, null: false, limit: 1
#defaultを一般ユーザーの0に設定し、limitを1にすることで、ユーザーは0 or 1の2種類に振り分けられる。
  end
end
#User.rb内
  enum role: 
  {
    general: 0,
    admin: 1
  }
#enumオプションを使うことで、0,1という数字の代わりにgeneralとadminという属性をUserに持たせる事ができる。
end




◆管理画面用のコントローラーを作成する

Admin関連のコントローラーは、admin/というディレクトリで一括管理した方が保守性が高いため、adminというnamespaceで区切ってコントローラーを作成するとよい。

rails g controller admin/base
rails g controller admin/user_sessions
rails g controller admin/dashboards

また、admin/user_sessionsコントローラーと、admin/dashboardsコントローラーはadmin/baseコントローラーを継承するように設定する。
こうすることで、admin関連のページ全体で使用したいメソッドやbefore_actionなどをbaseコントローラーに定義することで全てのコントローラーに適用されるようになる。

class Admin::UserSessionsController < Admin::BaseController
class Admin::DashboardsController < Admin::BaseController 




◆namespaceを使ったURL設定

URLもコントローラー同様、adminというネームスペースを使用して一般画面とは切り離すと良い。

ネームスペースを使用することで普通にルーティングしたときと比べてどのような違いがあるのかについては、こちらのQiita記事を参考にさせていただきました。
Railsのroutingにおけるscope / namespace / module の違い - Qiita

  namespace :admin do
    get '/login', to: 'user_sessions#new'
    post '/login', to: 'user_sessions#create'
    delete '/logout', to: 'user_sessions#destroy'
    root 'dashboards#index'
  end

こうすることで、ルーティングが以下のようになり、path,URL,コントローラー全てをadminというネームスペースで切り分ける事ができる。

            admin_login GET    /admin/login(.:format)                                                                   admin/user_sessions#new
                          POST   /admin/login(.:format)                                                                   admin/user_sessions#create
             admin_logout DELETE /admin/logout(.:format)                                                                  admin/user_sessions#destroy
               admin_root GET    /admin(.:format)                                                                         admin/dashboards#index

URLもコントローラー同様、adminというネームスペースを使用して一般画面とは切り離すと良い。

ネームスペースについてはこちらのQiita記事を参考にさせていただきました。 Railsのroutingにおけるscope / namespace / module の違い - Qiita

  namespace :admin do
    get '/login', to: 'user_sessions#new'
    post '/login', to: 'user_sessions#create'
    delete '/logout', to: 'user_sessions#destroy'
    root 'dashboards#index'
  end

こうすることで、ルーティングが以下のようになり、path,URL,コントローラー全てをadminというネームスペースで切り分ける事ができる。

            admin_login GET    /admin/login(.:format)                                                                   admin/user_sessions#new
                          POST   /admin/login(.:format)                                                                   admin/user_sessions#create
             admin_logout DELETE /admin/logout(.:format)                                                                  admin/user_sessions#destroy
               admin_root GET    /admin(.:format)                                                                         admin/dashboards#index

URLもコントローラー同様、adminというネームスペースを使用して一般画面とは切り離すと良い。

ネームスペースについてはこちらのQiita記事を参考にさせていただきました。 Railsのroutingにおけるscope / namespace / module の違い - Qiita

  namespace :admin do
    get '/login', to: 'user_sessions#new'
    post '/login', to: 'user_sessions#create'
    delete '/logout', to: 'user_sessions#destroy'
    root 'dashboards#index'
  end

こうすることで、ルーティングが以下のようになり、path,URL,コントローラー全てをadminというネームスペースで切り分ける事ができる。

            admin_login GET    /admin/login(.:format)                                                                   admin/user_sessions#new
                          POST   /admin/login(.:format)                                                                   admin/user_sessions#create
             admin_logout DELETE /admin/logout(.:format)                                                                  admin/user_sessions#destroy
               admin_root GET    /admin(.:format)                                                                         admin/dashboards#index

URLもコントローラー同様、adminというネームスペースを使用して一般画面とは切り離すと良い。

ネームスペースについてはこちらのQiita記事を参考にさせていただきました。 Railsのroutingにおけるscope / namespace / module の違い - Qiita

  namespace :admin do
    get '/login', to: 'user_sessions#new'
    post '/login', to: 'user_sessions#create'
    delete '/logout', to: 'user_sessions#destroy'
    root 'dashboards#index'
  end

こうすることで、ルーティングが以下のようになり、path,URL,コントローラー全てをadminというネームスペースで切り分ける事ができる。

            admin_login GET    /admin/login(.:format)                                                                   admin/user_sessions#new
                          POST   /admin/login(.:format)                                                                   admin/user_sessions#create
             admin_logout DELETE /admin/logout(.:format)                                                                  admin/user_sessions#destroy
               admin_root GET    /admin(.:format)                                                                         admin/dashboards#index




◆User_sessionsコントローラーの書き方

最初はcreateアクションをこのようにコーディングしていた。

  def create
    @user = login(params[:email], params[:password])

    if @user.present? && @user.admin?
      flash[:success] = 'ログインしました'
      redirect_to admin_root_path
    elsif @user.present? && @user.general?
      flash[:danger] = '権限がありません'
      redirect_to root_path
    else
      flash[:danger] = 'ログインに失敗しました'
      redirect_to admin_login_path
    end
  end

elsifを使っているので条件分岐が3つになり、コードが少々冗長になっている。
しかし、実際には管理画面全体をAdminオンリーで制限をかけるので、AdminかGeneralかの判定はBase_controllerのbefore_actionで定義した方が良い。

修正後のコードがこちら

class Admin::BaseController < ApplicationController
  before_action :check_admin
  layout 'layouts/admin_application'

# layoutで、admin_applicationを明示的に指定する事で、管理画面全体にadmin_application.html.erbがデフォルトで適用される。

  private

  def not_authenticated
    flash[:warning] = t('defaults.message.require_login')
    redirect_to admin_login_path
  end

  def check_admin
    redirect_to root_path, warning: t('defaults.message.not_authorized') unless current_user.admin?
  end
end
class Admin::UserSessionsController < Admin::BaseController
  skip_before_action :check_admin, only: %I[new create]
  skip_before_action :require_login, only: %I[new create]
  layout 'layouts/admin_login', layout: false

# ログインページのみ、ヘッダーやフッター、サイドバーのないシンプルなフォームにするためlayout: falseでadmin_application.html.erbが適用されないように設定している。
  
def new; end

  def create
    @user = login(params[:email], params[:password])
    if @user
      redirect_to admin_root_path, success: t(‘.success’)
    else
      flash.now[:danger] = t(‘.fail’)
      render :new
    end
  end

  def destroy
    logout
    redirect_to admin_login_path, success: t(‘.success’)
  end
end




◆知識


admin_login.html.erb内に<%= csrf_meta_tags %>の記述がないとInvalid Authentication Tokenエラーが出る。

同様に、admin_application.html.erb内に<%= csrf_meta_tags %>の記述がないと、destroyアクションが正しく機能しない。

Rails-ujsをマニフェストファイルで読み込んでいないと、postリクエストやdeleteリクエストが正しく動作せず、全てgetリクエストになってしまう。

Rails-ujsの役割については下記の記事を参考にさせていただきました
Rails学習者にrails-ujsの動作説明したら感動された話 - INODEVLOG