POSO
@POSO

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

ruby on railsに関して、ransackを使ったactiverecordの検索について

解決したいこと

解決したいこと
ransackを使ったサッカー選手検索機能を実装中です。
キーワードでの検索は成功するのですがactiverecordの検索ができません
フォームデータの送信はうまく行っているのですが、そこから先がわからないです。

発生している問題・エラー

<%= search_form_for @q, url: search_items_path do |f| %>
<%= f.label :name_cont, '選手検索' %>
<%= f.search_field :name_cont %>
<% f.label :category_id %>
<%= f.collection_select(:category_id, Category.all, :id, :name, {}, {class:"select-box", id:"category"}) %>
<% f.label :country_id %>
<%= f.collection_select(:country_id, Country.all, :id, :name, {}, {class:"select-box", id:"country"}) %>
<br>
<%= f.submit '検索' %>
<% end %>

これが問題のコードです
nameのみにキーワードを入れた場合

Parameters: {"q"=>{"name_cont"=>"メッシ", "category_id"=>"0", "country_id"=>"0"}, "commit"=>"検索"}

こうなって検索に成功しますが、activerecordからキーワードを入れた場合

Parameters: {"q"=>{"name_cont"=>"", "category_id"=>"1", "country_id"=>"0"}, "commit"=>"検索"}

この場合検索に失敗します
カテゴリーのみ入れた時の検索と、文字を何も入れずに検索した時の挙動が同じです
そのためカテゴリーidを受け取るための何かが欠けているのだと思います
全てのactiverecordに_contをつけた場合、nameにキーワードをれても検索に失敗します
modelは
itemが

class Item < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :category
belongs_to :minicategory
belongs_to :brand
end

categoryが

class Category < ActiveHash::Base
include ActiveHash::Associations
has_many :items

self.data = [
{ id: 0, name: 'カテゴリー選択' },
{ id: 1, name: 'キーパー' },
{ id: 2, name: 'ストライカー' },
]
end

よろしくお願いします

追記:コントローラーは

def search
    @results = @q.result
  end

  private

  def search_player
    @q = Player.ransack(params[:q])
  end

です

0

3Answer

読んでも何が起きているのかよく伝わりません。

「DBにどんなデータが入っていて」、「どんなパラメーターを受け取って」(これは記述されてます)、「どんなクエリを発行し」「期待される結果は何で」、「実際の結果は何なのか」、「(欲を言えば)どんなSQLが発行されたのか」、など、回答者が問題を正しく理解できる質問をするべきです。

良い質問とは何か、についてはstackoverflowを参考にすると良いでしょう。
https://stackoverflow.com/help/how-to-ask

0Like

Comments

  1. @POSO

    Questioner

    DBにどんなデータが入っていて→この場合選手(player)にid,name,category_id,country_idがあります。categoryとcountryはactiverecordで実装しています。
    期待される結果は何で、期待される結果は何か→この場合parameterのnameが空で、countryまたはcategoryの数値がある場合、countryが合致しているものを表示します。name、category、countryのどれかが合致していれば表示するとしたいため、部分一致だと思います。
    これでお願いします(クエリと発行されたSQLはわかりませんでした。
  2. @POSO

    Questioner

    追加情報ですが
    _idは Integer型カラムです、
  3. 少なくともcontrollerの実装は可能な範囲で掲載した方が良いと思います。また、質問として欠かせない情報なので、こちらへの返信ではなく質問内容をアップデートした方が良さそうです。

    ransakを触ったのが大分昔のうえで、今ある報からの推測ですが、or検索ではなくand検索になってないか、ということを疑います。まずはransakのto_sqlというメソッドで期待どおりのsqlになっているか確認してみると良いと思います。

    追記:
    そもそもcategory_idとcountry_idが、ransak検索に必要なPredicateを含んでいなくないですか?

    https://github.com/activerecord-hackery/ransack#search-matchers
  4. @POSO

    Questioner

    追記いたしました
  5. @POSO

    Questioner

    「category_idとcountry_idが、ransak検索に必要なPredicateを含んでいない」
    _contなどを追記し実行しましたが、期待される結果を表示しませんでした。また、_idにcontをつけると上記の通りnameのみに入力して検索しても結果なし、と表示されます。
  6. @POSO

    Questioner

    Parameters: {"q"=>{"name_cont"=>"メッシ", "category_id_cont"=>"0", "country_id_cont">"0"}, "commit"=>"検索"}
    この場合、何も表示されない(contをidにつけない場合普通に表示される)という意味です
  7. > or検索ではなくand検索になってないか、ということを疑います。まずはransakのto_sqlというメソッドで期待どおりのsqlになっているか確認してみると良いと思います

    こちらは確認しましたか?
  8. @POSO

    Questioner

    _eqにすることでidが一緒の場合検索に成功することが確認できました。
    よって
    Parameters: {"q"=>{"name_cont"=>”メッシ”, "category_id_eq"=>"1", “country_id_eq"=>”1”}, "commit"=>"検索"}

    "name_cont"=>””の場合
    Parameters: {"category_id_eq"=>"1", “country_id_eq"=>”1”}, "commit"=>"検索"}

    "category_id_eq"=>”0”の場合
    {"q"=>{"name_cont"=>”メッシ”, “country_id_eq"=>”1”}, "commit"=>"検索"}

    というように選択した数値が特定の数(この場合は0)またはnameに何も入力していない場合そのパラメータを送信しないという設定にすればうまくいくと思いますが、このコードのイメージがうまくつきません

Parameters: {"q"=>{"name_cont"=>”メッシ”, "category_id_eq"=>"1", “country_id_eq"=>”1”}, "commit"=>"検索"}

or検索をしたかったんじゃないのですか?

name、category、countryのどれかが合致していれば表示するとしたいため、部分一致だと思います

そもそも生のSQLを見せていただけたら話は早かったのに、頑なにto_sqlの結果を載せないのは何故なんでしょうか。もっと回答者の時間を尊重してください。

and検索でよく、falsyな値を検索対象から落としたいのであれば、シンプルにparams[:q]からfalsyな値を落としたパラメータをransackに渡せば良いと思います。

Player.ransack(params[:q])
0Like

This answer has been deleted for violation of our Terms of Service.

Your answer might help someone💌