Bambi_
@Bambi_

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

検索結果から詳細画面への遷移についてご教示ください

解決したいこと

Ruby on Railsで車の部品データ登録アプリを作っています。
ransackで検索機能を実装しましたが、検索結果から詳細画面に遷移できません。
CarTypeを選択し、そのCarTypePartを登録したときには詳細画面に遷移できます。
CarTypeモデル(親)とPartモデル(子)のルーティングをネストしています。
解決方法をご教示いただけないでしょうか?

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

ActiveRecord::RecordNotFound in PartsController#show
Couldn't find Part with 'id'=part

    def show
    @part = Part.find(params[:id])
  end

該当するソースコード

config/routes.rb

Rails.application.routes.draw do
  devise_for :users
  get 'parts/search'
  root to: "parts#index"
  resources :car_types, only: [:index, :new, :create] do
    resources :parts
  end
end

app/controllers/parts_controller.rb

class PartsController < ApplicationController
  before_action :search_part, only: [:index, :search]

  def index
    @car_types = CarType.order(:car_type_code)
    @parts = Part.all
    set_part_column
    @car_type = CarType.new
  end

  def new
    @car_type = CarType.find(params[:car_type_id])
    @part = Part.new
  end

  def create
    @car_type = CarType.find(params[:car_type_id])
    @part = Part.new(part_params)
    if @part.save
      redirect_to car_type_part_path(id: @part)
    else
      render :new
    end
  end

  def show
    @part = Part.find(params[:id])
  end

  def edit
  end

  def update
    if @part.update(part_params)
      redirect_to car_type_part_path(id: @part)
    else
      render :edit
    end
  end

  def search
    @result = @q.result
    @results = @q.result.includes(:car_type)
  end

  private

  def part_params
    params.require(:part).permit(:image, :product_number, :part_name_id, :material_id, :thickness, :weight, :supplier_id).merge(user_id: current_user.id, car_type_id: params[:car_type_id])
  end

  def search_part
    @q = Part.ransack(params[:q])

  end

  def set_part_column
    @part_part_name = Part.select("part_name_id").distinct
    @part_product_number = Part.select("product_number").distinct
  end

end

app/views/parts/index.html.erb

<div class="accordion" id="accordionExample">
  <div class="accordion-item">
    <h2 class="accordion-header" id="headingOne">
      <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
        <i class="fas fa-search"></i> 部品を検索する
      </button>
    </h2>
    <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
      <div class="accordion-body">
        <%= search_form_for @q, url: parts_search_path do |f| %>
          <%= f.label :car_type_id_eq, "車種:" %>
          <%= f.collection_select :car_type_id_eq, CarType.order(:car_type_code), :id, :car_type_code, include_blank: '指定なし' %>
          <br>
          <%= f.label :part_name_id_eq, "部品名:" %>
          <%= f.collection_select :part_name_id_eq, PartName.where.not(id: 1), :id, :name,  include_blank: '指定なし' %>
          <br>
          <%= f.label :product_number_eq, "品番:" %>
          <%= f.collection_select :product_number_eq, @part_product_number.order(:product_number), :product_number, :product_number, include_blank: '指定なし' %>
          <br>
          <%= f.label :material_id_eq, "材質:" %>
          <%= f.collection_select :material_id_eq, Material.where.not(id: 1), :id, :name, include_blank: '指定なし' %>
          <br>
          <%= f.label :thickness, "板厚:" %>
          <%= f.radio_button :thickness_lteq, '' %>
          指定なし
          <%= f.radio_button :thickness_lteq, '10' %>
          10.00mm以下
          <%= f.radio_button :thickness_lteq, '20' %>
          20.00mm以下
          <br>
          <%= f.radio_button :thickness_lteq, '30' %>
          30.00mm以下
          <%= f.radio_button :thickness_lteq, '40' %>
          40.00mm以下
          <br>
          <%= f.label :weight, "質量:" %>
          <%= f.radio_button :weight_lteq, '' %>
          指定なし
          <%= f.radio_button :weight_lteq, '1000' %>
          1000.00g以下
          <%= f.radio_button :weight_lteq, '3000' %>
          3000.00g以下
          <br>
          <%= f.radio_button :weight_lteq, '5000' %>
          5000.00g以下
          <%= f.radio_button :weight_lteq, '10000' %>
          10000.00g以下
          <br>
          <%= f.label :"仕入先" %>
          <%= f.collection_select :supplier_id, Supplier.where.not(id: 1), :id, :name, include_blank: '指定なし' %>
          <br>
          <%= f.submit "検索" %>
        <% end %>
      </div>
    </div>
  </div>
  <div class="accordion-item">
    <h2 class="accordion-header" id="headingTwo">
      <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
        <i class="fas fa-cogs"></i> 部品を登録する
      </button>
    </h2>
    <div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
      <div class="accordion-body">
        <% @car_types.each do |car_type| %>
          <%= link_to car_type.car_type_code, new_car_type_part_path(car_type) %>
        <% end %>
      </div>
    </div>
  </div>
  <div class="accordion-item">
    <h2 class="accordion-header" id="headingThree">
      <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
        <i class="fas fa-car"></i> 車種を登録する
      </button>
    </h2>
    <div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#accordionExample">
      <div class="accordion-body">
        <%= form_with model: @car_type, local: true do |f| %>
        <div class="car-type">
          <%= f.label :"車種" %>
          <%= f.text_field :car_type_code, placeholder: "300C" %>
        </div>
        <%= f.submit '登録', class: 'form-submit' %>
        <% end %>
      </div>
    </div>
  </div>
</div>

app/views/parts/search.html.erb

<div class="container">
  <div class="content-title">
    検索結果
  </div>

  <div class="wrap">
    <% if @results.length !=0 %>
      <% @results.each do |result| %>
        <div class="card">
          <div class="delete-btn">
            <i class="far fa-times-circle fa-2x fa-pull-right fa-border"></i>
          </div>
        <%= image_tag result.image.variant(resize: "400x400"), class: 'part-image' %>
          <div class="card-body">
            <p>車種:<%= result.car_type.car_type_code %></p>
            <p>部品名:<%= result.part_name.name %></p>
            <p>品番:<%= result.product_number %></p>
            <p>材質:<%= result.material.name %></p>
            <p>板厚:<%= result.thickness %>mm</p>
            <p>質量:<%= result.weight %>g</p>
            <p>仕入先:<%= result.supplier.name %></p></p>
            <p>登録者:<%= result.user.name %></p>
            <p><%= l result.created_at %></p>
            <%= link_to "詳しく見る", car_type_part_path([:car_type], [:part]) %>
          </div>
        </div>
      <% end %>
      <div class="page-top">
        <div id="topBtn"><i class="fas fa-arrow-circle-up fa-3x"></i><div>
      </div>
    <% else %>
      該当する部品はありません
    <% end %>
  </div>
</div>

自分で試したこと

検索結果にPart.idを紐付けし、search.html.erbの<%= link_to "詳しく見る", car_type_part_path %>の引数にPart.idを渡せば解決すると考え、思いつくものは全て試してみましたが上手くいきませんでした。よろしくお願いいたします!

0

1Answer

エラーメッセージ(Couldn't find Part with 'id'=part)からすると、
id=partで検索しにいってるようですが、car_type_part_pathにPart.idを渡したパターンのコードはどんな感じでしょうか?

1Like

Comments

  1. @Bambi_

    Questioner

    ご覧いただきありがとうございます!
    掲載したコードでこのようなエラーが出ています。
    エラー画面の下には
    Parameters:
    {"car_type_id"=>"car_type", "id"=>"part"}と表示されており、
    パスはhttp://localhost:3000/car_types/car_type/parts/part になってしまっています。
    ここからなにかわかりますでしょうか?
  2. link_to "詳しく見る", car_type_part_path([:car_type], [:part])
    のところを
    link_to "詳しく見る", car_type_part_path(result.car_type.id, result.car_type.part.id)
    とかでどうでしょう?
    IDを渡してあげなければいけませんので。
  3. @Bambi_

    Questioner

    ご回答いただきありがとうございます!
    **result.**という書き方は全く浮かんでいなかったので、とても勉強になります!

    教えていただいた通りに書き換えてみたところ、今度は以下のエラーが出てしまいました。
    NoMethodError in Parts#search
    Showing /Users/bumbi/projects/compare_parts/app/views/parts/search.html.erb where line #25 raised:

    undefined method `part' for #<CarType:0x00007f9a7abdcab0>
    Did you mean? parts

    これを受けて以下のようにしたところ
    link_to "詳しく見る", car_type_part_path(result.car_type.id, result.car_type.part.id)
    今度は、 Did you mean? ids というエラーが出たので
    link_to "詳しく見る", car_type_part_path(result.car_type.id, result.car_type.parts.ids)
    と書き換えてみました。
    エラーは出なくなり検索結果が表示されましたが、詳細ページを開くとどれも同じpart.idのページに遷移してしまいます。

    ちなみにこのアプリで一番実現したいことは比較機能なので、部品名だけで検索したり、何も指定せずに検索をしたいと考えています。
    パラメーターは以下のようになっているのですが、この中にpart.idがないことも問題でしょうか?

    Parameters:
    {"q"=>{"car_type_id_eq"=>"", "part_name_id_eq"=>"2", "product_number_eq"=>"", "material_id_eq"=>"", "thickness_lteq"=>"", "weight_lteq"=>"", "supplier_id"=>""}, "commit"=>"検索"}
  4. CarTypeとPartの関係が、1:Nなのですね。
    また、resultの中身がPartなのを見落としていました。

    となると、
    link_to "詳しく見る", car_type_part_path(result)
    link_to "詳しく見る", car_type_part_path(result.car_type, result)
    link_to "詳しく見る", car_type_part_path(result.car_type.id, result.id)
    あたりで行けそうな気もします。
    ※すみません、直ぐに検証する環境がないので、机上での予想になりますが。
  5. @Bambi_

    Questioner

    説明が不足しており、失礼いたしました。
    また、再度ご回答いただきありがとうございます!

    @newburu様にご提案いただいた
    link_to "詳しく見る", car_type_part_path(result.car_type, result)
    link_to "詳しく見る", car_type_part_path(result.car_type.id, result.id)
    のどちらでも、希望通り検索結果から詳細画面へ遷移することができました!

    貴重なお時間を割いていただき本当にありがとうございました!!!
  6. おおお、よかったです!
    引き続き頑張ってくださいー👍

Your answer might help someone💌