6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】ransackを用いた、ほんのすこし複雑な検索条件(delegate)

Last updated at Posted at 2023-12-11

注記
この記事の投稿者はRuby on Rails初学者であり、自身の学習の備忘録目的で記事投稿を行なっております。
情報の正確さには最大限注意をしておりますが、もし誤り等がございましたらお知らせいただけますと幸いです。

Ruby on Rails初学者です。
学習の一環として簡単な記事投稿アプリを作成しています!

記事投稿の経緯

gem 'ransack'を導入して、検索フォームを作成していたところエラーが発生したのですが、ransackのおかげで解消できたので備忘録として。

モデルの内容

ユーザー(user)は複数の投稿(post)をすることができます。
つまり、usersテーブルとpostテーブルは一対多のアソシエーションを設定しています。

ここで少し注意していただきたい点があります。
usersテーブルはnameカラムを持っておらず、profilesテーブルがnameを持っている点です。
(Usersモデルをスッキリとさせるために使用しています)

モデル

user.rb
class User < ApplicationRecord
  has_one :profile, dependent: :destroy
  has_many :posts, dependent: :destroy # postsテーブルとのアソシエーション
  validates :email, uniqueness: true, presence: true
  validates :password, presence: true, length: { minimum: 8 }, confirmation: true
  delegate :name, to: :profile # Profileモデルのnameメソッドを呼び出し
end
post.rb
class Post < ApplicationRecord
  belongs_to :user # usersテーブルとのアソシエーション
  has_many :comments, dependent: :destroy
  has_many :taggings, dependent: :destroy
  has_many :tags, through: :taggings

  validates :title, presence: true
  validates :body, presence: true
end
profile.rb
class Profile < ApplicationRecord
  belongs_to :user # usersテーブルとのアソシエーション
  validates :name, presence: true
end

Userモデルでは、profilesテーブルが持っているnameカラムを、delegate :nameを使って呼び出すことができます。
このUsersモデルをすっきりさせるためのdelegate実装が、のちに悲劇を生むのであった・・・

どんな問題が発生したのか

ransackを用いて、記事を書いたユーザー名で記事を検索可能な検索フォームを作成しました。

_search_form.html.erb
<%= search_form_for @q, url: posts_path do |f| %>
  <%= f.search_field :user_name_cont, placeholder: "ユーザー" %>
  <%= f.submit "Search" %>
<% end %>

views/posts /index.html.erbで呼び出したところ、NoMethodErrorが発生してしまった。

37b7558700d3a1fcbd899ee0da092a63.png

なぜエラーが発生したのか

エラーの意味を調べたところ、
「Ransackの検索フォームで使用されている検索条件 user_name_contPostモデルに存在しないよ」というエラーのようです。

つまりエラーの原因は
nameというカラムはusersテーブルに存在していないのに
user_name_contという検索条件で値を取得しようとしたこと」にあります。

前述の通り、nameカラムはusersテーブルではなくprofilesテーブルに存在しており、
delegateを通してprofilesテーブルから呼び出しています。

これで解決

検索条件をuser_name_contからuser_profile_name_contとすることで、検索機能が意図した動作をするようになりました。

_search_form.html.erb
<%= search_form_for @q, url: posts_path do |f| %>
  <%= f.search_field :user_profile_name_cont, placeholder: "ユーザー" %>
  <%= f.submit "Search" %>
<% end %>

:user_profile_name_contUserモデルを経由してProfileモデルのname属性を検索するためのransackの検索キーです。
ransackでは、今回のように関連モデルを通じた検索をすることが可能です。
便利ですね。
ただし、しっかりとテーブル同士のアソシエーションが設定できている必要があるので、実装の際には慎重に確認する必要がありそうです!

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?