🦺

別モデルの画像をf.collection_selectで選択し投稿するまでの手順

2023/09/28に公開

この記事でわかること

- 別モデルのデータをセレクトボックスで選択できるようになる
- セレクトボックスの使い方

前提条件

  • 完成イメージのSTEP1(別モデルの画像の投稿ができる)が実装済み
  • Itemsモデル(画像を引用するモデル)とProductsモデル(引用元のモデル)をN:1でアソシエーション済み

完成イメージ

  • STEP1(商品画像・商品名・商品画像を確認)
  • STEP2(セレクトボックスで該当する商品名を選択)
  • STEP3(投稿された画像を確認)

ER図

モデル名一覧

会員 商品 投稿
Users Products Items

テーブル一覧



実装手順

STEP2での選択フォームに表示する文字を作成

今回、私はフォームに会社名と商品名を同時に表示したかったので、Productモデルに新しく定義しました。

model/products.rb
  def product_display
    user.name + ':' + name
  end

投稿フォームを作成

私は投稿フォームを部分テンプレートで実装しました。

items/_form.html.erb
 <h4 class="align-middle text-center">おかしを紹介する</h4>
 <%= form_with model: item,local:true do |f| %>
  <div class="form-group row justify-content-center">
    <div class="form-inline form_text">
+    <%= f.collection_select(:product_id, @products, :id, :product_display, {prompt: "商品画像を選ぶ"}, :required => true ,class: 'form-control') %>
  </div>
  </div>
  <div class="form-group row justify-content-center">
    <div class="form-inline form_text">
      <label>商品名 </label>
      <%= f.text_field :title, class: 'form-control item_name ml-1 form w-15', placeholder:"商品名" %>
    </div>
  </div>
  <!-- 以下略 -->

画像をテーブルで表示する

items/_postitems.html.erb
 <% items.each do |item| %>
  <div class="table-responsive-sm">
   <table class="table text-nowrap table-bordered w-100">
      <tr class ="align-middle text-center">
         <th class="user_name">
          <%= image_tag item.user.get_profile_image(30,30), class: "rounded-circle" %><%= item.user.name %>さん
          <%= render 'layouts/user_certification', user: item.user %>
          </th>
         <th class="head" colspan="5"> <a data-toggle="collapse" href="#collapse1" class= "text-secondary"></a>投稿画像
         <% if item.user == current_user %>
           <%= link_to item_path(item), method: :delete do %>
            <i class="fa-solid fa-eraser"></i>削除
           <% end %>
         <% end %>
         </th>
       </tr>
        <tr class="align-middle text-center td collapse" id="collapse1">
+          <td colspan="5"><%= image_tag item.product.get_image, size:'300x300' %></td>
        </tr>
        <tr class="align-middle text-center">
         <th class="head">商品名</th>
         <td class="td" colspan="2"><%= item.title %></td>
         <th class="head">会社</th>
         <td class="td" colspan="2"><%= item.company %></td>
       </tr>
       <!-- 以下略 -->

上記の記述で実装できます。

実装の解説

実装の解説を以下に示します。

  1. productsモデルにセレクトボックスで表示するタイトルを設定する
  2. 投稿フォームでitemカラム,product_idにデータを渡す
  3. アソシエーションからitem.productで画像表示

この実装方法の問題点

  • productsのデータを引用しているので、商品詳細(product.show)を削除することができない。
    → 改善策:削除機能ではなく非公開機能を追加する

productsモデルにフォームで表示したいタイトルを設定する

実装手順の内容と同じなため割愛

投稿フォームでitemカラム,product_idにデータを渡す

「f .collection_select」については以下の記事を参考にさせていただきました。

https://qiita.com/ohnitakahiro/items/c536fe65e37980e1087e

f.collection_select(メソッド名, オブジェクトの配列, value属性の項目, テキストの項目 > >[, オプション or HTML属性 or イベント属性])

【Ruby】f.collection_select を使ってみた

また実際に記述したコードは以下の通りです。

items/_form.html.erb
 <%= f.collection_select(:product_id, @products, :id, :product_display, {prompt: "商品画像を選ぶ"}, :required => true ,class: 'form-control') %>

実装時、()内の記述には苦労しました。詳しい内容は引用を参考にしていだだけると幸いです。
自分の考え方としては、「どのカラムを対象にする?(どのメソッドに)?,どの配列を使う?
,データは?,フォームで表示する内容は?」というイメージで覚えました。(この考え方でいいかは分からないです)

  • prompt ・・・ デフォルトの文章を設定
  • required => true ・・・選択せずに投稿ボタンを押すとバリデーションがかかる

アソシエーションからitem.productで画像表示

items/_postitems.html.erb
<tr class="align-middle text-center td collapse" id="collapse1">
 <td colspan="5"><%= image_tag item.product.get_image, size:'300x300' %></td>
</tr>

以上で「別モデルの画像をf.collection_selectで選択し投稿するまでの手順」の紹介を終わります。

感想

実装時は、どのような工程でやりたいことを実現するか悩みました。またデータを渡すという考えをあまり理解できていなかったのでこの記事を通して理解が深まってよかったです。

この記事をかいた人

https://twitter.com/tya_dwc
23/6/1にDWCに入学し、主にRailsの学習に取り組みました。卒業が近づきこれから何で学習をするか悩んだときに、技術ブログをしようと考えました。初心者ですがよろしくお願いします。

Discussion