404、500エラー発生時のSlack通知
どうもどハマりエンジニアです。
目的
slack-notifier
exception_notification
上記の2つのgemを追加・適切な記述をし、Slackの該当チャンネルに通知できるようにします。Slackの通知設定でWebhookURLに指定するURL情報は、credentials(日本語だと信任状)を使って設定してください。通知確認後は、production環境のみで通知がいくようにします。
404エラーに関してはエラーハンドリング処理を実装し、public/404.htmlを表示させ、500エラーに関してはエラーハンドリング処理を実装し、ログに「エラーメッセージ」と「エラーのバックトレース」を出力させ、public/500.htmlを表示させます。
gemのインストール
$slack-notifier
&exception_notification ←なんかしらのエラーが発生すると、メールを自動的に送付してくれる gem
gemfileに上記を記載し$bundle install
slackのwebhook_urlを取得
https://任意のslackワークスペース名.slack.com/services/new
でアクセス- 検索フィールドから
Incoming WebHooks
を検索 Slackに追加
をクリックして通知したいチャンネル名を選択して保存- webhook_URLをコピー
通知設定
$ bundle exec rails g exception_notification:install
exception_notification.rb
env.production?のところで、エラーが発生した際にどの環境でエラーをslack に送るか設定します。確認の段階だけdevelopmentにします。
webhook_url と channel では、さきほど取得したurlとチャンネル名を記載します。
コントローラーでのrescue_formによるエラー補足
application_controller.rb
動的なエラーページを表示する方法としては、おそらくApplicationController
で下記のようにするのが最もポピュラーで手軽な方法です。ここで例外が発生した際にrenderさせる設定を記載します。
<注意>
明示的にrescue_from ActiveRecord::RecordNotFound, with: :render_404
のように例外を捕捉した場合はconsider_all_requests_local
の設定にかかわらず必ずwith:
の後のメソッドが呼ばれます。
その中のメソッドでは render file: Rails.root.join('public/404.html'), layout: false, status: :not_found
と記述しているので何が何でも404.htmlが表示されます。
ですので unless Rails.env.development? と記載し、開発環境意外でrenderさせるようにします。でないと、開発環境でなんのエラーが出ているのか分からなくなってしまいます。
あとは404.html、500.htmlを設定すれば完了です。
後rescue_from
で補足しているエラーはSlack通知がいかないので気をつけましょう。
掲示板/ユーザのCRUD機能の作成(管理者画面)
どうもどハマりエンジニアです。
本日は前回の引き続きで、管理者画面の掲示板及びユーザーのCRUD機能を作成していきます。
ユーザーと掲示板のコントローラー作成
$rails g controller admin::users
$rails g controller admin::boards
コントローラーは普通のCRUD機能ですので、一般での時と同じように作成します。
admin/user_controller.rb
admin/boards_controller.rb
ルーティングの設定
routes.rb
ビューの作成及び検索機能(日付)の設定等
まず、ユーザー一覧に管理者で検索できるようにしていきます。
admin/users/index.html.erb (検索部分のみ)
f.selectは、
<%= f.select 属性, 選択肢の集合, {オプション}, {HTMLオプション} %>
と書くか、あるいは、
<%= f.select( 属性, 選択肢の集合, {オプション}, {HTMLオプション} ) %>
と括弧を使って書きます。
オプションは、
{ include_blank: '指定なし' }
のようにします。この例では、何も選択されていない時は、 ‘指定なし’ という項目が選択されるという定義です。セレクトボックスの1番目の選択肢に’指定なし’ が追加されます。
ransackを使うとboardsテーブルに対して:title_eqと記述するだけでSQLを内部で走らせてくれます。
上記のeqの部分をPredicateと呼び、Predicateを変更することで様々な条件のデータを検索することができます。
User.roles_i18n.invert.map i18nを使えば、選択部分を日本語に変えることができます。inverでkeyとvalueの関係を逆にして、mapで表示させる設定をしています。例えば、コンソールを開いて下記を実行します。そうするとkeyがgeneral、valueが一般になっています。なので表示させたいのは一般なので、invertを使い反転させます。あとは、mapをつかい、表示の設定をしてあげます。
irb(main):001:0> User.roles_i18n
=> {"general"=>"一般", "admin"=>"管理者"}
views/ja.yml
i18nでは上記のように記載してあげます。
以上で管理者権限での検索が可能になります。
<参考記事>
https://310nae.com/rails-selectbox/
次に掲示板一覧にて日付で検索をできるようにしていきます。
admin/boards.index.html.erb(検索機能のみ)
ransackで oooo/oo/oo から xxxx/xx/xx までというふうに日付検索ができるようにしていたのですが、そのままだと xxxx/xx/xx の部分の時間が00:00:00となってしまう事で、指定した日付の前日までのデータしか取得できませんでした。
日付の検索についてはいつからいつまでといった感じにするためにransackをカスタマイズする必要があります。そのためransack.rbというファイルを作り、そこに設定を加えていきます。ちなみにgteq(以上)、lteq(以下)というpredicate(述語)でransackをインストールすることで使えるものです。
config/initializers/ransack.rb
これできちんと指定した日付のデータも検索結果に含まれるようになりました!
SQLを確認してみてもきちんと 2019-03-01 00:00:00 から 2019-03-01 23:59:59.999999 までというようにデータを検索してくれております。
これで日付での検索機能は完了です!
掲示板のメニューをアクティブに
どいうことかというと、例えば掲示板一覧にいるときは、メニューのボタンの色をかえるということ。これは直接ビューに書き込んでもいいのですが、ヘルパーに書き込んだ方が便利なので、今回はヘルパー に記載していきます。
app/helpers/application_helper.rb
admin/shared/_sidebar.html.erb
へるぱーで定義したメソッドをつかえば、これだけで掲示板メニューをアクティブにすることができます。
以上で、おおまかな掲示板/ユーザのCRUD機能の作成(管理者画面)の説明を終わります。
AdminLTE 3を使って簡単な管理者ページを実装
どうもどハマりエンジニアです。
本日は管理画面へのログイン機能、管理画面トップページの作成 を作成していきます。
AdminLTE3のインストール
まず今回はyarnを使ってAdminLTEをインストールしていきます。
yarnとはJavaScriptのパッケージマネージャーのことで、yarnとnpmの2種類ありますが、今回はyarnを使っていきます。
$yarn add admin-lte
これでこれでnode_modules
とpackage.json
とyarn.lock
というファイルがインストールされます。 node_modules/admin-lteディレクトリにデフォルトテンプレートが記載されているので今回はその中のstarter.html
とlogin.htmlを使っていきます。
管理者ページ用のマニフェストファイルを作成
今回は一般ページと管理者ページでは見た目が大きく変わってくるので、一般ページと分けて管理者ページ専用のマニフェストファイルを作成していきます。なので一般ページはjacascripts/application.js、管理者ページはjavascripts/admin.jsに記載していくことになります。管理者ページではしっかりとjquery3やrails-ujsを指定しないとlink_toのヘルパーメソッドのルーティンでdeleteメソッドを指定出来ないなどの問題が起きてしまいます。
app/assets/javascripts/admin.js
このままだと一般ページにもadmin.jsが読み込まれてしまいます。require=treeがjavascriptディレクトリ階層全てのファイルを読み込むので、個別に記載していく必要があります。
app/assets/javascripts/application.js
これはコメント編集の時に使ったjsです。require=treeを消して個別に書いていきます。
app/assets/stylesheets/admin.scss
ここには、starter.htmlにlinkでここのcssを使用してあると記載してあるので、こちらで専用にimportしてあげる必要があります。
マニフェストファイルの読み込み設定
プリコンパイルの設定をします。application以外のマニフェストファイルを個別に読み込みたい場合はプリコンパイルの設定をしないとそのファイルは対象外とされてしまうためエラーが起きてしまいます。
config/initializars/assets.rb
Userモデルに管理者かどうか判別させるためのroleカラム を追加
$rails g migration AddRoleToUsers role:integer
一般権限となるdefaultは0としてAdmin権限は1とします。
$rails db:migrate
enumの追加をする。enumとはモデルの数値カラムに対して文字列の名前を定義することができます。 今回は一般管理者をgeneral、管理者権限をadminとして定義していきます。
user.rb
管理者用のコントローラーを作成
$rails g controller admin::base
こうすることでcontorollersの中にadmminディレクトリが作成され、そのなかに新たなコントローラーが作成されます。base_controllerには、application_controller.rbのように、管理者のためのコントローラの基盤となる処理を実装していきます。なので、admin以下のコントローラーは全てbaseコントローラーが継承される記載をしていく必要があります。
admin/base_controller.rb
layoutで読み込みたいレイアウトを指定します。この作業はレイアウトは後ほど作成します。 check_adminメソッドでadmin権限でない場合はトップページに遷移させるようにします。
$rails g controller admin::dashboards
$rails g controller admin::user_sessions
admin/user_sessions_controller.rb
classはbase_contoroller.rbから継承されるように書き直します。ログインのフォーマットは特別にlayoutを変えます。node_modules/admin-lte/dist/pages/examplesにあるlogin.htmlを参考に新たにフォーマットを作成します。
admin/dashboards.rb
ルーティングの設定
routes.rb
今回は/adminから始まるURLにしたいので、namespaceを使っていきます。これを使うと一般ページと分けて管理することが出来ます。
rootの設定のところでas: :rootを付けないとエラーが出てくるのでつけるようにします。
ビューの設定
admin/layoutディレクトリを作成して、その中にapplication.html.erbとadmin_login.html.erbを作成していきます。
view/admin/layout/application.html.erb
view/admin/layout/admin_login.html.erb
admin/shared配下にてヘッダー、フッター、サイドバーのパーシャルの作成とログイン画面とトップページの作成をしていきます。(ここは省略)
application/helper.rb
管理者ログイン用のアカウントを作成
以上で完成になります。
sorceryのreset_passwordモジュールを使用したパスワードリセット機能
どうもどハマりエンジニアです。
本日はパスワードのリセット機能について実装していきます。
使う概念
- soceryのreset_passwordモジュール
- letter_opener_web
- config
sorceryのreset_passwowrdモジュールをインストールする
$rails g sorcery:install reset_password --only-submodules
そうすると上記のmigrationが作成されます。
rails db:migrate 実行
Mailerの作成
$rails g mailer UserMailer reset_password_email
(user_mailer.rb)
- default from: 'from@example.com'でメールの送信元のアドレスを指定できる
- mail(to: user.email,subject: 'パスワードリセット')でメールの宛先、件名を指定
(sorcery.rb)
sorcery.rbにreset_passwordサブモジュールを追加し、パスワードリセットに使用するActionMailerとしてUserMailerを定義
コントローラー・ビューの作成
$rails g controller password_resets
(password_resets_controller.rb)
create()では送信されてきたメールに対応するUserを検索し、「deliver_reset_password_instructions!」を呼び出すことでトークンの発行とメール送信を行っています。
edit()はトークンの存在チェックです。
update()では「change_password!」を呼び出してパスワードの変更を行っています。APIであるため、それぞれのアクションではHTTPステータスコードを状態に応じて返しています。
(routes.rb) ルーティングの設定
(new.html.erb)リセット申請画面
(edit.html.erb)リセット編集画面
メール文作成
(reset_password_email.html.erb)
@urlは先ほどmailer.rbで作成
(reset_password_email.text.erb)
letter_opener_webを追加し、開発環境では実際のメールは送られないように設定
下記のgemをインストールする
'letter_opener_web'
(routes.rb)設定を加える
configのgemを追加
rails g config:install
config/settings.yml
config/settings.local.yml
config/settings/development.yml
config/settings/production.yml
config/settings/test.yml
上記のファイルが作成されるので、各ファイルに必要な記述をしていきます。
(config/environments/development.rb)
(settings/development.yml)
上記でパスワードリセットの実装は完了です。
実際にパスワードのリセットを申請すると、http://localhost:3000/letter_opener にメールが届くので確認してください。
以上で本日の実装は終了です。
ransackを使った検索機能の実装
どうもどハマりエンジニアです
gemの導入
gem 'ransack' → $bundle install
要件
検索フォームのテンプレートを作成
(boards/index.html.erb)
- viewからsearch_form_forへ検索ワード入力してEnterを押すと、指定したpathへ送信
- bords_controllerのindexアクションへ送信して検索する
:title_or_body_cont
が検索条件を指定している部分で、マッチャーと呼ばれ、gemでいくつもの種類が用意されている。今回は一部分でも文字が含まれている場合はヒットさせたいので、contを使用している。
controllerを実装
(boards_controller)
- フォームから飛んできたデータをparams[:q]で受けて、@searchへ代入(ransackの仕様上、検索パラメータはqを付けて飛ばすようになっている)
- @searchオブジェクトに対して、resultメソッドで検索結果を表示
- 通常indexページは@boards = Board.all.includes(:user).page(params[:page])などと書いていることが多いが、こちら記載は不要になる。
以上で掲示板一覧の検索機能は完成!
ブックマーク一覧での検索
こちらも掲示板一覧とほぼ同じであるが、ここではブックマークをしている掲示板の中から検索したい。
(bookmarks.html.erb)
ここではurlを指定してあげ、boards_controllerのbookmarksアクションにいくようにする。それ以外は同じ!
(boards_controller.rb)
ブックマークした掲示板のなかからデータをもってきたいので、@searchはcurrent_user.bookmark_boardsのなかから検索するようにする。
掲示板一覧と同様に最初に記入してあった「
」
この部分は不要になる。
以上でブックマーク一覧の検索も完了!
これ以外にも様々な検索が可能なので、場面に応じて適図使用を変えなければいなけい。
掲示板のページネーション
どうもどハマりエンジニアです。
今回は掲示板の下部にページネーションを付け加える実装を行っていきます。
①gem 'kaminari' → bundle install
②rails g kaminari:config
ここで設定等を決めることができるファイルが作成させます
③rails g kaminari:views bootstrap4
見た目をよくするためにbootstrapを使いいます
これだけで見た目がよくなります
<kaminari_config.rb>
ここで表示される数の上限を決めます。
<boards_controller.rb>
.page(params[:page])を加える。
<bookmarks.html.erb>
あとは好きなとろこに差し込むだけです!
以上で簡単にページネーションを実装することができました。
さらにカスタム等したい場合は、下記のサイトを参考にすると良いと思います!
https://qiita.com/rio_threehouse/items/313824b90a31268b0074
コメント(編集)のAjax化について
どうもどハマりエンジニアです。
今回はコメント(編集)のAjax化について行っていきます。
流れとして下記の4つを実装していきます。
機能を四つに分けて実装していきます。
1. 編集ボタンクリックでラベル非表示、コメントエリアとボタン表示
2. キャンセルボタンクリックでラベル表示、コメントエリアとボタン非表示
3. 更新ボタンクリック成功でDB更新、ラベル表示、コメントエリアとボタン非表示
4. 更新ボタンクリック失敗でエラーメッセージ表示
そもそもrailsに渡していた投稿内容の情報をjavascriptにどうやって渡すのか?
railsで定義した変数をJavaScriptに渡すためにはjson形式に変換して渡す必要があります。
まずは、編集ボタンクリックでラベル非表示、コメントエリアとボタンの表示とその逆の実装をしていく。
(comments/_comment.html.erb)
class="js-button-comment-update" → jsに使う
data-comment-id → dataは属性として使う。また一つ一つにコメントのID必要が あるためIDをひっぱてくる
(comments_controller)
(assets/javascripts/edti_comments.js)
function()関数の中で、Promiseオブジェクトを生成しています。Promiseの引数にresolveとrejectがありますが、これが非同期処理が実行された場合のコールバック関数となります。
resolveは処理が正常に終了した時に呼ばれるコールバック関数です。また上記では記述されていませんが、rejectは処理が失敗した時に呼ばれるコールバック関数となります。resolveに引数がありますが、このように任意のオブジェクトを渡すことができます。
then関数とcatch関数が記述されています。thenは、処理が正常に実行された時、すわなちresolveが実行された時に呼ばれ、resolveの引数が渡されます。catch関数は上記では記述されていませんが、rejectが実行された時に呼ばれます。
replace(/\r?\n/g, '');
これは改行コード(\r\nまたは\n)をすべて削除するには次のように記述します。
<参考資料>
http://js.studio-kingdom.com/javascript/function/
https://qiita.com/hiro266/items/160a4f9290ecd9f27d15
https://pikawaka.com/rails/json
https://noumenon-th.net/programming/2018/12/14/promise1/
https://qiita.com/aiandrox/items/f612b9b8503785ed18bf