Rails viewからcontrollerに値を渡す方法

この記事はプログラミング学習者がコードを書く中で得られた内容を備忘録を兼ねて記事にしたものです。間違った所などあればご指摘頂けると嬉しいです。

## 変数の受け渡しについて
Railsで変数を受け渡す時にcontrollerからviewへ受け渡すというのは良くやります。
これまでもコードを書く中で何度も使ってきました。

```ruby:merchandises_controller.rb
class MerchandisesController < ApplicationController
  def index
    @merchandises = Merchandise.with_attached_image
  end
end
```
```ruby:index.html.erb<% @merchandises.each do |merchandise| %>
  <div class="col mb-5">
    <div class="card h-100">
      <!-- Product image-->
      <% if merchandise.image.attached? %>
        <%= image_tag merchandise.image, :size => '269x170' %>
      <% end %>
      <!-- Product details-->
      <div class="card-body p-4">
        <div class="text-center">
          <!-- Product name-->
          <h5 class="fw-bolder">
            <%= link_to merchandise.name, merchandise_path(merchandise) %>
          </h5>
          <!-- Product price-->
          ¥<%= merchandise.amount.to_formatted_s(:delimited) %>-
        </div>
      </div>
    </div>
  </div>
<% end %>
```
上記コードではcontrollerで作成した`@merchandises`というインスタンス変数の値をviewファイルの中で展開してレンダリングする内容です。

学習を進めていく中でviewファイルがトリガーとなって値をcontrollerに渡す機能が必要となりました。
最初は方法をなかなか見つけられず四苦八苦しましたが、何とか見つけられて実装した機能にも取り込んだ書き方を２種類お伝えします。

## form_withヘルパーを使って値を渡す場合

```ruby:show.html.erb
<%= form_with model: @cart_item, url: create_path(@merchandise), method: :get, local: true do |f| %>
  <div class="form-group">
    <%= f.label :quantity, CartItem.human_attribute_name(:quantity) %>
    <%= f.text_field :quantity, class: 'form-control' %>
  </div>
  <%= f.submit 'Add to cart', class: "btn btn-outline-dark mt-auto" %>
<% end %>
```
通常、form_withヘルパーではブラウザで入力された値を受け取ってcontrollerへ渡します。
`<%= f.text_field :quantity, class: 'form-control' %>`
が入力欄のコードでsubmitボタンが押されると`quantity`変数の中に入力された値が入ってcontrollerへ伝わります。
私の場合、この時取得が必要な値は`quantity`と表示されているページデータの`id`でした。
`quantity`は上述の通りsubumitボタンを押せば取得できます。
問題はもう一つの`id`です。
form_withヘルパーは`url`を指定することでsubmitボタンを押した際に指定のアクションへ飛ぶことができます。
```ruby:show.html.erbの抜粋
<%= form_with model: @cart_item, url: create_path(@merchandise), method: :get, local: true do |f| %>
```
この時、pathの後ろに括弧書きで変数を書くことでcontorollerに値を渡すことができるということが分かりました。
pry-byebugとbinding.pryを使ってparamsの中身を確認した所、`format`として`id`を含んでいることが分かりました。
![params.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/2a756b1f-b46e-ec70-21ef-224dcd27d3f2.png)

後はcontroller側でformatの値を受け取るだけです。
```ruby:carts_controller.rb
@merchandise = Merchandise.find_by(id: params[:format])
if params[:quantity].to_i <= 0 || params[:quantity].blank? # quantityを使うif文
```
これで無事view側からcontrollerへ必要な値を受け渡すことができるようになりました。

## link_toメソッドを使って値を渡す場合
link_toメソッドは通常表示されたボタンを押した際に指定されたpathへ移動する性能です。
```ruby:index.html.erbの抜粋
<%= link_to 'Add to cart', create_path, class: "btn btn-outline-dark mt-auto" %>
```
上のサンプルですと`create_path`がそれに当たります。
ここでもform_withヘルパーと同様にcontrollerに対して２つの値を引き渡す必要があります。
`quantity`と`id`です。
しかも今回は`quantity`は`1`という固定の定数を渡したいという状況でした。
link_toメソッドもfrom_withと同様にurlを書く時に値を渡すことができます。
但し、form_withヘルパーの場合はformで入力された値一つとurlからの値一つという方法でした。
幸いlink_toメソッドからは値を二つ渡せることが調べて分かりました。
```ruby:index.html.erbの抜粋(修正後)
<% @merchandises.each do |merchandise| %>
<%= link_to 'Add to cart', create_path(merchandise.id, quantity:1), class: "btn btn-outline-dark mt-auto" %>
```
調査をもとに修正したコードは上記になります。
create_pathの後ろに括弧書きで値を二つ記述することで値を渡せるようになりました。
![params.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/ed4bcc9b-94ee-3c17-7e1f-732a3cad7849.png)

以上、viewからcontrollerに値を渡す方法をご紹介しました。

日頃、Qiitaを含めた記事には助けられているので、少しでもお役に立てると嬉しいです。