検索機能は必須機能ではないですがあると便利ですね!
テックキャンプの備忘録です!
目的
- ルーティングのcollectionとmemberを理解
- 検索に必要なメソッドを理解
seachアクションのルーティング設定
collectionとmember
ルーティングを設定する際に使用でき、生成されるルーティングのURLと実行されるコントローラを任意でカスタムできる
ルーティングに:id
がつくかつかないかの違い
config/routes.rb
Rails.application.routes.draw do
devise_for :users
root to: 'tweets#index'
resources :tweets do
resources :comments, only: :create
collection do
get 'search'
end
end
resources :users, only: :show
end
検索フォーム作成
app/views/tweets/index.html.erb
<%= form_with(url: search_tweets_path, local: true, method: :get, class: "search-form") do |form| %>
<%= form.text_field :keyword, placeholder: "投稿を検索する", class: "search-input" %>
<%= form.submit "検索", class: "search-btn" %>
<% end %>
検索のメソッドをモデルで定義
ビジネスロジック
データに対する処理などを行うプログラム処理
「データをどのように処理するのか」
「どのデータを取得するのか」
「どのような手順で処理をしていくのか」 など指す。
whereメソッド
ActiveRecordメソッドの一つ
モデル.where(条件)
のように、引数部分に条件を指定することで、テーブル内の「条件に一致したレコードのインスタンス」を配列で取得できる
モデル.where('検索対象となるカラムを含む条件式')
LIKE句
曖昧な文字列の検索をするときに使用 whereと一緒に
class Tweet < ApplicationRecord
validates :text, presence: true
belongs_to :user
has_many :comments
def self.search(search)
if search != ""
Tweet.where('text LIKE(?)', "%#{search}%")
else
Tweet.all
end
end
end
引数のsearchは、検索フォームから送信されたパラメータが入るため、
if search != ""
と記述し、検索ふぉーむに何かが入力されていた場合を条件としています。
もし検索ふぉーむに何も入力をせずに検索ボタンを押すと、引数で渡されるsearchの中身は空になります
この場合elseに該当し、Tweet.all
という記述は、その時全ての投稿を取得して表示するためのもの
テーブルとのやりとりに関するメソッドはモデルに置く という意識が必要
searchアクションをコントローラーに定義
~略~
before_action :move_to_index, except: [:index, :show, :search]
~略~
def search
@tweets = Tweet.search(params[:keyword])
end
~略~
Tweetモデルに書いたsearchメソッドを呼び出し、
seachメソッドの引数にparams[:keyword]と記述して、検索結果を渡す
未ログイン時に検索するとトップページにリダイレクトされるのでbefore_actionのexceptオプションに:search
追加
検索結果のビュー作成
app/views/tweets/search.html.erbを作成
<%= form_with(url: search_tweets_path, local: true, method: :get, class: "search-form") do |form| %>
<%= form.text_field :keyword, placeholder: "投稿を検索する", class: "search-input" %>
<%= form.submit "検索", class: "search-btn" %>
<% end %>
<div class="contents row">
<% @tweets.each do |tweet| %>
<%= render partial: "tweet", locals: { tweet: tweet } %>
<% end %>
</div>