🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

Q&A

解決済

2回答

1649閲覧

部分一致でユーザー検索をかけたが、完全一致で認識されてしまう。

punchan36

総合スコア105

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

0グッド

0クリップ

投稿2021/03/11 00:52

編集2021/03/18 03:23

前提・実現したいこと

ユーザー検索機能を実装しています。ユーザー名や性別などに加え、「ユーザーが話せる言語」でも絞り込みをかけています。

ユーザーは自分が話せる言語をプロフィール編集画面(users/edit.html.erb)で選択出来ます(複数可)。こちらの機能は既にユーザー・言語間を多対多の関係で実装済みです。

以下がつまずいている点なのですが、例えばユーザーがそれぞれ以下の言語を話せるとします。

  • ユーザーA: 日本語
  • ユーザーB: 日本語、英語
  • ユーザーC: 日本語、英語、中国語

「日本語」のみを選択し検索した場合、日本語を話せるA, B, C全員をヒットさせたかったのですが、現状ユーザーAだけがヒットします。「日本語のみを話せるのはユーザーAのみです」と認識されてしまっているようです。

同様に「英語、中国語」を選択すると、該当のユーザーがいない場合の処理が動いてしまいます。どちらも話せるユーザーCをヒットさせたかったのですが、「英語、中国語のみを話せるユーザーはいません」と認識されているようです。

該当のソースコード

users/index.html.erb

<%= form_with url: users_path, method: :get, local: true do |f| %> <p>User name</p> <%= f.search_field :name, :value => params[:name] %> <p>Keyword</p> <%= f.search_field :introduction, :value => params[:introduction] %> <p>Gender</p> <%= f.radio_button :gender, "Male", :checked => params[:gender] == ("Male") %>Male <%= f.radio_button :gender, "Female", :checked => params[:gender] == ("Female") %>Female <p>Languages</p> <%= f.check_box :language_ids, {multiple: true, :checked => params[:language_ids]&.include?("1")}, "1", false %>Japanese <%= f.check_box :language_ids, {multiple: true, :checked => params[:language_ids]&.include?("2")}, "2", false %>English <%= f.check_box :language_ids, {multiple: true, :checked => params[:language_ids]&.include?("3")}, "3", false %>Chinese <%= f.submit :search, :class => "btn-square-little-rich" %> <% end %>

users_controller.rb

def index if params[:name].present? || params[:introduction].present? || params[:gender].present? || params[:language_ids].present? @users = User.where(['name LIKE ? AND introduction LIKE ? AND gender LIKE ? AND language LIKE ?', "%#{params[:name]}%", "%#{params[:introduction]}%", "#{params[:gender]}%", "%#{params[:language_ids]}%"]) .page(params[:page]).per(20) else # ユーザーが何も入力しなかった場合。 @users = User.all.order(created_at: :desc).page(params[:page]).per(20) end if @users == [] # 該当のユーザーが存在しなかった場合。 flash[:notice] = "User was not found" @users = User.all.order(created_at: :desc).page(params[:page]).per(20) end end

試したこと

"%#{params[:language_ids]}%"のように% %で挟む事で部分一致にしたつもりだったのですが、なぜか上手くいきません。

英語(id: 2)、中国語(id: 3)で検索した場合、ログは以下の様に出力されます。

Parameters: {"utf8"=>"✓", "name"=>"", "introduction"=>"", "language_ids"=>["2", "3"], "commit"=>"search"}

各ユーザーの言語情報は以下の様に保存されておりましたので、なぜこれでユーザーCがヒットにならないのかが分かりません…。

[27] pry(main)> User.find(1).language_ids User Load (4.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 (4.9ms) SELECT `languages`.`id` FROM `languages` INNER JOIN `user_languages` ON `languages`.`id` = `user_languages`.`language_id` WHERE `user_languages`.`user_id` = 1 => [1] [28] pry(main)> User.find(2).language_ids User Load (0.7ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1 (0.8ms) SELECT `languages`.`id` FROM `languages` INNER JOIN `user_languages` ON `languages`.`id` = `user_languages`.`language_id` WHERE `user_languages`.`user_id` = 2 => [1, 2] [29] pry(main)> User.find(3).language_ids User Load (2.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1 (2.3ms) SELECT `languages`.`id` FROM `languages` INNER JOIN `user_languages` ON `languages`.`id` = `user_languages`.`language_id` WHERE `user_languages`.`user_id` = 3 => [1, 2, 3]

どなたかご助言を頂けますと有難いです。

補足情報(FW/ツールのバージョンなど)

ruby 2.6.4p104
RubyGems 3.0.3
Rails 5.2.3

【追記】

モデル関連

user.rb

class User < ApplicationRecord has_many :user_languages, dependent: :destroy has_many :languages, through: :user_languages end

language.rb

class Language < ApplicationRecord has_many :user_language has_many :users, through: :user_language end

user_language.rb

class UserLanguage < ApplicationRecord belongs_to :user belongs_to :language end

テーブル情報

schema.rb

ruby

1ActiveRecord::Schema.define(version: 2021_03_11_063016) do 2 create_table "languages", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| 3 t.string "description" 4 t.boolean "done" 5 t.bigint "user_id" 6 t.datetime "created_at", null: false 7 t.datetime "updated_at", null: false 8 t.index ["user_id"], name: "index_languages_on_user_id" 9 end 10 11 create_table "user_languages", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| 12 t.bigint "user_id" 13 t.bigint "language_id" 14 t.datetime "created_at", null: false 15 t.datetime "updated_at", null: false 16 t.index ["language_id", "user_id"], name: "index_user_languages_on_language_id_and_user_id", unique: true 17 t.index ["language_id"], name: "index_user_languages_on_language_id" 18 t.index ["user_id"], name: "index_user_languages_on_user_id" 19 end 20 21 create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| 22 t.string "name" 23 t.datetime "created_at", null: false 24 t.datetime "updated_at", null: false 25 t.string "gender" # "sex" から "gender" に変更しました。 26 t.string "language" 27 t.text "introduction" 28 end 29 30 add_foreign_key "languages", "users" 31 add_foreign_key "user_languages", "languages" 32 add_foreign_key "user_languages", "users" 33end

ログ関連

以下の言語を話せるユーザーに関する language 情報を確認したログを追記致しました。

  • ユーザーA(id: 1): 日本語
  • ユーザーB(id: 2): 日本語、英語
  • ユーザーC(id: 3): 日本語、英語、中国語
[36] pry(main)> User.find(1).language User Load (33.1ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 => "[\"1\"]" [37] pry(main)> User.find(2).language User Load (1.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1 => "[\"1\", \"2\"]" [38] pry(main)> User.find(3).language User Load (20.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1 => "[\"1\", \"2\", \"3\"]"

/ (コマンド上では ) が表示されていました。ここに問題があったのでしょうか…。

winterboumさまにご提示頂いたコードで検索した際のログ

以下のユーザーしか存在しない中で「英語」のみで検索した所、誰もヒットしませんでした。

  • ユーザーA(id: 1): 日本語
  • ユーザーB(id: 2): 日本語、英語
  • ユーザーC(id: 3): 日本語、英語、中国語
Parameters: {"utf8"=>"✓", "name"=>"", "language_ids"=>["2], "introduction"=>"", "commit"=>"search"} User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1 ↳ app/controllers/application_controller.rb:9 User Load (0.8ms) SELECT `users`.* FROM `users` WHERE (name LIKE '%%' AND introduction LIKE '%%' AND gender LIKE '%') AND `users`.`language` = '2' LIMIT 20 OFFSET 0 ↳ app/controllers/users_controller.rb:34 Rendering users/index.html.erb within layouts/application User Load (2.4ms) SELECT `users`.* FROM `users` ORDER BY `users`.`created_at` DESC LIMIT 20 OFFSET 0 ↳ app/views/users/index.html.erb:40 Rendered users/index.html.erb within layouts/application (38.4ms) CACHE User Load (0.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1 [["id", 2], ["LIMIT", 1]] ↳ app/views/layouts/application.html.erb:48 (0.7ms) SELECT COUNT(*) FROM `notifications` WHERE `notifications`.`visited_id` = 2 AND `notifications`.`checked` = FALSE AND `notifications`.`action` = 'message' ↳ app/helpers/notifications_helper.rb:54 (0.8ms) SELECT COUNT(*) FROM `notifications` WHERE `notifications`.`visited_id` = 2 AND `notifications`.`action` != 'message' AND `notifications`.`checked` = FALSE ↳ app/helpers/notifications_helper.rb:48 Completed 200 OK in 342ms (Views: 304.0ms | ActiveRecord: 5.3ms)

追記2

【検索の仕様に関して】
仕様と致しましては、検索された言語(複数可)を「全てを含んだ」ユーザーをヒットさせたいです。

  • ユーザーA: 日本語
  • ユーザーB: 日本語、英語
  • ユーザーC: 日本語、英語、中国語

例えば上記のユーザーがいた場合、
①「日本語」で検索 → A, B, C全員をヒットさせたい。
②「日本語、英語」で検索 → B, Cをヒットさせたい。
③「英語、中国語」で検索 → Cのみをヒットさせたい。

※完全一致ではない。
「日本語」でユーザー検索 → 完全一致ですと「日本語のみ」を話せるユーザーAだけがヒットすると思いますが、実装したいのはこちらの機能ではありません。

※部分一致でもない。
「日本語、英語」でユーザー検索 → 部分一致ですと「日本語または英語のどちらか」を話せるユーザーA, B, Cの全てがヒットすると思いますが、実装したいのはこちらの機能でもありません。

名前や性別を含んだ検索でも同様に、検索された文言を「全て含んだ」ユーザーをヒットさせたいです。

  • 名前:(指定なし)
  • 性別:Male
  • 言語:日本語、中国語
  • キーワード:hoge

例えば上記の条件で検索した場合:
男性で、かつ日本語・中国語をともに話せ(それ以上話せても可)、かつ自己紹介欄に「hoge」の文言を含むユーザーをヒットさせたいです(名前は問わない。[]と言う名前と言う訳ではない)。

最終的に解決したコード

users_controller.rb

ruby

1@users = User.all.order(created_at: :desc).page(params[:page]).per(20) 2 3if params[:language_ids].present? 4 @users = @users.select("users.*, COUNT(*) AS languages_count") 5 .joins(:user_languages) 6 .where(user_languages: { language_id: params[:language_ids] }) 7 .group("user_languages.user_id") 8 .having("languages_count = #{params[:language_ids]&.length}") 9end 10 11if params[:name].present? || params[:gender].present? || params[:introduction].present? 12 @users = @users.where(['name LIKE ? AND gender LIKE ? AND introduction LIKE ?', 13 "%#{params[:name]}%", "#{params[:gender]}%", "%#{params[:introduction]}%"]) 14end 15 16if @users == [] 17 # 該当のユーザーが存在しなかった場合。 18 flash[:notice] = "User was not found" 19 @users 20end

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2021/03/11 00:56

>各ユーザーの言語情報は以下の様に保存されていると思いますので、 「思う」ではなくデータの実態を確認してください。
punchan36

2021/03/11 01:11

失礼致しました。rails c で確認した内容を元に編集致しました。
m.ts10806

2021/03/11 02:24

いえ、そうではなく、実際のデータの中身を、直接コマンドかDBアクセスツールで
m.ts10806

2021/03/11 02:24

※いずれにしてもテーブル定義とモデル定義提示されないと答えようがない部分ではありますが
neko_daisuki

2021/03/11 07:00

Userテーブルにlanguageというカラムがあるのでしょうか? ログを見ると User has_many :languages, through: :user_languages となってるように見えるのですが、それとは別にカラムがあるのなら、 User.find(1).language の値の追記をお願いします。
punchan36

2021/03/11 07:57

有難うございます。 複数のテーブルでアソシエーションを組んでおりましたので、モデル、テーブル等の情報を追記致しました。
guest

回答2

0

ベストアンサー

それぞれの language カラムに保存されている"文字列"

ユーザーA: ["1"]
ユーザーB: ["1", "2"]
ユーザーC: ["1", "2", "3"]

検索する文字列 %["1"]% では、ユーザーA しかマッチしません。

一般に、string のカラムに配列っぽいものを格納して検索するのは上手くいきません。
パフォーマンスの問題もあります(%からはじまるLIKEの検索はインデックスが効かない)。

以下のようにすれば関連先を読み込んで絞り込めます

ruby

1# params[:language_ids] == ["1", "2"] 2@users = User.joins(:languages).where(languages: { id: params[:language_ids] }) 3# これを絞り込むこともできる 4@users = @users.where("name LIKE ?", "%#{params[:name]}%")

発行されるSQL

sql

1SELECT `users`.* FROM `users` 2 INNER JOIN `user_languages` ON `user_langages`.`user_id` = `users`.`id` 3 INNER JOIN `languages` ON `languages`.`id` = `user_languages`.`language_id` 4 WHERE `languages`.`id` IN (1, 2)

追記

いまテーブルが用意できないので確認できないのですが、これでどうでしょう

ruby

1User.select("users.*, COUNT(*) AS languages_count") 2 .joins(:user_languages) 3 .where(user_languages: { language_id: params[:language_ids] }) 4 .group("user_languages.user_id") 5 .having(languages_count: params[:language_ids].length)

1.中間テーブルの language_id が params[:language_ids] に含まれるものに絞り込む
2.中間テーブルのuser_idでグループ化してその数をカウント(ユーザーごとの一致したlanguage数)
3.カウントがparams[:language_ids]の数と一致するか(完全に含むか)で絞り込む

という動作にしているつもりです。

投稿2021/03/11 11:56

編集2021/03/12 07:31
neko_daisuki

総合スコア2090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

punchan36

2021/03/12 05:51

有難うございます! @users = User.joins(:languages).where(languages: { id: params[:language_ids] }).page(params[:page]).per(20) 上記のコードですと、「日本語、中国語」で検索をかけると以下のユーザーがヒットしました。 ・ユーザーA: 日本語 ・ユーザーB: 日本語、英語 ・ユーザーC: 日本語、英語、中国語 ・ユーザーC: 日本語、英語、中国語 今度は「日本語、中国語のいずれか」を話せるユーザーを検索してしまったようです。 更に該当する言語数の分だけユーザーが表示されてしまいました(ユーザーCは2回)。これは distinct メソッドを用いて改善されましたが… いずれにせよ、日本語・中国語を「含む」言語を話せるユーザーと言う意味合いで、何とかユーザーCだけヒットさせられるような記述は出来ないものでしょうか…。方法が思いつきませんでした。。
neko_daisuki

2021/03/12 14:46

追記で仕様に沿ってるつもりなのですがうまく動きませんか?
punchan36

2021/03/16 09:09

返信が遅くなり大変申し訳ありません。 ご教示頂いたコードで言語検索を試すと、以下のエラーが出ました。 Mysql2::Error: Unknown column 'users.languages_count' in 'having clause' 外部キーに languages_count を指定していないのが原因(?)と思い、foreign_key: "languages_count" を指定するなど試してみましたが、今度は下記のエラーメッセージが出ました。 Mysql2::Error: Unknown column 'user_languages.languages_count' 調べた所外部キー周りが怪しいと思ったのですが、原因は別にあるのでしょうか…。 こちらのページ等を参考に考えました。 http://enjoy-programing.com/rails%E3%81%A7%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E7%B5%90%E5%90%88%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%8F%E3%81%A6%E3%83%8F%E3%83%9E%E3%81%A3%E3%81%9F%E4%BB%B6/
neko_daisuki

2021/03/16 15:08

ごめんなさい。having をハッシュで指定するとダメみたいです。 .having("languages_count = #{params[:language_ids].length}") としてみてください。
neko_daisuki

2021/03/16 15:13

having を文字列で指定すると HAVING (languages_count = 3) ハッシュで指定すると(存在しない) HAVING `users`.`languages_count` = 3 この languages_count は select で指定(as)した COUNT に付けた名前です
punchan36

2021/03/17 06:01

有難うございます!ご教示頂いたコードで希望の実装が出来ました…。 今最後に「ユーザー名や性別」等の条件も組み合わせておりまして、言語が選択されている場合の検索は完璧なのですが、言語が未選択の場合のみ以下のエラーが出てしまいます。 Mysql2::Error: You have an error in your SQL syntax; ... AND `user_languages`.`language_id` IS NULL if @users == [] #←エラー発生箇所 # 該当のユーザーが存在しなかった場合。 flash[:notice] = "User was not found" SQLがどうと言うよりは恐らく idsが '' の為に起こったエラーだと思いましたので 「&.length」や 「&& params[:language_ids].nil?」 を付け加えましたが、違うみたいです…。 if params[:name].present? || params[:gender].present? || params[:language_ids].present? || params[:introduction].present? @users = User.where(['name LIKE ? AND gender LIKE ? AND introduction LIKE ?', "%#{params[:name]}%", "#{params[:gender]}%", "%#{params[:introduction]}%"]) .select("users.*, COUNT(*) AS languages_count") .joins(:user_languages) .where(user_languages: { language_id: params[:language_ids] }) .group("user_languages.user_id") .having("languages_count = #{params[:language_ids]&.length}") .page(params[:page]).per(20) else # ユーザーが何も入力しなかった場合。 @users = User.all.order(created_at: :desc).page(params[:page]).per(20) end if @users == [] && params[:language_ids].nil? # 該当のユーザーが存在しなかった場合。 flash[:notice] = "User was not found" @users = User.all.order(created_at: :desc).page(params[:page]).per(20) end 「性別等の条件」と「言語条件」の繋げ方などが悪いのでしょうか…? 長引いてしまい申し訳ありません。
neko_daisuki

2021/03/17 06:16

params[:name].present? || params[:gender].present? || params[:language_ids].present? || params[:introduction].present? だと、params[:language_ids] が空の時でも他の値があれば実行されてしまうので、 @user = User if params[:language_ids].present? @user = @user.select(... end # params[:language_ids] を削除 if params[:name].present? || params[:gender].present? || params[:introduction].present? @user = @user.where(... みたいな感じにすれば良いのではないでしょうか
punchan36

2021/03/17 07:18

有難うございます。 if文を「性別等の条件」と「言語条件」で分けてしまうと、相互間の「且つ」の部分が結びついてない状態に戻ってしまいました。 「言語条件」の @users = User.select(... 以下ですが、こちらが未選択( '' )ですと処理が出来ないのでしょうか?それが出来れば一番シンプルだなと思ったのですが…。 普段「&.メソッド」や「.nil?」などを使用するのですが、それでは効かなかったので疑問に思いました。
neko_daisuki

2021/03/17 16:49

こちらの環境では params[:language_ids] が [] または "" の場合でもエラーが出ません。 centos7 の Server version: 10.5.8-MariaDB MariaDB Server で確認しています。 エラーが出る前の行で binding.pry して @users.to_sql として表示されるものを張り付けてください。 if で条件を付けくわえるやり方だと上手くいかないというのは、 @users = @users.where みたいに、@users に where を繋げてでもでしょうか? (@users = User.where.. if ... @users = User.where.. みたいになってないか)
punchan36

2021/03/18 03:24

if で「性別等の条件」と「言語条件」を分ける方法で全て上手くいきました!私の理解力がなかったにも関わらず、本当に有難うございました…。 上手くいかなかった原因は仰るように @users = User と定義した @users を用いずに @users = User.where.. if.. としていた点でした。 やっている事は同じだと思い定義していなかったのですが、処理の内容が変わる点を見ても明らかに意味合いが違うのですね…? また、 > params[:language_ids] が [] または "" の場合でもエラーが出ません と仰るのは params[:name].present? || params[:gender].present? || params[:language_ids].present? || params[:introduction].present? のように言語条件を他の条件と繋げて処理した場合でもと言う事でしょうか? 最終的に上手く動いたコードは質問文の一番最後に追記致しました!
neko_daisuki

2021/03/18 03:40

検索条件を足していけます @users = Users.where(name: "neko") @users = @users.where(age: 3) # 条件を足す @users = Users.where(name: "tama") # 最初からやり直し User.where(他の条件).group(...).having(...) の形でもエラーは出ませんでした。
punchan36

2021/03/18 05:00

理解出来ました!有難うございます。 if文で条件を足す方法で既に問題は解決致しましたが、前者の方法のエラーがやはり気になります。 params[:name].present? || params[:gender].present? || params[:language_ids].present? || params[:introduction].present? と繋げて条件指定し、params[:language_ids]を未指定にした場合のエラーです。 質問自体は解決致しましたので、もし可能であればご助言頂けますと有難いです! 161: @users = User.all.order(created_at: :desc).page(params[:page]).per(20) 162: end 163: 164: binding.pry => 165: if @users == [] 166: # 該当のユーザーが存在しなかった場合。 167: flash[:notice] = "User was not found" 168: @users 169: end 170: [1] pry(#<UsersController>)> @users.to_sql => "SELECT users.*, COUNT(*) AS languages_count FROM `users` INNER JOIN `user_languages` ON `user_languages`.`user_id` = `users`.`id` WHERE (name LIKE '%%' AND gender LIKE 'Female%' AND introduction LIKE '%%') AND `user_languages`.`language_id` IS NULL GROUP BY user_languages.user_id HAVING (languages_count = ) LIMIT 20 OFFSET 0"
neko_daisuki

2021/03/18 05:36

languages_count = になってますね。 having("languages_count = #{(params[:language_ids]&.length || 0)}") とすればエラーは出ないかもしれません。 でも、言語を何も選択してないユーザーだけを選択するクエリになっちゃいます。
punchan36

2021/03/18 06:00

なるほどです…確かに言語を選択していないユーザーを探す処理になってしまいました。 やはりif文で分けて条件を足す方法が一番無難なのかなと思いました。 重ね重ねにはなりますが、親身にご助言を頂き本当に有難うございました!
guest

0

"%#{params[:language_ids]}%"ですと
language LIKE '%[2, 3]%' の様になります。これでは。。。
idsで来るのでしたら LIKEではなく AND language LIKE の前 の sex LIKE ? で一旦閉じて
where(.....).where(languate: params[:language_ids])でどうでしょう。

蛇足
性別に sex を使う方が多いのですが、違和感があります。genderがベターではと。。。 。

追記

User.joins(:languages) .where(['name LIKE ? AND introduction LIKE ? AND gender LIKE ?', "%#{params[:name]}%", "%#{params[:introduction]}%", "#{params[:gender]}%") .where("languages.id" => params[:language_ids])

最後の1行生SQLにバラさないとだめかもですが、ためして

追記2
この条件ですと私の力では1回では書けないです。
relation =
User.joins(:languages)
.where(['name LIKE ? AND introduction LIKE ? AND gender LIKE ?',
"%#{params[:name]}%", "%#{params[:introduction]}%", "#{params[:gender]}%")
users = params[:language_ids].inject(relation){|rel,id|
rel.where("lanuages.id" => id)
}`
で、users が得られるものかと。

投稿2021/03/11 04:12

編集2021/03/15 10:20
winterboum

総合スコア23567

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

punchan36

2021/03/11 05:08

有難うございます! 以下の様にコントローラを書き換えると、今度は完全一致したユーザーすらもヒットせず、if @users == [] 以降の処理が走ってしまいました…。 where(['name LIKE ? AND introduction LIKE ? AND sex LIKE ?', "%#{params[:name]}%", "%#{params[:introduction]}%", "#{params[:sex]}%"]).where(language: params[:language_ids]) >genderがベターではと。 仰る通りです。。後ほどカラム名から変更しようと思います。有難うございます。
winterboum

2021/03/11 07:13

その時のparams見せてください
punchan36

2021/03/11 07:58

追記致しました。 また :sex 部分は :gender にカラム名から変更致しました。
winterboum

2021/03/11 10:51

ここかなぁ   "#{params[:gender]}%" %が足りないのが効いてるか。。。
punchan36

2021/03/12 05:53

試してみましたがそちらが関係している訳ではなかったようです…。 詳細に見て頂き有難うございます!中々解決せず申し訳ありません。
winterboum

2021/03/12 06:18

根本的にちがう。 User と Language 多対多ですね。 検索式がまるでちがいます。LIKE使ってるんで騙された。 回答に追記します
punchan36

2021/03/12 06:49

有難うございます! 試させて頂いたところ neko_daisuki さまにご教示頂いたコードと同様の結果になりました。 返信内容が被ってしまうのですが、ご教示頂いたコードですと「日本語、中国語」で検索をかけると以下のユーザーがヒットしました。 ・ユーザーA: 日本語 ・ユーザーB: 日本語、英語 ・ユーザーC: 日本語、英語、中国語 ・ユーザーC: 日本語、英語、中国語 今度は「日本語、中国語のいずれか」を話せるユーザーを検索してしまったようです。 更に該当する言語数の分だけユーザーが表示されてしまいました(ユーザーCは2回)。これは distinct メソッドを用いて改善されましたが… いずれにせよ、日本語・中国語を「含む」言語を話せるユーザーと言う意味合いで、何とかユーザーCだけヒットさせられるような記述は出来ないものでしょうか…。方法が思いつきませんでした。。
winterboum

2021/03/12 07:42 編集

LIKEなのでどれかが かと思ってましたが、指定したもの全てですか? 言語に対する絞り込みの仕様がはっきりしません 正しい質問をしないと正しい答えは得られません
punchan36

2021/03/12 08:57

誤解を与えてしまう質問内容で大変申し訳ありませんでした。 質問欄に再度追記致しました。 可能でありましたらご助言頂けますと有難いです。
winterboum

2021/03/15 10:20

回答追記したつもりだったのですが、できていなかったみたい。 追記2に書きました
punchan36

2021/03/16 09:10

返信が遅くなり大変申し訳ありません。 ご教示頂いたコードで言語検索を試した所、以下の様なおかしな状態になりました。 ・言語を一つ選んで検索→その言語を含んだユーザーがヒットする(正常)。 ・言語を二つ以上選んで検索→どんな言語の組み合わせでも if @users == [] 以下の処理になぜか流れてしまう。例えば「日本語、英語、中国語」で検索した場合、それに完全一致するユーザーがいるにも関わらず「ユーザーが見つかりません」の処理になる。 ログを追ってみたのですが、原因が分かりません…。 Processing by UsersController#index as HTML Parameters: {"utf8"=>"✓", "name"=>"", "language_ids"=>["1", "2", "3"], "introduction"=>"", "commit"=>"search"} User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 ↳ app/controllers/application_controller.rb:9 User Load (1.0ms) SELECT `users`.* FROM `users` INNER JOIN `user_languages` ON `user_languages`.`user_id` = `users`.`id` INNER JOIN `languages` ON `languages`.`id` = `user_languages`.`language_id` WHERE (name LIKE '%%' AND introduction LIKE '%%' AND gender LIKE '%') AND `languages`.`id` = 1 AND `languages`.`id` = 2 AND `languages`.`id` = 3 LIMIT 20 OFFSET 0 また、言語を一つも選択せず、ユーザー名や性別のみ指定して検索した場合以下のエラーが出てしまいました。 undefined method `inject' for nil:NilClass 自力で改善出来ず申し訳ないです…。
winterboum

2021/03/16 09:14

「言語を一つも選択せず」対策していなかったな users = params[:language_ids].inject のところ users = ( params[:language_ids] || [] ).inject にしてください。 前者はちょい考えます
winterboum

2021/03/16 09:45

前者大変だ。。。 SQLのベテランを召喚出来るような質問、タイトル、タグにしてください。
winterboum

2021/03/16 11:17

neko_daisukiさんがそういう方みたい
punchan36

2021/03/18 04:59

有難うございます! 「言語を一つも選択しなかった場合のエラー」は "|| []" で解決しましたが、前者の部分は大分複雑だったのですね…。 最終的にneko_daisukiさまにご教示頂いたコードで解決致しました。理解が悪いにも関わらず、親身にアドバイスを頂き本当に有難うございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問