【Rails】enumについて

はじめに

enumについて記述していきます。

enumとは?

 enumとは、1つのカラムに指定した複数個の定数を保存できる様にする為のモノです。

例 user.rb

 class User < ApplicationRecord
  enum role: { general: 0, admin: 1 }
end

このenumを使うと指定した複数個の定数以外の値は保存できない様にしたり、カラムに指定した定数が入っているレコードを取り出すのが容易になったりと多くのエンジニアが頻繁に使用する大変便利なメソッドです。

enumの定義方法

  1. テーブルにenum用のカラムを用意する 
  2. モデルにenumの定義をする

マイグレーションファイル

class AddRoleToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :role, :integer, null: false, default: 0
  end
end

これでuserにroleという役割カラムを作成しました。integer型なので整数しか入りません。 enumはこの数値に定数を与えることができます。

それが先ほど例で出したものです。

user.rb

 class User < ApplicationRecord
  enum role: { general: 0, admin: 1 }
end

つまり、新規作成したuserは基本0の値が入るのでroleカラムにgeneralが入ります。

【Rails】AdminLTEについて

はじめに

管理画面を作るのが大変。そこで、管理画面作成に特化したCSSフレームワークAdminLTEについて記していきます。

インストール

$ yarn add admin-lte@^3.0

このように様々なファイルが取り込まれます。 yarnでインストールしたので、ルートディレクトリ直下の、node_modules/以下を確認しましょう。

Image from Gyazo

いろいろ展開されますが、adminLTEの本体はdist以下に格納されています。 あとは、依存関係のあるbootstrap, jquery(plugins/jQuery/)などなど。

これをRailsで読み込んでいきます。

まず、app/assets/stylesheets/admin.scssとapp/assets/javascripts/admin.jsを作成しましょう。

ここには、何を読み込むかを記載します。 たとえば、

app/assets/stylesheets/admin.scss

@import 'admin-lte/dist/css/adminlte.min.css';

app/assets/javascripts/admin.js

//= require admin-lte/dist/js/adminlte.min

このような、形で読み込みます。これは、node_modulesから取り込んでいます。 では、どうやってadmin-lte/dist/js/adminlte.minを探しているのか? node_modules/admin-lte/dist/js/adminlte.minではないのか?

それは、 config/initializers/assets.rbにパスが書いてあるからです。

assets.rb

Rails.application.config.assets.version = '1.0'

# パスの記述
Rails.application.config.assets.paths << Rails.root.join('node_modules')

# 他のマニフェストや、個別のスタイルシート/JavaScriptファイルをインクルードしたい場合は、config/initializers/assets.rbのprecompileという配列を使用します。
Rails.application.config.assets.precompile += %w[admin.js admin.scss]

これで準備完了です。

layoutsの指定

あとは、viewにこのadmin.scssとadmin.jsを参照するlayoutを指定しましょう。

admin/layouts/admin.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title><%= page_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>


    <%= stylesheet_link_tag    'admin', media: 'all' %> #ここをadminに変更
    <%= javascript_include_tag 'admin' %>#ここをadminに変更
  </head>

  <body>
    
    <%= yield %>
  
  </body>
</html>

###あとは使用したいコントローラーにlayoutメソッドを使用し、使用したいlayoutを指定します。

controller

class Admin::UserSessionsController < Admin::BaseController
  
  layout 'admin_login' #こんな感じ

  def new; end

  def create
    @user = login(params[:email], params[:password])
    if @user&.admin?
      redirect_to admin_root_path, success: 'ログインしました'
    elsif @user
      redirect_to root_path, danger: '権限がありません'
    else
      flash[:danger] = 'ログインに失敗しました'
      render :new
    end
  end

  def destroy
    logout
    redirect_to admin_login_path, success: 'ログアウトしました'
  end
end

【JavaScript】yarnについて

はじめに

yarnとは何かについて分からなかったので、整理しました。

yarnとは?

Node.jsで動作するパッケージマネージャーの一つです。
フロントエンド関連のパッケージ管理ツールは様々混在していますが、大枠 Bower → npm → yarn と言った流れを経てきています。

Node.jsとは?

 Node.jsというのは、JavaScriptでサーバーサイドの処理を可能にさせるプログラムです。 「Node.js = サーバサイドJavaScript」だと認識しておけばいいとどこかに書いてありました。(正確ではないらしい)

パッケージマネージャーとは?

「パッケージマネージャとは、コンピュータに何のソフトウェアがインストールされたかを記録し、新しいソフトウェアのインストール・新しいバージョンへのソフトウェアの更新・以前インストールしたソフトウェアの削除を容易に行えるようにするプログラム」

要するに

 yarnとnpmはJavaScriptでサーバーサイドの処理を行うために使うプログラム(Node.js)上で使うパッケージマネージャーということです。

フレームワークなどを使うにはインストールが簡単でじゃなきゃ?

何個ものプログラムでできているフレームワークをインストールするとします。それを動かすために必要なプログラムを全て手作業でサーバーの適切な場所にコピーし、特定の設定ファイルを書き換え、正常にインストールできたかを確認し、バージョン管理をするのはとても大変なことです。

パッケージマネージャ全て管理してくれる!!

 簡単なコマンドの入力でインストールを完了することができる。

yarnについて

  • JavaScriptのパッケージマネージャ
  • 2016年にFaceBookが公開した
  • npmと互換性がある = 同じpackage.jsonが使える

yarnのメリット

  • npmよりインストールが速い
    • 約半分になる場合もあるそう
  • npmより厳密にモジュールのバージョンを固定できる
    • yarn.lockファイルで、各パッケージのインストールバージョンを固定できる。
  • npmと一緒に使える
    • npmと同じのpackage.jsonが使えるため、同一プロジェクトでnpm or yarnで固定しなくて良い。

yarnのインストール

$ sudo npm install -g yarn

package.jsonの生成

パッケージを一括管理できるpackage.json。 プロジェクトにまだpackage.jsonがない場合、以下のコマンドで生成できる。

$ yarn init

yarnでパッケージをインストール

package.jsonに記載されたモジュールをインストールする。

$ yarn

パッケージの追加

以下のコマンドでパッケージのインストールとpackage.jsonへの追加ができる。

$ yarn add [パッケージ名]

npmではnpm install --saveだった。

パッケージのアンインストール

以下のコマンドでパッケージのインストールとpackage.jsonへの追加ができる。

$ yarn remove [パッケージ名]

npmではnpm uninstall

参考資料

npmとはyarnとは
yarnとは

【Rails】gem configについて

はじめに

 アプリを開発していく中で本番環境と開発環境で値を変えたいといったケースが出てくると思います。たとえばホストの情報を管理したい時などに使えます。メールを送る下準備としてホスト情報を設定しておく必要があるのですが、ホスト情報って開発環境、ステージング環境、本番環境で異なりますよね? 例えばこのように。

  • 開発環境・・・localhost:3000
  • ステージング環境・・・localhost:3000
  • 本番環境・・・exumple.jp

これを素直に実装しようとするとこのようになるはずです。 gem configを利用することで、Ruby on Railsで便利に定数を管理することができます。

設定

Gemfile

gem 'config'
$ bundle install

初期設定

以下のコマンドを実行して、configの初期設定をおこなっていきます。

$ bundle exec rails g config:install
Running via Spring preloader in process 30847
      create  config/initializers/config.rb
      create  config/settings.yml
      create  config/settings.local.yml
      create  config/settings
      create  config/settings/development.yml
      create  config/settings/production.yml
      create  config/settings/test.yml
      append  .gitignore

「config/」以下にいろいろとconfig関連のファイルが生成されました。

それぞれのファイルの役割は以下のとおりです。 Image from Gyazo

設定方法

web:
  host: 'localhost:3000'

例 config/settings/development.yml

   Settings.service.name
   Settings.service[:name]
   Settings[:service][:name]

【Rails】gem letter_opener_webについて

はじめに

 Ruby on Railsで開発中に送ったメールを確認する Gem letter_opener_webの使用方法の紹介です。 このように、開発環境で簡単に送られたメールを確認することができます。

Image from Gyazo

設定方法

Gemfile

group :development do
  gem 'letter_opener_web'
end

次に、 development.rb

#
Rails.application.configure do
 #配信方法
  config.action_mailer.delivery_method = :letter_opener_web
 # default_url_optionsの設定は、電子メールテンプレートのリンクURLを構築するのに便利です。
  config.action_mailer.default_url_options = { host: 'localhost:3000' }

end

routes.rb

Rails.application.routes.draw do
  mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?
end

使用方法

ブラウザで

http://localhost:3000/letter_opener

と入力するだけです。

【Rails】sorcery(Reset password)

はじめに

 sorceryとは、Railsに認証機能の実装を行うためのライブラリです。 同じように認証機能を提供してくれているものとしてdeviseなどが挙げられますが、sorceryの方がよりシンプルで、カスタマイズ性に富んでいるという特徴を持ちます。今回はsorceryのReset Passwordモジュールの実装方法を記していきます。

実装方法

モジュールのインストール

$ rails g sorcery:install reset_password --only-submodules
Running via Spring preloader in process 30110
        gsub  config/initializers/sorcery.rb
      insert  app/models/user.rb
      create  db/migrate/20200419075054_sorcery_reset_password.rb

これで、password_resetサブモジュールを使用するための記述がconfig/initializers/sorcery.rbに、自動で行われました。また、マイグレーションファイルなども作成されます。

マイグレーションファイル

class SorceryResetPassword < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :reset_password_token, :string, default: nil
    add_column :users, :reset_password_token_expires_at, :datetime, default: nil
    add_column :users, :reset_password_email_sent_at, :datetime, default: nil
    add_column :users, :access_count_to_reset_password_page, :integer, default: 0

    add_index :users, :reset_password_token
  end
end

この、マイグレーションファイルをDBに反映させます。

$ rails db:migrate

パスワードリセット用のMailerを作成

まず、Mailerを作成します。

$ rails g mailer UserMailer reset_password_email
Running via Spring preloader in process 88211
      create  app/mailers/user_mailer.rb
      invoke  erb
      create    app/views/user_mailer
      create    app/views/user_mailer/reset_password_email.text.erb
      create    app/views/user_mailer/reset_password_email.html.erb

次に、config/initializers/sorcery.rbの中で、sorceryのパスワードリセットに使用するActionMailerをUserMailerで指定します。

config/initializers/sorcery.rb

 Rails.application.config.sorcery.submodules = [:reset_password]

 Rails.application.config.sorcery.configure do |config|
   config.user_config do |user|
 # パスワードリセット用のMailerにUserMailerを指定する
     user.reset_password_mailer = UserMailer
  end
end

それでは、パスワードリセット用のメソッドを記述します。

class UserMailer < ApplicationMailer
  def reset_password_email(user)
    @user = User.find(user.id)
    @url  = edit_password_reset_url(@user.reset_password_token)
    mail(to: user.email,
         subject: 'パスワードリセット')
  end
end
# reset_password_emailメソッドなので、reset_password_email.〇〇のビューがメールのフォーマットになる
# メイラーのメソッド内で定義されたインスタンス変数はメイラーのビューで使える。

最後に、メイラービューの設定をします。

app/views/user_mailer/reset_password_email.html.erb

<h1><%= @user.decorate.full_name %>様</h1> 
<p>=====================================</p>

<p>パスワード再発行のご依頼を受け付けました。</p><br>

<p>こちらのリンクからパスワードの再発行を行ってください。</p>

<p><a href="<%= @url %>"><%= @url %></a></p>

app/views/user_mailer/reset_password_email.text.erb

<%= @user.decorate.full_name %>様
===========================================

パスワード再発行のご依頼を受け付けました。

こちらのリンクからパスワードの再発行を行ってください。
<%= @url %>

リセットをするためのフォームからコントローラまで

routes.rb

resources :password_resets, only: %i[new create edit update]

まずは、パスワードリセットのトークンを発行しメールを送るためのフォーム。

passowrd_reserts/new.html.erb

<% content_for(:title, t('.title')) %>
<div class="container">
  <div class="row">
    <div class=" col-md-10 offset-md-1 col-lg-8 offset-lg-2">
      <h1><%= t('.title') %></h1>
      <%= form_with url: password_resets_path, method: :post, local: true do |f| %>
        <div class="form-group">
          <%= f.label :email, User.human_attribute_name(:email) %>
          <%= f.email_field :email, class: 'form-control' %>
        </div>
        <div class="actions">
          <%= f.submit t('default.sent'), class: 'btn btn-primary' %>
        </div>
      <% end %>
    </div>
  </div>
</div>

email情報からパスワードをリセットしたい、userを抜き出す。

app/controllers/password_resets_controller.rb

 class PasswordResetsController < ApplicationController
  skip_before_action :require_login

  def new; end

  def create
    @user = User.find_by_email(params[:email])
    # ここで先ほど定義したメソッドのapp/mailers/user_mailer.rbへ
    @user&.deliver_reset_password_instructions!
    redirect_to login_path, success: 'パスワードリセット手順を送信しました'
  end

  def edit
    @token = params[:id]
    @user = User.load_from_reset_password_token(params[:id])
    not_authenticated if @user.blank?
  end

  def update
    @token = params[:id]
    @user = User.load_from_reset_password_token(params[:id])

    return not_authenticated if @user.blank?

    @user.password_confirmation = params[:user][:password_confirmation]
    if @user.change_password(params[:user][:password])
      redirect_to login_path, success: 'パスワードを変更しました'
    else
      flash.now[:danger] = 'パスワードを変更できませんでした'
      render action: 'edit'
    end
  end
end

createメソッドが動き、さきほどの設定したメールテンプレートが送信されます。そのトークンが含まれたURLからeditアクションを起動しapp/views/password_resets/edit.html.erbへ遷移されます。

app/views/password_resets/edit.html.erb

<% content_for(:title, t('.title')) %>
<div class="container">
  <div class="row">
    <div class=" col-md-10 offset-md-1 col-lg-8 offset-lg-2">
    <h1><%= t('.title') %></h1>
      <%= form_for @user, :url => password_reset_path(@token), :html => {:method => :put} do |f| %>
        <%= render 'shared/error_messages', object: f.object %>

        <div class="form-group">
          <%= f.label :email %><br />
          <%= @user.email %>
        </div>
        <div class="form-group">
          <%= f.label :password %><br />
          <%= f.password_field :password, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :password_confirmation %><br />
          <%= f.password_field :password_confirmation, class: 'form-control' %>
        </div>
        <div class="actions">
          <%= f.submit class: 'btn btn-primary' %>
        </div>
      <% end %>
    </div>
  </div>
</div>

このフォームでボタンを押すと、updateアクションが起動し、パスワードリセット完了です。

参考資料

sourcery公式

【Rails】日時フォーマット(lメソッド)

はじめに

Viewにcreated_atのような日付を出力すると、

Tue, 30 Jul 2020 00:12:12 +0000

のような日本人には見慣れない表示がされます。この記事ではこれを日本人が見やすい表示に変更する流れを紹介します。

タイムゾーンを日本時間にする

まず、タイムゾーンを日本時間にしましょう。

config/application.rb

module Normal
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    # アプリケーション側のタイムゾーン
    config.time_zone = 'Tokyo'
    # DB側から受け取った時刻をどのタイムゾーンとして解釈するか
    config.active_record.default_timezone = :local  
  end
end

これで画面に表示される日時が日本時間になります。

Tue, 30 Jul 2020 09:12:12 +0900

日本人が読みやすいフォーマットにする

lメソッドをしようするのですが、そのまえに準備をします。 先ほどのapplication.rbに以下を追記します。

# デフォルトの言語を日本語に変更
    # デフォルトは:enになっている
    config.i18n.default_locale = :ja
    # localeファイルの読み込み設定
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]

続いて、 config/locales/ja.ymlというファイルを作成し、以下の記述をします。

ja:
  time:
    formats:
      default: "%Y/%m/%d %H:%M:%S"

これで準備OKです。 View側で

<%= l user.created_at %>

と記述してみましょう。

2020/11/30 09:12:12

とわかりやすい表示になっているはずです。

応用編

他にも、ja.ymlの指定を増やせばいろいろな形のフォーマットを実現できます。

ja.yml

ja:
  time:
    formats:
      default: "%Y/%m/%d %H:%M:%S"
      short: "%m/%d %H:%M"

View側

<%= l user.created_at, format: :short %>
11/30 09:12

このように、フォーマットを作ることができます。

参考文献

Railsガイド 日付・時刻フォーマットを追加する