ぴよ丸水産

週末ファゴッティストによる技術ブログ

【Ruby on Rails】フォームからDBに値登録・画面にDBの内容表示

0. はじめに

Ruby on RailsでDB(sqllite)をいじってみました。
フォームからの登録→Web画面に表示
をやってみました。

説明が雰囲気で理解している感が強めです。
あと、結果よりプロセスを前面に出してます。

目次

  1. Modelについて
  2. Modelを作ってみる
  3. フォームを作ってみる
  4. DBにフォームの入力値を登録してみる
  5. DBの値を表示してみる

1. Modelについて

Ruby on RailsでDBをいじるために、
Modelという概念を理解します。

下記の記事が端的にまとめていて、
理解しやすかったです。

Railsのmodelを徹底解説!知っておくべき3つの知識も…|Udemy メディア

Modelとは、
データベースのテーブルに対応するRubyのクラス
とのことです。

2. Modelを作ってみる

下記のコマンドで生成します。
rails generate model <モデル名> <カラム名>:<型> [<カラム名>:<型> …]

モデル名は単数形(末尾がsではない)でなければなりません。
<カラム名>:<型>は複数カラムがある場合は後ろに追記していきます。

ちなみに、Modelの削除は下記のコマンドです。
rails destroy model <モデル名>

date amount
貯金した日付 金額

こんなテーブルを作りたかったので、
下記のコマンドで作成しました。

>rails generate model saving date:date amount:integer
      invoke  active_record
      create    db/migrate/20191128052254_create_savings.rb
      create    app/models/saving.rb
      invoke    test_unit
      create      test/models/saving_test.rb
      create      test/fixtures/savings.yml

なにやらrailsが必要なファイルを生成してくれたようです。

db/migrate/20191128052254_create_savings.rb がミソで、
下記のようになっています。
DBに「Savingsってテーブル作ってちょ!」と依頼してます。

class CreateSavings < ActiveRecord::Migration[6.0]
  def change
    create_table :savings do |t|
      t.date :date
      t.integer :amount

      t.timestamps
    end
  end
end

rails db:migrateコマンドを実行することで、
その依頼が実行されます。

>rails db:migrate
== 20191128052254 CreateSavings: migrating ====================================
-- create_table(:savings)
   -> 0.0074s
== 20191128052254 CreateSavings: migrated (0.0100s) ===========================

3. フォームを作ってみる

Web画面のフォームから値を投入させたいので、
まず、Viewでフォームを作ってみます。

後々Controllerをがちゃがちゃいじるので、
下記のコマンドを実行しておきます。

>rails generate controller saving
      create  app/controllers/saving_controller.rb
      invoke  erb
      create    app/views/saving
      invoke  test_unit
      create    test/controllers/saving_controller_test.rb
      invoke  helper
      create    app/helpers/saving_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/saving.scss

app/views/savingができてますね。
ここに、new.html.erbを作っていじっていきます。

View

  • app/views/saving/new.html.erb
<h1>貯蓄管理</h1>
<h2>貯蓄入力</h2>

<%= form_for @saving do |f| %>

    <div class="field">
      <%= f.label :date, "日付" %>
      <%= f.date_select(
        :date,
        use_month_numbers: true,
        start_year:        2018,
        date_separator:    '/') %>
    </div>
  
    <div class="field">
      <%= f.label :amount, "金額 ¥" %>
      <%= f.number_field :amount %>
    </div>
    
    <div class="actions">
      <%= f.submit "登録" %>
    </div>
  <% end %>

まずは入力分だけです。
後で表示分作ります。

<%= %>は、Rails on Ruby独特の記法のようで、
記法に則って書くと、HTMLに変換してくれるみたいです。

フォームを作るには、この記事が参考になりました。

Railsのform_forを使ったフォームのController,View,Modelの連携した処理フロー - Rails Webook

ポイントを説明します。

form_forメソッド

基本的な書式は下記の通りです。

<%= form_for モデルのオブジェクト do |文字列| %>

<% end %>

フォームの中身の記法は下記の通り

<%= 文字列.label :ラベル名, "Webに表示する項目名">
<%= 文字列.フォームの種類 :controllerに引き渡すparamのキーになる文字列>

登録ボタンはこちら

<%= 文字列.submit "登録" %>

なかなか説明がいけてないが、
まぁ、よいでしょう。(よくない)

私が使ったフォームの種類は以下の二つです。

  • date_select
  • number_field

controller

Viewで外観ができたので、
中の処理を作っていきます。
app/controllers/saving_controller.rbは、
自動生成済みなので、それを編集します。

  • app/controllers/saving_controller.rb
class SavingController < ApplicationController
    def new
        @saving = Saving.new
    end

フォームを表示するために、
newメソッドの定義が必要です。
@変数名 = モデル名.newで、
データベースのオブジェクトを@変数名に格納します。
ControllerはDBに投入する処理でもう少しいじることになります。
まだ完成形ではありません。

他には以下のような準備が必要です。

  • routes.rbの編集 config/routes.rbに2行追加します。
  • get '/saving_setting' => "saving#new"
    「/saving_settingにアクセスしたら、savingコントローラのnewアクションを実施しなさい」
    と、定義しています。
  • post 'savings' => "saving#create"
    「テーブルsavingsにPostされたら、savingコントローラのcreateアクションを実施しなさい」
    と、定義しています。

  • Viewの紐づけ newアクションが実行されたら表示するために、
    Viewのファイルはnew.html.erbという名前になっています。

ここまでやると、画面からフォームが見れます。
登録ボタン押しても、まだ動きません。

f:id:blue-38:20191129130820p:plain

4. DBにフォームの入力値を登録してみる

入力値の登録処理は、
コントローラに定義していきます。
下記のようになります。

  • app/controllers/saving_controller.rb
class SavingController < ApplicationController
    def new
        @saving = Saving.new
    end
    def create
        @saving = Saving.create(
            date: Date.new(saving_params["date(1i)"]&.to_i, saving_params["date(2i)"]&.to_i, saving_params["date(3i)"]&.to_i),
            amount: saving_params[:amount]
        )
        redirect_to '/saving_setting'
    end
    private

        def saving_params
            params.require(:saving).permit(:date, :amount)
        end
end

ポイントを押さえていきます。

createメソッド

やり方はいくつかあるようですが、
私は、モデル名.createでレコードを生成させました。

    def create
        モデルのオブジェクト変数 = モデル名.create(
            カラム名: 値
            …
        )
        redirect_to '登録ボタン押したらリダイレクトさせるパス
    end

フォームのdate_selectから渡される値に癖があったので、
以下の記事が参考になりました。

Ruby on Rails - date_selectの値がデータベースに登録できない|teratail

格納先のDBカラムの型はdate型なのですが、
フォームから受け取っている値は、
ハッシュ型(xxx:n, yyy:n, zzz:n)の数値だったので、
Date.newで加工する必要がありました。

ストロングパラメータ

Viewから渡されるparamsを受け取るために、
ストロングパラメータというものを使います。

Rubyのストロングパラメータ(Strong Parameters)を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン

DBを更新するのに必要なパラメータだけを受け取るために
ストロングパラメータを定義する必要があります。

    private

        def ストロングパラメータ名
            params.require(:モデル名).permit(:DBカラム名)
        end

ここで受け取って、
先述のcreateメソッド部分で、
amount: saving_params[:amount]のように使ってます。

ここまでで、DBにデータを投入する仕組みが整いました。

確認方法

え、ほんとにDBに入ったの?
って確認する方法を紹介します。

こんな感じでフォームに入れてもらって、
「登録」ボタンを押します。

f:id:blue-38:20191129131233p:plain


rails dbconsoleを使います。

>rails dbconsole
SQLite version 3.30.1 2019-10-10 20:19:45
Enter ".help" for usage hints.
sqlite>
  • テーブル一覧表示
sqlite> .table
ar_internal_metadata  savings               schema_migrations
  • テーブル表示
sqlite> select * from savings;
1|2018-02-17|30000|2019-11-28 07:39:08.354420|2019-11-28 07:39:08.354420
2|2018-05-29|30000|2019-11-29 02:37:20.483411|2019-11-29 02:37:20.483411

入力値がDBに登録されているか確認できます。

5. DBの値を表示してみる

DBに値が入ったので、
いよいよWEB画面に表示させてみます。

Viewをいじります。
私は、登録フォームの下に表示されるようにしました。

  • new.html.erb
<h1>貯蓄管理</h1>
<h2>貯蓄入力</h2>

<%= form_for @saving do |f| %>

    <div class="field">
      <%= f.label :date, "日付" %>
      <%= f.date_select(
        :date,
        use_month_numbers: true,
        start_year:        2018,
        date_separator:    '/') %>
    </div>
  
    <div class="field">
      <%= f.label :amount, "金額 ¥" %>
      <%= f.number_field :amount %>
    </div>
    
    <div class="actions">
      <%= f.submit "登録" %>
    </div>
  <% end %>

  <h2>貯蓄履歴</h2>
  <table border="1">
  <tr>
    <th>日付</th>
    <th>金額</th>
  </tr>
  <% @list.each do |set| %>
  <tr>
    <td><%= set.date %></td>
    <td><%= set.amount %></td>
  </tr>
  <% end %>
  </table>

上記の<h2>貯蓄履歴</h2>からが追記箇所です。

表の作り方は、HTML記法に倣ってますが、
DBから値を引っ張ってくるrails独自の記法は下記の部分です。

<% モデルのオブジェクト変数.each do |文字列| %>
 …(省略)…
<%= 文字列.カラム名 %>
 …(省略)…
<% end %>

モデルのオブジェクト変数は、
Controllerで定義しておく必要があります。

  • saving_controller.rb
class SavingController < ApplicationController
    def new
        @saving = Saving.new
        @list = Saving.all
    end
    (以下略)

全カラムの全レコードを@listに格納するように、
newメソッドで定義しました。
@list = Saving.all

これで、下記のように、
DBの値がWeb画面に表示されました。

f:id:blue-38:20191129131246p:plain

まとめ

伝えたいことは、 独学でも、 ググりながら格闘すれば、 何とかそれっぽいWEBアプリができそうだということです。