注記
この記事の投稿者はRuby on Rails初学者であり、自身の学習の備忘録目的で記事投稿を行なっております。
情報の正確さには最大限注意をしておりますが、もし誤り等がございましたらお知らせいただけますと幸いです。
Ruby on Rails初学者です。
学習の一環として簡単な記事投稿アプリを作成しています!
記事投稿の経緯
gem 'ransack'
を導入して、検索フォームを作成していたところエラーが発生したのですが、ransack
のおかげで解消できたので備忘録として。
モデルの内容
ユーザー(user
)は複数の投稿(post
)をすることができます。
つまり、users
テーブルとpost
テーブルは一対多のアソシエーションを設定しています。
ここで少し注意していただきたい点があります。
users
テーブルはname
カラムを持っておらず、profiles
テーブルがname
を持っている点です。
(Users
モデルをスッキリとさせるために使用しています)
モデル
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
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
class Profile < ApplicationRecord
belongs_to :user # usersテーブルとのアソシエーション
validates :name, presence: true
end
User
モデルでは、profiles
テーブルが持っているname
カラムを、delegate :name
を使って呼び出すことができます。
このUsers
モデルをすっきりさせるためのdelegate
実装が、のちに悲劇を生むのであった・・・
どんな問題が発生したのか
ransack
を用いて、記事を書いたユーザー名で記事を検索可能な検索フォームを作成しました。
<%= 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
が発生してしまった。
なぜエラーが発生したのか
エラーの意味を調べたところ、
「Ransackの検索フォームで使用されている検索条件 user_name_cont
がPost
モデルに存在しないよ」というエラーのようです。
つまりエラーの原因は
「name
というカラムはusers
テーブルに存在していないのに
user_name_cont
という検索条件で値を取得しようとしたこと」にあります。
前述の通り、name
カラムはusers
テーブルではなくprofiles
テーブルに存在しており、
delegate
を通してprofiles
テーブルから呼び出しています。
これで解決
検索条件をuser_name_cont
からuser_profile_name_cont
とすることで、検索機能が意図した動作をするようになりました。
<%= search_form_for @q, url: posts_path do |f| %>
<%= f.search_field :user_profile_name_cont, placeholder: "ユーザー" %>
<%= f.submit "Search" %>
<% end %>
:user_profile_name_cont
はUser
モデルを経由してProfile
モデルのname
属性を検索するためのransack
の検索キーです。
ransack
では、今回のように関連モデルを通じた検索をすることが可能です。
便利ですね。
ただし、しっかりとテーブル同士のアソシエーションが設定できている必要があるので、実装の際には慎重に確認する必要がありそうです!