質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

88.33%

[Ruby on Rails]複数条件でAND検索し、その結果をビューで表示させたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 326

clora

score 72

前提

複数の条件に一致した時のデータを取得したいと考えています
検索条件は日付(date) AND グループid(group_id) AND 製品id(product_id)の三つです。

検索条件の三つの値をフォームに入力して検索しようとすると、

wrong number of arguments (given 0, expected 3)

という、エラーが出てしまいます。
これは、引数が渡せていないというエラーだということはわかっているのですが、検索の条件を満たす、引数を3つ渡した時だけ、given 0、となってしまいます。
試しに、渡す引数の数を一つや二つにすると、given 1,given 2となるので、引数は渡せていて、メソッドも呼び出されていると思うのですが(もちろんエラーは出ます)、引数を三つ渡した時だけエラーメッセージがgiven 0となり、検索できません。
searchメソッドの記述などを間違えているのでしょうか。それとも、引数の渡し方がおかしいのでしょうか。
DBには該当するデータは存在しています。
よろしくお願い致します。

発生している問題・エラーメッセージ

ArgumentError in Productions::SearchesController#search
wrong number of arguments (given 0, expected 3)

Extracted source (around line #8):
8  def self.search(date,line_id,product_id)
9    if search
10    Production.where
      ("(date = ?) AND (line_id = ?) AND (product_id = ?)", "%#{date}%", "%# {group_id}%", "%#{product_id}%")
11    redirect_to productions_searches_path

該当のソースコード

#route.rb
Rails.application.routes.draw do
  root 'groups#index'
  namespace :productions do
    resources :searches, only: :index do
      collection do
        get 'search'
      end
    end
  end

  resources :groups do
    resources :productions
  end
end
#/controllers/productions/searches_controller.rb
class Productions::SearchesController < ApplicationController
  def index
    @production = Production.new
  end

  def search
    #Productモデルのcodeカラムに情報を取りにいってます
    product_id = Product.find_by(code: params[:production][:product_id]).id

    @production = Production.search(params[:production][:date], params[:production][:group_id], product_id)
    redirect_to search_productions_searches_path
  end
end
#models/production.rb
class Production < ApplicationRecord
  belongs_to :product
  belongs_to :group

  validates :date, presence: true
  validates :product_id, presence: true

def self.search(date,group_id,product_id)
  if search
    Production.where
    ("(date = ?) AND (group_id = ?) AND (product_id = ?)", "%#{date}%", "%#{group_id}%", "%#{product_id}%")
  else
    redirect_to productions_searches_path
  end
end
-# views/productions/searches/index.html
<%= form_for [@production], url: search_productions_searches_path do |f| %>
  <div class="form__info__date">
    <%= f.date_field :date  %> #日付の入力
    <%= f.number_field :products_id %> #productsのid(数字)を入力
    <%= f.select :group_id, [["グループ1", 1],["グループ2", 2]]  %> #グループidの入力
    <%= f.submit '検索', class: "btn" %>
  </div>
<% end %>
-# views/productions/searches/search.html
-# 検索結果の出力画面は仮です
<%= @production.date %>
<%= @production.group_id %>
<%= @production.product_id %>

試したこと

SearchesControllerのsearchメソッドを呼ぶ前でbinding pryして検索条件がきちんと入力されているか、確かめました。

#/controllers/productions/searches_controller.rb
def search
 #Productモデルのcodeカラムに情報を取りにいってます
 product_id = Product.find_by(code: params[:production][:product_id]).id
 binding pry
 @production = Production.search
               (params[:production][:date], params[:production][:group_id], product_id)
end
[1] pry(#<Productions::SearchesController>)> product_id
=> 1
[2] pry(#<Productions::SearchesController>)> params[:production][:group_id]
=> "1"
[3] pry(#<Productions::SearchesController>)> params[:production][:date]
=> "2019-12-13"

この内容を見ると、値がnilにはなっていないとは思います。しかし、product_idがint型、group_idがstr型なのが気になりますが。
また、仮で、下記のようにsearchメソッドに直接数字などを渡してもやはり、三つ渡した時だけ、given 0となってしまいエラーになってしまいます。

#/controllers/productions/searches_controller.rb
@production = Production.search("2019-12-13", "1", "1")

@production = Production.search("2019-12-13", 1, 1)

実現したいこと

三つの条件を入力して、該当するデータを取得する

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

rails 5.0.7
ruby 2.5.1

追記

コメントで指摘を受けた部分を変更しました。
それに加えて、resultアクションを追加して、@production_resultに検索結果を挿入し、resultアクションで検索結果を表示させるようにしました。
しかし、@production_resultがnilになってしまい検索結果が表示されません。
どうもsearchメソッドを使用すると、@production_resultがから([])となってしまいます。
これは、検索結果がないということなのでしょうか?配列の中の値がnilとして返ってくるのならわかるのですが、配列自体が空になってしまいます。まだ、searchメソッドの記述がおかしいのでしょうか。
下記はsearchメソッドを使用した後、binding pryで確かめた結果です。

[1] pry(Production)> @production_result
=> nil
#route.rb
Rails.application.routes.draw do
  root 'groups#index'
  namespace :productions do
    resources :searches, only: :index do
      collection do
        get 'search'
      end
      collection do
        get 'result'
      end
    end
  end

  resources :groups do
    resources :productions
  end
end
#/controllers/productions/searches_controller.rb
def search
 @production_result = Production.new
 product_id = Product.find_by(code: params[:production][:product_id]).id
 @production_result = Production.search(params[:production][:date], params[:production][:group_id], product_id)

 redirect_to result_productions_searches_path(@production_result)
end

def result

end
def self.search(date,line_id,product_id)
  if date and group_id and product_id
    Production.where
    ("(date = ?) AND (group_id = ?) AND (product_id = ?)", "%#{date}%", "%#{group_id}%", "%#{product_id}%")
  else
    redirect_to productions_searches_path
  end
end
-#views/productions/searches/result.html
検索結果
<%= @production_result.date %>
<%= @production_result.group_id %>
<%= @production_result.product_id %>
 id   date   group_id   product_id 
 26   2019-12-13 00:00:00   1   1 

試したこと

binding pryをしてみたところ、seaechメソッドをすると@production_resultが[]となってしまいます。

追記 part2

上記の状況から進展がありました。
@production_resultがnilになってしまうのはproduct_idの指定の仕方が間違えていたことによるものでした。
上の方にも書いた通り、product_idは他のテーブルに値を探しにいって変数product_idに入れて、searchメソッドに渡しています。その時にフォームから直接受け取ったgroup_idは"1"となっていたのに対し、product_idは 1 となっていました。そのため、そのまま、product_idを検索条件に入れてしまうと、条件に引っかからず、検索結果が0となり、@production_resulがnilになっているのでしたそこで下記のように、searchメソッドを書き直したところ、きちんと検索結果が、@production_resultに入ってくれました。

#production.rb
def self.search(date,line_id,product_id)
    Production.where(date: date).
              where(group_id: group_id).
              where(product_id: "#{product_id}")
end
[1] pry(#<Productions::SearchesController>)> product_id
=> 1 #こっちはただの数字
[2] pry(#<Productions::SearchesController>)> params[:production][:group_id]
=> "1" #こっちはダブルクォーテーションで囲まれている

ただ、まだ検索結果のビューでは、@production_resulはnilclassになってしまいますね、、、。
うまく変数が渡せていないだけだと思うのですが、、、。

追記 part3

なんとか解決しました。
ビューの方の表記を変えたところきちんと検索結果が表示されました。

間違い
<%= @production_result.date %>

正解
<%= (@production_result.to_a)[0].date %>

また、asmさんのアドバイス通りwhereでなく、find_byを使えば@production_result.dateという形でも取り出せます。whereやfind_byの違いや原理を理解していないのがエラーにハマった原因でした。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

def self.search(date,group_id,product_id)
  if search

Production.searchメソッドの再帰呼び出しになります。
このsearchは何なのでしょうか?

    Production.where
    ("(date = ?) AND (group_id = ?) AND (product_id = ?)", "%#{date}%", "%#{group_id}%",  "%#{product_id}%")

Production.where()
("(date = ?) AND (group_id = ?) AND (product_id = ?)", "%#{date}%", "%#{group_id}%",  "%#{product_id}%")

と解釈されます。


コメントに返信

redirect_to productions_searches_path

モデルのなかでredirect_toを使うのは避けた方がいいでしょう。
(そもそも使えないと思います。)

LIKE検索でもないのに%で囲む意味がよくわかりませんが

Production.where(date: date).
           where(group_id: group_id).
           where(product_id: product_id)
Production.where("(date = ?) AND (group_id = ?) AND (product_id = ?)",
                 date, group_id,  product_id)

どっちでもよかったはずです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/12/14 21:14

    なんとか解決しました!
    検索結果を挿入した@production_resultの型が普通の配列と違ったようで、ビューの方で取り出し方を下記のように変えたら、きちんと表示されるようになりました。
    ありがとうございました。助けてもらったので自己解決ではありませんが、追記などをしてゴチャゴチャになったので、解決方法を自己解決の欄にまとめたいと思います。
    お世話になりました。

    <%= (@production_result.to_a)[0].date %>

    キャンセル

  • 2019/12/14 21:19

    あぁ、複数件ヒットすることを想定していないのを見逃していました。
    whereをfind_byにした方がよさそうですね。

    キャンセル

  • 2019/12/14 21:29

    なるほど!find_byだと
    @production_result.date
    みたいな表記でできますね。find_byとwhereの違いを調べてみたのですがよくわかりません(笑)
    find_byは一個しかデータを取ってこないが、whereだと、複数の行のデータが入っているから、きちんと何番目か指定してあげないと取り出せない、みたいな感じでしょうか。
    長々とありがとうございました。お世話になりました。

    キャンセル

0

アドバイスを沢山もらったので自己解決ではないですが、追記を繰り返して見辛いので、最終的なコードを示しておきたいと思います。
検索結果は基本的に複数件ヒットすることはないので、find_byを使うことにしました。
途中で作ったresultアクションは使わないので削除しました。

# routes.rb
Rails.application.routes.draw do
  root 'groups#index'
  namespace :productions do
    resources :searches, only: :index do
      collection do
        get 'search'
      end
    end
  end

  resources :groups do
    resources :productions
  end
end
# models/production.rb
def self.search(date,group_id,product_id)
    Production.find_by("(date = ?) AND (group_id = ?) AND (product_id = ?)",
                 date, group_id,  product_id)
end
#searches_controller.rb
class Productions::SearchesController < ApplicationController
  def index
    @production = Production.new
  end

  def search
    product_id = Product.find_by(code: params[:production][:product_id]).id

    @production_result = Production.search(params[:production][:date], params[:production][:group_id], product_id)
  end
end
#search.html
検索結果
<%= (@production_result.date %>
<%= (@production_result.group_id %>
<%= (@production_result.product_id %>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.33%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る