しおブログ言うてますけど

技術ブログ言うてますけど技術以外のことも発信すると思われ。RubyとかRuby on Railsとか生き方とかジャンルにこだわらず自分の好きなように。初心者なのでお手柔らかに。

Gem gretelを使ってパンくずを設定する方法

こんにちは。塩濱です。
今回はgretelというGemを使ってパンくずを設定する方法についてまとめていきたいと思います。
パンくずとはこんな感じで自分が今どのページにいるかわかるというものです。(間違ってたら修正します)

https://i.gyazo.com/727a8adbf183c706dd6a91abb5b56dc9.png

前提

今回使用するgreteというGemをインストールし、使えるるようになっていること。

使用方法

$ rails generate gretel:install

rails g コマンドを使用してgretel:installするとbreadcrumb.rbというファイルが作成されます。 このファイルにパンくずの設定を書いていきます。

# config/breadcrumb.rb

# 記法
crumb crumsの名前を指定 do
  link '表示させたい文字', その文字のリンク先
  parent 親の指定
end

基本的な記法はこのようになります。

crumb :admin_tags do
  link 'タグ', admin_tags_path
  parent :admin_dashboard
end

crumb :edit_admin_tag do |tag|
  link 'タグ編集', edit_admin_tag_path(tag)
  parent :admin_tags
end

crumb :new_admin_article do
  link '記事作成', new_admin_article_path
  parent :admin_articles
end

idが必要になるURLにはブロックでローカル変数を渡すことでidが渡されます。

viewの設定

ここまでできたらあとは、viewで記述するだけです。

<% breadcrumb :admin_users %>

先程 breadcrumb.rbで設定したcrumbの名前をつけることによってパンくずが設定されます。 また、crumb :edit_admin_tagのようにローカル変数を渡しているものはview側でも変数を渡さなければいけません。

<% breadcrumb :edit_admin_tag, @tag %>

変数を渡すことで、エラーが出ずにパンくずが設定できているかと思います。

まとめ

パンくずはWEBサイト、WEBアプリケーションなどでよく使われるものだと思うので、しっかり理解していきたいと思いました。

RSpec 〜ログイン処理をmoduleにまとめる

こんにちは。塩濵です。
RSpecを使ってテストを書いている時、ログインの処理を書くことがよくあります。
毎回書くのは大変なので今回はログイン処理のテストをmoduleにまとめることで、毎回書かずにわかりやすいコードにするということについてまとめていきます。

前提

前提として、RSpec、capybara、factory_bot_railsのGemが追加してあり、 これらのGemが正しく使えること。

RSpecの基本形

RSpecについて詳しくはここではまとめませんが、基本的な記法だけ、まとめておきます。

describe [ 仕様を記述する対象(テスト対象) ], type: [ Specの種類 ]  do

  context [ ある状態・状態 ] do
    before do
      [事前準備]
    end

    it [ 仕様の内容(期待の概要) ] do
      [期待する動作]
    end
  end

end

RSpecの基本的な形は上記の様になります。
itに達成するまでにdescribeやcontextを何個もネストすることもでき、内部のcontext、describe、itを並べて複数記述することもできます。
ネストや複数記述したSystem Specのコードの基本形も書いておきます。

describe '〜機能', type: :system do

  describe '登録' do

    context '〇〇の場合' do
      before do
        # (context内を確認するのに必要な)事前準備
      end

      it '△△する' do
        # 期待する動作
      end
    end

    context 'XXの場合' do
      before do
        # (context内を確認するのに必要な)事前準備
      end

      it '○○する' do
        # 期待する動作
      end
    end
  end

  discribe '削除' do
    # 略
  end
end

たくさん用語が出てきますが、大きく分けて2つのタイプに分ける事ができます。
●テストケースを整理・分類する => describe, context
●テストコードを実行する => before, it

このようにdescribe, contextは整理、分類するために使われ、before, itはテストコードを実行するために記述されます。

UserFactoryの作成

ログイン処理をmoduleにまとめる前にUserFactoryを作成することによってテスト実行時に、ログインさせるユーザーを作成します。
ここではログインページに遷移し、EmailPasswordを入力して、ログインボタンを押すと、ログインが完了するといった処理の流れにしていきたいと思います。

FactoryBot.define do
  factory :user do
    sequence(:email) { |n| "example#{n}@example.com" }
    password { 'password' }
    password_confirmation { 'password' }
  end
end

UserFactoryの作成が完了しました。
sequenceは同一ではない適当な値が代入されます。
この場合、example1@example.comexample2@example.comexample3@example.comというふうになります。

ログイン処理のmoduleを作成

supportディレクトリを作成し、supportディレクトリ内にlogin_module.rbファイルを作成します。
login_module.rbファイルにログインの処理を書いていきます。

module LoginModule
 def login(user)
   visit new_user_session_path
   fill_in 'Email', with: user.email
   fill_in 'Password', with: user.password
   click_button 'ログイン'
   expect(current_path).to eq root_path
 end
end

moduleが設定できたらこのmoduleを読み込む設定をrails_helper.rbに記載します。

# rails_helper.rb

RSpec.configure do |config|
  config.include LoginModule
end

こうすることでSystem Specでログインをまとめたmoduleを使えることができます。

まとめ

今回はログインの処理をmoduleにまとめることによってログインの処理を毎回書かずにコード量を減らせるというメリットがあることについてまとめてみました。
RSpecでテストを書くことにはまだまだ理解が追いついていないので、キャッチアップとアウトプットを繰り返して、身に付けれるように努力していきたいと思いました。

ransackで「いつ~いつ」を検索するためのカスタマイズ方法

こんにちはしおはまです。
今回はransackというGemを使って「いつ~いつ」という条件で検索できるようにするためのカスタマイズ方法についてまとめていきたいと思います。
基本的な検索方法については別の記事で紹介しておりますのでそちらを参照してください。

前提条件

今回実装するための前提条件として、ToDoアプリを作ったとして、そのToDoアプリのリストの作成日時を「いつ~いつ」という条件で検索できるようにしたいという構成になってます。
Listモデルのcreated_atを検索対象としています。
もちろん今回使用するransackというGemは導入している前提です。 それでは実装方法についてまとめていきます。

簡単なやり方

一番簡単な実装方法はlistcontrollerにて

@q = List.ransack(params[:q])
@lists = @q.result.includes(%i[user]).order(created_at: :asc)

として検索できるようにします。
viewにて

<%= f.label :created_at_gteq %>
<%= f.text_field :created_at_gteq %>

<%= f.label :created_at_lteq %>
<%= f.text_field :created_at_lteq %>

とすることによって「いつ~いつ」という条件の検索ができるようになります。
しかし、この実装方法では正しく絞り込みができません。
例えば、1月1日から1月5日までのリストを検索したい場合、「xx(年)/1/1」~「xx(年)/1/5」と検索フォームに入力します。
created_at_gteqcreated_at_lteqの場合、「1月1日00時〜1月5日00時」までのリストしか表示することができません。
これでは困ります。実質前日のリストしか検索できないようになってますね。

ransackのカスタマイズ

ransackは非常に便利なので、カスタマイズすることによって検索条件を変更することができます。
どうやってカスタマイズしたらいいのか。
predecatesをカスタマイズすることで検索条件を変更することができます。
predicateを直訳すると述語
検索するとき、「attribute(属性) + predicate(述語)」で検索しますよね。

<%= f.search_field :name_cont %>

このようなコードの場合、name(属性)+cont(述語)というふうにすることで、name属性に~を含んでいるものを検索対象としています。
このcontという部分がpredicate。つまり述語になります。

github.com

上記のURLはransackの公式Github内のWikiにここをカスタマイズするよ~的なことが書いてあるURLです。
このまま全部コピペして、みたいなことはしなくてよくて、カスタマイズしたい部分だけコードを書けばいいです。
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

この辺りはransackの公式Githubを見たほうがわかりやすいですが、1つずつ見ていきます。

config.add_predicate→ 述語の名称。ここでカスタマイズするpredicateの名前を設定します。

arel_predicate→入力された値を適切にフォーマットする。ここでカスタマイズするpredicateを記載します。今回はcreated_at_lteqのpredicateであるlteqをカスタマイズしたいので引数にlteqを取ります。

formatter: proc→値を検証します。無効な値は、検索に使用されません。 ここで受け取った値をどうフォーマットするかを変更できます。
デフォルトでは{ |v| "#{v}-diddly" }となっています。
今回はend_of_dayで受け取るように設定しています。

viewの設定

ここまで設定できたらviewの設定をしていきます。

<%= f.date_field :created_at_gteq, include_blank: true, class: 'form-control', , placeholder: '年/月/日' %>
<%= f.date_field :created_at_lteq_end_of_day, include_blank: true, class: 'form-control', , placeholder: '年/月/日' %>

今回、lteq_end_of_dayというpredicateを設定したので「いつ~いつ」という検索条件の「いつまで」の部分にcreated_at_lteq_end_of_dayとしています。 どのようになってるか見てみましょう。

https://i.gyazo.com/48db56414b15236d1a0ba45496031152.png

こんなふうになっており、「いつ~いつ」という検索ができるようになっていますね。

まとめ

  • ransackでカスタマイズするときは、config/initializers/ransack.rbを作成し、ransack公式Github内のWikiを参考にカスタマイズする。
    ransack.rbのconfigのコードが最初よくわからなかったが、config.add_predicateではカスタマイズするpredicateの名前を設定する。つまり名前を設定していて、arel_predicateで実際にカスタマイズするpredicateを設定しているということに気づいてだいぶ整理しやすくなった。
    アウトプットって大事やな... 最後まで拝読していただきありがとうございました。

yarnでインストールしたAdminLTE3を使った管理画面の作り方

こんにちはしおはまです。
今回はAdminLTE3を使った管理画面の作り方をまとめていきたいと思います。
そもそもAdminLTE3ってなんですか?って思いますね。

簡単にAdminLTEの説明

AdminLTE3とはBootstrap3をベースにした、管理画面等のテンプレートテーマです。

https://i.gyazo.com/508d2e0cb3e93816b1d534ce76acbb02.png

上記のような画面や、

https://i.gyazo.com/f7503cb214a4a9a50c6b4d2bd4a57272.png

こんな管理者用のログイン画面だって簡単に実装できてしまいます。
スマートフォン等にも対応しており、かっこいい管理画面作りたいけどデザインに自信がない・・・といった方でも、かっこいいUIが作成できてしまいます。(ちなみに僕はフロント部分が苦手なので大変助けられました...)

前提条件

ます前提条件としてyarn がインストールされていることを確認してください。
yarnがインストールされていない場合は、先にyarnをインストールしてからこちらを参考してください。
ここではyarnのインストールは割愛させていただきます。

AdminLTEのインストール

それではさっそくAdminLTEをインストールしていきます。

$ yarn add admin-lte

https://i.gyazo.com/28556dffc072ec52bd6be1147ad8f18a.png

色々インストールされて最後に✨ Done inという文字が出たら正常にインストールされています。

インストールが完了したら以下の3つのファイルが作成されます。

  • node_modules

https://i.gyazo.com/f0652887e14c5c66f0edfcdb5e2702d4.png

{
  "dependencies": {
    "admin-lte": "^3.1.0-rc"
  }
}
  • yarn.lock
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@fortawesome/fontawesome-free@^5.15.1":
  version "5.15.2"
  resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.2.tgz#218cd7276ab4f9ab57cc3d2efa2697e6a579f25d"
  integrity sha512-7l/AX41m609L/EXI9EKH3Vs3v0iA8tKlIOGtw+kgcoanI7p+e4I4GYLqW3UXWiTnjSFymKSmTTPKYrivzbxxqA==

"@lgaitan/pace-progress@^1.0.7":
  version "1.0.7"
  resolved "https://registry.yarnpkg.com/@lgaitan/pace-progress/-/pace-progress-1.0.7.tgz#c96fbbd9fd4cf528feed34ea0c8f9d8b3e98f0dd"
  integrity sha1-yW+72f1M9Sj+7TTqDI+diz6Y8N0=

"@sweetalert2/theme-bootstrap-4@^4.0.1":
  version "4.0.3"
  resolved "https://registry.yarnpkg.com/@sweetalert2/theme-bootstrap-4/-/theme-bootstrap-4-4.0.3.tgz#7a9e7a99f5ecfb353e4ba9a16de918736162370c"
  integrity sha512-jP8cpQy4cGjlGPkEK8KF/owF00BRz5vvEdi5VrpTsiMjdkte85a1EZ/azPsX9HQrMAZ2qAmIsleV8UDcl8R2YQ==

"@ttskch/select2-bootstrap4-theme@^1.4.0":
  version "1.5.2"
  resolved "https://registry.yarnpkg.com/@ttskch/select2-bootstrap4-theme/-/select2-bootstrap4-theme-1.5.2.tgz#3b4519b349f3e7831c28752a1e9617312a192656"
  integrity sha512-gAj8qNy/VYwQDBkACm0USM66kxFai8flX83ayRXPNhzZckEgSqIBB9sM74SCM3ssgeX+ZVy4BifTnLis+KpIyg==

このうちnode_modulesは頻繁に活用するのでちゃんとインストールされていることを確認してください。

使い方

AdminLTEの使い方はシンプルで先程インストールしたnode_modulesから使いたいhtmlファイルを選び、erbファイルに変換して使います。
例えば、初めに画像で使った管理者用のログイン画面を使いたい場合、

node_modules/admin-lte/pages/example/login.html

のファイルを使えば、簡単に使うことができます。

jsファイルとcssファイルを分ける

先程使用したlogin.htmlはあくまでもhtmlファイルなので中身を見るとわかると思うのですが、cssの読み込みやjsの読み込みのコードまで書いてあります。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>AdminLTE 3 | Log in</title>

  <!-- Google Font: Source Sans Pro -->
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
  <!-- Font Awesome -->
  <link rel="stylesheet" href="../../plugins/fontawesome-free/css/all.min.css">
  <!-- icheck bootstrap -->
  <link rel="stylesheet" href="../../plugins/icheck-bootstrap/icheck-bootstrap.min.css">
  <!-- Theme style -->
  <link rel="stylesheet" href="../../dist/css/adminlte.min.css">
</head>
<body class="hold-transition login-page">
<div class="login-box">
  <div class="login-logo">
    <a href="../../index2.html"><b>Admin</b>LTE</a>
  </div>
  <!-- /.login-logo -->
  <div class="card">
    <div class="card-body login-card-body">
      <p class="login-box-msg">Sign in to start your session</p>

      <form action="../../index3.html" method="post">
        <div class="input-group mb-3">
          <input type="email" class="form-control" placeholder="Email">
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-envelope"></span>
            </div>
          </div>
        </div>
        <div class="input-group mb-3">
          <input type="password" class="form-control" placeholder="Password">
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-lock"></span>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-8">
            <div class="icheck-primary">
              <input type="checkbox" id="remember">
              <label for="remember">
                Remember Me
              </label>
            </div>
          </div>
          <!-- /.col -->
          <div class="col-4">
            <button type="submit" class="btn btn-primary btn-block">Sign In</button>
          </div>
          <!-- /.col -->
        </div>
      </form>

      <div class="social-auth-links text-center mb-3">
        <p>- OR -</p>
        <a href="#" class="btn btn-block btn-primary">
          <i class="fab fa-facebook mr-2"></i> Sign in using Facebook
        </a>
        <a href="#" class="btn btn-block btn-danger">
          <i class="fab fa-google-plus mr-2"></i> Sign in using Google+
        </a>
      </div>
      <!-- /.social-auth-links -->

      <p class="mb-1">
        <a href="forgot-password.html">I forgot my password</a>
      </p>
      <p class="mb-0">
        <a href="register.html" class="text-center">Register a new membership</a>
      </p>
    </div>
    <!-- /.login-card-body -->
  </div>
</div>
<!-- /.login-box -->

<!-- jQuery -->
<script src="../../plugins/jquery/jquery.min.js"></script>
<!-- Bootstrap 4 -->
<script src="../../plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- AdminLTE App -->
<script src="../../dist/js/adminlte.min.js"></script>
</body>
</html>

これをRailsではアセットパイプラインの仕組みを使って、jsファイルとcssファイルを分けることができます。
ここではわかりやすくadmin.jsadmin.scssファイルを作成し、個別ファイルでjsとcssを分けていきます。

#admin.scss

@import 'bootstrap/dist/css/bootstrap.min.css';
@import 'admin-lte/dist/css/adminlte.min.css';
@import 'admin-lte/plugins/fontawesome-free/css/all.min.css';
#admin.js

//= require rails-ujs
//= require jquery/dist/jquery.min
//= require bootstrap/dist/js/bootstrap.min
//= require admin-lte/dist/js/adminlte.min

※application.js、application.cssでのrequire_tree .について

Railsではデフォルトでapplication.jsapplication.css

# application.js

//= require_tree .
# application.css

*= require_tree .

というコードがあります。
これは何を意味しているかというと、require_treeには指定したディレクトリ以下のすべてのJSファイルを読み込むといった特徴があります。
先程作成したadmin.jsadmin.cssapplication.jsapplication.cssと同じ階層に作成しています。
→つまりrequire_treeを記述していることによって管理画面しか使用しないファイルまでapplication.css(js)を読み込んでしまいます。
個別でcss、jsファイルを読み込むにはrequire_tree は削除します。

jsファイルとcssファイルを別に読み込むことができたら元のhtmlファイルをerbで使う部分以外を削除します。(今回は元のファイルからかなりカスタマイズしています)

    <div class="hold-transition login-page">
      <div class="login-box">
        <div class="login-logo">
          <%= link_to 'ログイン', '#' %>
        </div>

        <div class="card">
          <div class="card-body login-card-body">

            <%= form_with  local: true do |f| %>

              <div class="form-group">
                <%= f.label :email, (t 'user_sessions.new.email') %>
                <%= f.email_field :email, class: 'form-control', id: 'email' %>
              </div>

              <div class="form-group">
                <%= f.label :password, (t 'user_sessions.new.password') %>
                <%= f.password_field :password, class: 'form-control', id: 'password' %>
              </div>

              <div class="row">

                <!-- /.col -->
                <div class="col-4 form-group">
                  <%= f.submit t('user_sessions.new.title') , class: 'btn btn-primary' %>
                </div>

                <!-- /.col -->
              </div>
            <% end %>

          </div>
        </div>
      </div>
    </div>

このようにすると

https://i.gyazo.com/79911e72c08a0f625bff12891a8a045c.png

無事にログインが作れたかと思います。

まとめ

今回はバックエンドの実装ではなく、フロント部分の実装をしました。
フロント部分は苦手なのでしっかりアウトプットすることで知識の定着を測っていきたいです。
バックエンドの実装も今後まとめていければと思っています。
最後まで拝読していただき、ありがとうございました。

sorceryでパスワードリセット機能を実装する

こんにちは。しおはまです。
今回はsorceryというGemを使ってパスワードをリセットする機能を実装する過程をまとめてみたいと思います。

sorceryとは

そもそもsorceryってどういうGemなのか説明します。
Sorceryは、ユーザ認証機能を簡単に実装できるライブラリで、MITライセンスのオープンソースソフトウェアとして公開されています。

github.com

↑がsorcerygithubです。
ユーザの認証の基本的な機能であるパスワード認証を始め、

  • User Activation
  • Reset Password
  • Remember Me
  • Session Timeout
  • Brute Force Protection
  • Basic HTTP Authentication
  • Activity Logging

といった機能が揃っており、必要に応じて機能を選んで使うことができます。
ログイン機能やパスワード認証の実装についても今後ブログでまとめたいですが、今回はパスワードをリセットする方法にフォーカスを当ててまとめていきたいと思います。
なお、ログイン機能については今回は実装できている前提で説明をしますのでご了承ください。

sorceryのインストール

さっそくパスワードをリセットする方法について見ていきます。
まずは、Gemfilesorceryを記述してbundle installしましょう。

 # Gemfile

gem 'sorcery'

パスワードのリセットを実装するにはsorceryReset Passwordというmoduleを使用します。

github.com

こちらのgithubに一連の流れは書いてあるので、より正しい情報が知りたいという方は参照してみてください。

moduleのインストールとマイグレーションファイルの作成

まず初めの手段として下記のコマンドでmoduleのインストールとマイグレーションファイルの作成をします。

$ rails g sorcery:install reset_password --only-submodules

コマンドを叩くと、自動的にマイグレーションファイルが作成されます。

class SorceryResetPassword < ActiveRecord::Migration
  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_index :users, :reset_password_token
  end
end

マイグレーションファイルが作成されたことを確認して、マイグレーションを実行します。

$ rails db:migrate

config/initializers/sorcery.rb(sorceryの設定ファイル)を見ると自動的にpassword_resetのサブモジュールを使用することが書かれています。

# Gemfile

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

####################################

Rails.application.config.sorcery.configure do |config|
  config.user_config do |user|
    user.reset_password_mailer = UserMailer
  end
end

PasswordResetsコントローラーの追加

ここまで設定できたらrails gコマンドでPasswordResetsコントローラーを作成します。
アクションはパスワードを変更するcreate、編集ファイルのedit、作成するためのupdateを指定します。

rails g controller PasswordResets create edit update

PasswordResetsコントローラーが作成できたらReset passwordのgithubにしたがってコードを記述します。(多少カスタマイズしているところもありますが、おおまかなところは変わり無いです)

class PasswordResetsController < ApplicationController
  skip_before_action :require_login

  def create
    @user = User.find_by(email: params[:email])
    @user&.deliver_reset_password_instructions! if @user
    flash[:success] = 'パスワードリセット手順を送信しました'
    redirect_to root_path
  end

  def edit
    @token = params[:id]
    @user = User.load_from_reset_password_token(params[:id])
    return 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])
      flash[:success] = 'パスワードを変更しました'
      redirect_to login_path
    else
      flash.now[:danger] = 'パスワードを変更できませんでした'
      render :edit
    end
  end
end

細かいメソッドの説明は割愛しますが、createアクションはパスワードをリセットするためのメールアドレスを送信し、どのユーザーのメールアドレスかを判定します。
editアクションでは実際にパスワードをリセットするための判定がされています。(詳しくはgithubWikiload_from_reset_password_tokenの動きなどを確認するといいと思います)。
updateアクションではパスワードをリセットする動きを制御しています。

 if @user.change_password

の部分でパスワードの条件分岐をしており、正しくパスワードが入力されたらtrueになり、正常にパスワードがリセットされるということになります。

ルーティングの設定

コントローラーまで設定できたら次にルーティングの設定をしていきます。
ルーティングの設定は簡単ですね。

# route.rb

resources :password_resets, only: [:create, :edit, :update]

これでルーティングが正しく設定されますね。

送信メールの設定

ルーティングの設定ができたら送信するためのメールを設定していきます。

# reset_password_email.text.erb

Hello, <%= @user.email %>
===============================================

You have requested to reset your password.

To choose a new password, just follow this link: <%= @url %>

Have a great day!

ここは自分が送信メールで設定できる部分なので自由にコードを書いてもいいのですが、<%= @user.email %>でパスワードをリセットするために送信したメールアドレス、<%= @url %>にパスワードをリセットするためのURLが記載されますので、ご注意ください。

# app/mailers/user_mailer.rb

def reset_password_email(user)
  @user = User.find user.id
  @url  = edit_password_reset_url(@user.reset_password_token)
  mail(:to => user.email,
       :subject => "Your password has been reset")
end

user_mailer.rbApplicationMailerを継承しており、メールに関する設定を変更できます。
特にmail(to: user.email, subject: 'パスワードリセット')で、メールの送信元、メールの題名を設定することができます。

フォームの作成

ここまで設定できたらあとはフォームを作成するだけです。
どのようにフォームを作成するかは個人個人で違うと思いますが、githubを参考に# app/views/password_resets/new.html.erb# app/views/password_resets/create.html.erbにコードを書いていくと簡単に作成することができます。

まとめ

ここまで読んでいただきありがとうございます。
長くなってしまいましたが、パスワードリセット機能はログイン機能を実装したら必然的にリセット機能も必要になってくるのでしっかり理解しておきたいところですね。
にしてもsorceryは使いたい機能を使う時にサブモジュールをインストールして自分で実装できるのがいいですね。

ransackで検索機能を実装する

こんにちは、しおはまです。
今回はransackという検索機能を実装できるgemの使い方をまとめてみます。

ransackとは

冒頭で説明した通り、ransackは検索機能を簡単に実装することができるRailsのGemです。
検索機能を実装することで掲示板やToDoアプリ、その他WEBアプリにおいて検索機能が実装されているとなにかと便利です。
それでは使い方をみていきます。

ransackのインストール

まずはGemを使うためにGemfileにransackを追加していきます。

gem 'ransack

Gemfileに追加したらbundle installして準備完了です。

ransackの使い方

まず、コントローラーからみていきましょう。
例として、ユーザーの名前を検索できる機能を実装することを想定し、 users_controllerではこのような形式になってるとしましょう。

# users_controller

def index
  @users = User.all
end

インスタンス変数@usersにUserオブジェクトの全ての値が入っています。
この値を検索できるように下記のように書き換えます。

# users_controller

def index
  @q = User.ransack(params[:q])
  @users = @q.result(distinct: true)
end

いきなりransackとか(params[:q])とかresultとか出てきて戸惑うかもしれませんが、このメソッドの概要を説明します。

用語 説明
params[:q] ビューファイルから送られてくるパラメーター。
ransackメソッド 送られてきたパラメーターを元にテーブルからデータを検索するメソッド。(whereメソッドのransack版というイメージ。)
resultメソッド ransackメソッドで取得したデータをActiveRecord_Relationのオブジェクトに変換するメソッド。

なんとなくイメージは掴めたでしょうか。
@qの部分は自分で好きな変数名をつけても動きますが、慣習的に@qを使用します。
次に検索をフォームを作っていきます。

# 検索フォーム.erb(例)

<%= search_form_for @q, url: users_path do |f| %>
  <%= f.label :name, "Keyword" %>
  <%= f.search_field :name_cont %>

  <%= f.submit "検索" %>
<% end %>

検索フォームを実装するには<%= %>で囲んでsearch_form_forメソッドを使います。
search_form_forメソッドはransackで用意されているメソッドです。
これがどのようにして検索フォームとしてできているのか。
_contの部分です。
_contはransackで用意されているメソッドで、検索したワードが含まれているレコードを取得するためのメソッドです。
つまり、検索結果に属性(カラム)が含まれていれば表示するというものになります。
ransackには検索のためのメソッドが沢山ようされています。

検索に使えるメソッド

_contのような便利なメソッドの他にたくさんの便利メソッドが用意されているので少し紹介します。

メソッド名 説明
_eq 完全に一致するとき
_not_eq 完全に一致しないとき
_matches 一部が一致するとき
_does_not_match 一部が一致しないとき
_matches_any いずれかに一致するとき
_matches_all 全てに一致するとき
_does_not_match_any いずれにも一致しないとき
_does_not_match_all 全てに一致しないとき
_lt 〜未満のとき
_lteq 〜以下のとき
_gt 〜より大きいとき
_gteq 〜以上のとき
_present nullでも空でもないとき
_blank nullまたは空のとき
_null nullのとき
_not_null nllではないとき
_in 配列内の値と一致するとき
_not_in 配列内のどの値とも一致しないとき
_lt_any いずれかの値より少ないとき
_lteq_any いずれかの値以下のとき
_gt_any いずれかの値より大きいとき
_gteq_any いずれかの値以上のとき
_lt_all 全ての値よりも少ないとき
_lteq_all 全ての値以下のとき
_gt_all 全ての値より大きいとき
_gteq_all 全ての値以上のとき
_not_eq_all 指定した値ではないとき
_start 前方一致のとき
_not_start 前方不一致のとき
_start_any 〜のいずれかで始まるとき
_start_all 〜の全てから始まるとき
_not_start_any 〜のいずれかで始まらないとき
_not_start_all 〜の全てから始まらないとき
_end 後方一致のとき
_not_end 後方不一致のとき
_end_any 〜のいずれかで終わるとき
_end_all 〜の全てで終わるとき
_not_end_any 〜いずれかで終わらないとき
_not_end_all 〜の全てで終わらないとき
_cont 〜の部分が一致するとき
_cont_any 〜のいずれかが含まれているとき
_cont_all 〜の全てが含まれているとき
_not_cont 〜に部分が一致しないとき
_not_cont_any 〜のいずれかが含まないとき
_not_cont_all 〜の全てが含まれないとき
_i_cont 大文字と小文字を区別しない値が含まれるとき
_i_cont_any 大文字と小文字を区別しないいずれかの値が含まれるとき
_i_cont_all 大文字と小文字を区別しない全ての値が含まれるとき
not_i_cont 大文字と小文字を区別しない値が含まれないとき
_not_i_cont_any 大文字と小文字を区別しないいずれかの値が含まれないとき
_not_i_cont_all 大文字と小文字を区別しない全ての値が含まれないとき
_true 真偽値のレコードを取得するとき
_false 真偽値と反対のレコードを取得するとき

長くなってしまいましたがこのようなメソッドが用意されているので、時と場合によって使い分けるようにしましょう。

まとめ

  • コントローラーとビューを変更して、検索機能を実装する。
  • viewファイルではsearch_form_forメソッドを使用する

検索機能は汎用性が高く、よく使われると思うので、いろいろなメソッドを使いこなせるようにしていきたいです。

kaminariの使い方 まとめ

こんにちは。しおはまです。
今回はページネーションを実装するのに便利なGem(kaminari)の基本的な使い方をまとめてみます。

ページネーションとは

よくブラウザとかで見るこれです。(下記の画像を参照)
https://i.gyazo.com/377c6968bdbadbf9ef4760806aa50159.png

検索結果が多くなり、1ページに収めようとするとUI的に見にくい場合なんかにページネーションは使用されていますね。
または、掲示板アプリなどでたくさん記事を投稿すると、古い記事がどんどん下のページにいってしまい、見にくくなりますよね。
そんな時、ページネーションを実装し、ページを分けることで見やすくなります。
そこで、RailsのGemで簡単にページネーションが実装できるkaminariというGemの使い方を学んだので、自分なりにアウトプットしていこうと思います。

kaminariのインストール

まず初めにGemfilekaminariを追加し、bundle installします。

gem 'kaminari'

インストールが完了したらkaminariを使うことができます。簡単ですね。

記述の仕方

使い方はシンプルで、controllerでページネーションさせたいデータにpageメソッドを追加して、viewファイルにて、paginateメソッドを用いてページネーションを追加するだけです。
文脈だとわかりにくいのでここでは例として、ToDoアプリを作ったとして、そのToDoリストをページネーションさせたいとします。
ToDoアプリのモデルはTaskとし、ToDo一覧ページでタスクが10件以上あるとページネーションさせるとします。(あくまでも例です。アプリにてCRUD処理が実装できている前提です。)

# tasks_controller.rb

class TaskController < ApplicationController
  def index
    @tasks = Task.all
  end
end

Taskコントローラーのindexアクションではこのようなコードになっていると思います。
ここで、kaminariをインストールした時に追加されるpageメソッドを使います。
pageメソッドについては後述します。

# tasks_controller.rb

class TaskController < ApplicationController
  def index
    @tasks = Task.all.page(params[:page])    -----------この部分
  end
end

page(params[:page]) を追加し、viewファイルにてページネーションの指定をすることでページネーションが完成します。

#viewファイル

<%= paginate @tasks %>

このようにviewファイルにてページネーションを表示させたい部分にpaginateメソッドを使用し、引数に先程pageメソッドを設定したインスタンスを渡すことでページネーションが実装されます。
ちなみにデフォルトでは、ページネーションが1ページに表示するレコード数はデフォルトで25件です。

※pageメソッドについて

kaminariを導入すると、モデルクラスにpageメソッドが定義されます。このメソッドは、ページネーションにおけるページ数を指定します。ビューのリクエストの際paramsの中にpageというキーが追加されて、その値がビューで指定したページ番号となります。よって、pageの引数はparams[:page]となります。

kaminariのデフォルト設定の変更

今の状態でもページネーションは実装できていますが、このままでは1ページに表示するレコード数がで25件なので、1ページに表示するレコードを10件に変更したいです。
やり方は様々ありますが、ここではrails gコマンドでconfig/initializersに設定ファイルを作成させましょう。

$ rails g kaminari:config

これで簡単にconfig/initializersファイルにkaminari_config.rbが作成されます。
作成された kaminari_config.rbを見るとこのようなコードが書かれていると思います。

Kaminari.configure do |config|
  # config.default_per_page = 25
  # config.max_per_page = nil
  # config.window = 4
  # config.outer_window = 0
  # config.left = 0
  # config.right = 0
  # config.page_method_name = :page
  # config.param_name = :page
end

ここでkaminariのデフォルトの設定を変更できます。 色々ありますが、1つずつ見ていきましょう。 config.default_per_page
→1ページ辺りの項目数を変更できます。
config.max_per_page
→1ページ辺りの最大数を変更できます。
config.window
→現在のページから、左右何ページ分のリンクを表示させるかを変更できます。
config.outer_window
→最初(First)と最後(Last)のページから、左右何ページ分のリンクを表示させるかを変更できます。
config.left
→最初(First)のページから、何ページ分のリンクを表示させるかを変更できます。
config.right
→最終(Last)ページから、何ページ分のリンクを表示させるかを変更できます。
config.page_method_name
→モデルに追加されるページ番号を指定するスコープの名前を変更できます。
config.param_name = :page
→ページ番号を渡すために使用するパラメータ名を変更できます。

kaminari_config.rbではこのような色々なデフォルトの設定を変更することができます。
今回は1ページに表示するレコードを10件に変更したいので、

 config.default_per_page = 10

というふうに変更することで1ページに表示するレコードを10件に変更することができます。

まとめ

ここまでページネーションを簡単に実装することができるGemkaminariについて、使い方を自分なりにまとめてみました。
ページネーションは何度も実装するものでは無いかもしれませんが、忘れてしまわないようにブログにまとめることで、整理することができました。
ここまで読んでいただき、ありがとうございました。