ransackを使った検索機能

gemransackを用いると、簡単に検索機能を追加できる

導入

gem 'ransack'

$ bundle install

これでransackのインストールは完了

コントローラーの編集

検索するためのアクションを追加します。検索した結果を表示するために新たにsearchアクションを追加する。

Rails.application.routes.draw do
  resources :users do
    collection do
      get 'search'
    end
  end
end

このような形でcollectionを使って、/users/searchのURLでsearchアクションを拾えるようにする。

コントローラに検索を行うための記述をする。 検索結果を取得するコードをprivate以下にメソッド化し、before_actionで呼び出す。そして、searchアクションを定義する。

class UsersController < ApplicationController
  before_action :set_q, only: [:index, :search]

  def search
    @results = @q.result
  end

  private

  def set_q
    @q = User.ransack(params[:q])
  end
用語 説明
params[:q] この後に作成するビューファイルから送られてくるパラメーター
ransackメソッド 送られてきたパラメーターを元にテーブルからデータを検索するメソッド
resultメソッド ransackメソッドで取得したデータをActiveRecord_Relationのオブジェクトに変換するメソッド

検索フォームの作成

ビューファイルに検索フォームの作成をしていく。

<h1>ユーザー検索</h1>
<%= search_form_for @q, url: search_users_path do |f| %>
  <%= f.label :name_cont, 'ユーザー名' %>
  <br>
  <%= f.submit '検索' %>
<% end %>

search_form_forというform_withのようなメソッドがransackに用意されているのでそれを使う。

_contは検索したいカラム名を前に入れると、検索したいカラムに対してあいまい検索がされる。完全一致の場合_eqがある。

検索結果が表示されるビューを作成

<h1>検索結果</h1>
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th>Height</th>
      <th>Weight</th>
      <th>Gender</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @results.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.age %></td>
        <td><%= user.height %></td>
        <td><%= user.weight %></td>
        <td><%= user.gender %></td>
        <td><%= link_to 'Show', user %></td>
        <td><%= link_to 'Edit', edit_user_path(user) %></td>
        <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= link_to 'Top', users_path %>

<% @results.each do |user| %>の部分で結果をもとに繰り返し表示させている。

参考

https://pikawaka.com/rails/ransack

jsの$()とか#とか

課題17

$("#error_messages").remove()

まず、このコードを細かく見ていく。"#error_messages"は、idがerror_messagesのものを対象とする、という意味で、removeは外すという意味なので、idがerror_messagesの表示があれば削除してくださいね、ということになる。これがないとどんどんエラーメッセージが溜まってしまう。

<% if @comment.errors.present? %>
   $("#new_comment").prepend("<%= j(render('shared/error_messages', object: @comment)) %>")
 <% else %>
   $("#js-table-comment").prepend("<%= j(render('comments/comment', comment: @comment)) %>")
   $("#js-new-comment-body").val('')
 <% end %>

少し長いけど、きちんと理解できるようにする。 一行目は、@commentにエラーがあるかどうかで分岐させている。エラーがあればtrue,なければfalseで分岐。

trueなら、idがnew_commentを対象にして、prepend(対象の前に挿入する)をしている。prependの中身は(" ")で囲んでいるので文字列にしている。erbなので、<%= %>で呼び出している。

j()ActionView::Helpers::JavaScriptHelper#escape_javascriptエイリアス。改行コード、シングルクォート、ダブルクォートをJacaScript用にエスケープしてくれる。エスケープとは、プログラム内で使用できない文字を、大体の文字に置き換えること。

render('shared/error_messages',object: @comment)では、sharedディレクトリの_error_messages.html.erbを呼び出す。その際にobjectを@commentに置き換えて呼び出す。

falseの場合、elseが処理されるので、$("js-table-comment")を対象として、その先頭に("<%= j(render('comments/comment', comment: @comment)) %>")を呼び出す。ということになる。

$("#js-new-comment-body").val('')は、idがjs-new-comment-bodyの値を''にするという動きをする。

参考

https://qiita.com/mm36/items/684f36f22e79d0a27ae9

paginateとkaminari

paginateってなんだ?

ページ下部にある123とかってやつ。これを実装するために、kaminariというgemをインストールする。

実装

gem 'kaminari'
$ bundle instal

これでkaminariを使えるようになった。どう実装するのか。

rails g kaminari:config

でkaminariのコンフィグを作る。そうすると、config/initializers/kaminari

# frozen_string_literal: true

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
  # config.max_pages = nil
  # config.params_on_first_page = false
end

とできるので、自由にいじる。

controllerに追加

ページネーションを追加したいアクションにpage(params[:page])を追加する。app/controller/boards

def index
  @boards = Board.all.page(params[:page])
end

として、表示したいview、今回はapp/views/boards/index.html.erb

<%= paginate @boards %>

と書き込むと、ページネーションが表示されるようになる。

ページネーションの見た目

見た目を変えるために

$ rails g kaminari:views bootstrap4

ってすると見た目が変わり、よきよきになる。

参考

https://www.autovice.jp/articles/139 https://qiita.com/rio_threehouse/items/313824b90a31268b0074

testを作る際のsetupメソッドとは

setupメソッドとは

testを作る際に、

def setup
  @user = User.new(name:"hoge",nickname:"fuga")
end

などとしてsetupメソッドを定義することがある。このsetupメソッドは、他のテストが実行される前にかならず実行されるものになっていて、他のテストの中で、@userを使うこともできるようになっている。

参考

https://qiita.com/ryouya3948/items/b8df22ea8f2507b72eae

findとfind_byの違い

Userのidが1のデータがあると仮定する。

User.find(1)

User.find_by(id: 1)

では同じようにUserのidが1のデータを取ってくるが、存在しないUserのidが2のデータを取ってこようとすると、

User.find(2)  # => errorが出る。

User.find_by(id: 2)  # => nilを返す。

という違いがある。

blank?メソッド

空文字" "を認識してくれるメソッド。Rubyには搭載されておらず、RailsRubyっぽいメソッドとして準備してくれているもの。 空文字かどうか判別するのにempty?メソッドもあるが、これは、" "この文字列はfalseを返すため、blank?と挙動が少し異なる。

test assert_selectメソッドについて

testで使うassert_selectメソッドは特定のHTMLタグが存在するかどうかをテストしてくれます。「セレクタ」と呼ばれることもあります。

assert_select "title","Home | Sample App"

と書くと、titleタグ内にHome | Sample Appという文字列があるかどうかをチェックします。