LoginSignup
0

posted at

updated at

Before Rails Tutorial ポケモン図鑑をつくろう

はじめに

本投稿は講義資料であり、Rubyの基礎は理解しているが、rails tutorialで躓く読者を対象としています。

目次

1章: 環境構築
2章: ポケモン図鑑をつくろう ⇐ 今ここ


本章ではいよいよRailsアプリケーションを開発していきます。
その前に、Railsで開発する上で必要な知識を解説していきます。

Webページが表示される仕組み


MVC

MVCに関しては本章以降でも学んでいくので、いまはふわっとした理解で大丈夫です。

Modelは、データベースとのやりとりを担う
Viewは、表示関連全般を担う
Controllerは、橋渡しの役割を担う

MVC-02.png

1, ブラウザから /users へのリクエストを Rails sever に送信する
2, router によって、/users は Users controller の index アクションを呼び出す
3, index アクションから、User Model が呼び出される
4, User Model は DataBase からデータを取り出す
5, 取り出したデータを、Controller に返す
6, 受け取ったデータを @users に保存し、 View (indexアクションなので index.html.erb) に渡す。
7, ERBを実行し、@users のデータを含んだ HTMLを生成し、Controller へ返す
8, Controller は、受け取ったHTMLをブラウザにわたす

今後もModel View Controller を構築していくので、適宜図を見返してください。

下準備

1. CSSフレームワークを導入してみよう

このままだと味気ないデザインなので、CSSフレームワークを導入してそれっぽくしてみましょう。
今回はBulmaというCSSフレームワークを使用します。
CSSとは?
Bulma 公式サイト

erbファイルに追記する

app/views/layouts/application.html.erbに下記を追加します。
 

goorm内左側から
pokemon_zukanフォルダをクリック
appフォルダをクリック
layoutsフォルダをクリック
application.html.erbをクリックすると中央にエディタ(コードを書く場所)が出るので、ここで編集してください。
編集後は必ず保存をしましょう。
スクリーンショット 2022-06-28 13.55.18.png

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>PokemonZukan</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    
     <!-- 下の1行を追加する-->
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
         <!-- ここまで -->
     <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
     <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

2.画像アップロードの準備

アプリケーションにポケモンの画像を投稿する機能を追加したいので、
Rails5.2より追加されたActive Strageという公式で公開されたファイルアップロード機能を使用します。
【Rails】 Active Storageを使って画像をアップしよう!

ImageMagickを導入

ターミナルで下記を実行してください。

terminal(1行ずつ実行してください)
$ sudo apt-get update
$ sudo apt-get install libmagickwand-dev
$ sudo apt-get install imagemagick --fix-missing

rails sを実行したまま、コマンドを実行したい場合、
新しくターミナルを開く必要があります。
goormの場合 > goorm内上部のWINDOW>New Terminal Window(一番上)をクリックすると起動します。

PaizaCloudの場合 > PaizaCloud内左側のターミナルをクリックすると起動します。

Active Strageのインストール

Active StrageをRailsアプリケーションに追加します。
ターミナルで以下を実行してください。

terminal(1行ずつ実行してください)
$ rails active_storage:install
$ rails db:migrate

Gemfileの編集

Gemfileの27,28行目あたりにに下記を追加して、bundle installをしてください。

Gemfile
gem 'mini_magick'
gem 'image_processing', '~> 1.2'
terminal
$ bundle install

新たにgemを入れたあとはrails sをし直しましょう。
rails sを実行してるターミナルでCtrl + c をしてサーバーを止めてから
rails sを入力して実行してください

3. protect_from_forgeryの追加

RailsのCSRF対策について
app/controllers/application_controller.rbに下記を追記してください。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
 protect_from_forgery # これを追加する
end

これで下準備は完了です。


Controller と View の作成

作成は基本的に generate コマンドを用います。
(gは generateコマンドの短縮形です)
gの後は、controller に続けて、コントローラーの名前(複数形)を書きます。
rails g controller Pokemons index show new
そのうしろ(引数といいます)に書いたもの(index,show,new)は、
同名のviewとアクションが自動生成されます。
(Viewは views/pokemons の中に、アクションは pokemons_controllerの中に生成)

tarminal
$ rails g controller Pokemons index show new
     create    app/controllers/pokemons_controller.rb
     route     get 'pokemons/index'
               get 'pokemons/show'
               get 'pokemons/new'
     create    app/views/pokemons
     create    app/views/pokemons/index.html.erb
     create    app/views/pokemons/show.html.erb
     create    app/views/pokemons/new.html.erb

imagesフォルダ内の画像(4枚)をapp/assets/imagesフォルダ内に移動させてください。

pokemons.scssを編集します。(下記のファイルを丸々コピー&ペーストしてください)

app/assets/stylesheets/pokemons.scss
// =====  Pokemon/show ===== //
.pokemon-name {
  line-height: 65px;
  font-size: 25px;
  color: #f2f5ec;
  background-color: #344e67;
}

.p-type {
  display: inline;
  margin: 3em;
  font-size: 20px;
}

.p-description {
  color: #283b4f;
  background-color: #fff;
  font-size: 20px;
  line-height: 1.5;
  padding: 50px;
}

.pokemon-card {
  display: table;
  padding: 20px;
  background-color: #fff;
}

.p-name {
  display: table-cell;
  vertical-align: middle;
}

.vertical-middle {
  display: inline-block; 
  vertical-align: middle;
  
}

.p-edit {
  margin-top: 110px;
}

.p-edit a{
  margin-top: 60px;
  display: inline;
  font-size: 16px;
}

.alert {
    color:#262626; 
    background:#FFEBE8;
    text-align: center;
    border:2px solid #990000;
    padding:12px; font-weight:850;
  }

先程のrails g ...コマンドでルーティングが生成されているので、確認してみましょう。

terminal
$ rails routes
  Verb  URI                Pattern
  GET   /pokemons/index    pokemons#index
  GET   /pokemons/show     pokemons#show
  GET   /pokemons/new      pokemons#new

これは具体的には、 http://localhost:3000/pokemons/index
というURLに対するリクエスト1があれば、 pokemons_controllerindex アクションを呼び出すというものでした。
今回indexアクションの中身が空なので、Model は呼び出されず、単に対応するView (index.html.erb) が実行されるだけです。(図の3,4,5の部分が素通りされます)

ルーティングがうまくいってみるか確認するために、試しにアクセスしてみましょう。
(サーバーを起動させるときは、 $ rails s をタイプします)
http://localhost:3000/pokemons/index

Pokemons#index
Find me in app/views/pokemons/index.html.erb

と表示されていると思います。

Viewの変更

日本語にしておきましょう。erbの変更は前回行ったとおりですね。とてもシンプルなものでした。
app/views/pokemons/index.html.erbにあるコードを削除し、
下記を追記してください。

app/views/pokemons/index.html.erb
<h1 class="title has-text-centered">ポケモンいちらん</h1>

erb の中身がシンプルすぎて不思議な方もいらっしゃるかもしれません。
【気になって次にすすめない人向けの解説】
app/views/layouts/application.html.erb を開いてください。
コード内の= yieldの部分に、index.html.erbが移植されて HTML を生成しています。 
今はこの程度の理解で問題ありません。
https://railstutorial.jp/ でより深く理解できます

Controllerの変更

コントローラーの中にアクションが本当に作られているかも確認してみましょう。
app/controllers/pokemons_controller.rb を開いてみてください。

app/controllers/pokemons_controller.rb
class PokemonsController < ApplicationController
  def index
  end

  def show
  end

  def new
  end
end

データベース内のデータを取り出すには、Controllerのアクション内で
Model を呼び出すと取りだすことができます。

app/controllers/pokemons_controller.rb
class PokemonsController < ApplicationController
  def index
  end

  def show
    @pokemon = Pokemon.find(1) # これを追記
  end

  def new
  end
end

しかし、このままpokemons/showにアクセスしても
uninitialized constant PokemonsController::Pokemonというエラーがでます。
(Modelも、ポケモンの情報も作っていないからです)
ですので、次はgenerateコマンドを使用して、Modelを作成していきます。

Modelの作成

pokemonsテーブルには、
ポケモンの名前(name)
図鑑番号(number)
ポケモンのタイプ(zokusei)
ポケモンの説明(description)
ポケモンの画像(image)
を持たせていきます。

g の後は、model に続けて、Model名(単数形)、そして項目(カラムといいます)を書きます。

terminal
$ rails g model Pokemon name:string number:integer zokusei:string description:text image:attachment
      invoke  active_record
      create    db/migrate/20220426050238_create_pokemons.rb
      create    app/models/pokemon.rb
      invoke    test_unit
      create      test/models/pokemon_test.rb
      create      test/fixtures/pokemons.yml

作成・編集したマイグレーションファイルはターミナルでrails db:migrateを実行すると読み込まれ、
データベースに反映されます。

terminal
$ rails db:migrate
== 20220426050238 CreatePokemons: migrating ===================================
-- create_table(:pokemons)
   -> 0.0052s
== 20220426050238 CreatePokemons: migrated (0.0058s) ==========================

db/migrate/(作成日時)_create_pokemons.rb というファイルを見てみましょう。
開いてみると、下記のようなコードがあると思います。

[作成日付]_create_pokemons.rb
class CreatePokemons < ActiveRecord
  def change
    create_table :pokemons do |t|
      t.string :name
      t.integer :number
      t.string :zokusei
      t.text :description
      t.timestamps
    end
  end
end

上記は string型であるnameというカラム(他5つ)を持つ pokemons テーブルを作成せよという意味です。 change 意外に up down などもあります。詳細は下記サイトなどを参照ください
【Rails入門】データベースを設定するrails db:migrateを説明!


これでpokemonsテーブルが作成されました。

テーブルは作成したけども、ポケモンの情報はまだ何もいれてませんね。
初期データをいれるには db/seeds.rb2 ファイルを使用します。
( seed = 種 という意味です )
大量のデータを入力するのは手間なのでseed.rbを作成していきます。
(そもそもブラウザからデータをいれる機能もまだ作っていません)

seed.rbを編集しましょう。
もともとあるコードを削除し、下記を追記してください。

db/seeds.rb
pokemon = Pokemon.create(name: "フシギダネ",
						 zokusei: "くさ",
						 number: 1,
						 description: "うまれてから しばらくの あいだは せなかの タネから えいようを もらって おおきく そだつ。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/hushigidane.png')),
                  filename: 'hushigidane.png')

pokemon = Pokemon.create(name: "フシギソウ",
						 zokusei: "くさ",
						 number: 2,
						 description: "せなかの つぼみが ふくらみだすと あまい においが ただよいはじめる。たいりんの はなが さく まえぶれ。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/hushigisou.png')),
                  filename: 'hushigisou.png')

pokemon = Pokemon.create(name: "フシギバナ",
						 zokusei: "くさ",
						 number: 3,
						 description: "あめの ふった よくじつは せなかの はなの かおりが つよまる。かおりに さそわれ ポケモンが あつまる。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/hushigibana.png')),
                  filename: 'hushigibana.png')


pokemon = Pokemon.create(name: "ヒトカゲ",
						 zokusei: "ほのお",
						 number: 4,
						 description: "ヒトカゲの ほのおの しっぽは いのちの ともしび。 げんきなときは ほのおも ちからづよく もえあがる。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/hitokage.png')), filename:'hitokage.png')

pokemon = Pokemon.create(name: "リザード",
						 zokusei: "ほのお",
						 number: 5,
						 description: "リザードが くらす いわやまを よなかに みあげると しっぽの ほのおが ほしのように みえる。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/riza-do.png')), filename:'riza-do.png')

pokemon = Pokemon.create(name: "リザードン",
						 zokusei: "ほのお",
						 number: 6,
						 description: "くるしい たたかいを けいけんした リザードンほど ほのおの おんどが たかくなると いわれている。
")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/riza-don.png')), filename:'riza-don.png')



pokemon = Pokemon.create(name: "ゼニガメ",
						 zokusei: "みず",
						 number: 7,
						 description: "こうらに とじこもり みを まもる。 あいての すきを みのがさず みずを ふきだして はんげきする。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/zenigame.png')),
                  filename: 'zenigame.png')

pokemon = Pokemon.create(name: "カメール",
						 zokusei: "みず",
						 number: 8,
						 description: "いちまんねんの じゅみょうを もつと いわれている。ふさふさの しっぽは ながいきの シンボルとして にんき。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/zenigame.png')),
                  filename: 'kame-ru.png')

pokemon = Pokemon.create(name: "カメックス",
						 zokusei: "みず",
						 number: 9,
						 description: "こうらの ふんしゃこうの ねらいは せいかく。みずの だんがんを 50メートル はなれた あきかんに めいちゅうさせる ことが できるぞ。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/kamekkusu.png')),
                  filename: 'kamekkusu.png')


pokemon = Pokemon.create(name: "イーブイ",
						 zokusei: "ノーマル",
						 number: 133,
						 description: "しんかのとき すがたと のうりょくが かわることで きびしい かんきょうに たいおうする めずらしい ポケモン。")
pokemon.image.attach(io: File.open(Rails.root.join('app/assets/images/i-bui.png')),
                  filename: 'i-bui.png')

そしてデータの読み込みをrails db:seedで行います。

terminal
$ rails db:seed

データが保存されたかの確認はrails cでコンソールを起動すると確認できます。

terminal
$ rails c
railsConsole
> p = Pokemon.find(1) # 入力して実行
   (54.0ms)  SELECT sqlite_version(*)
  Pokemon Load (0.2ms)  SELECT "pokemons".* FROM "pokemons" WHERE "pokemons"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Pokemon id: 1, name: "フシギダネ", number: 1, zokusei: "くさ", description: "うまれてから しばらくの あいだは せなかの タネから えいようを もら
って おおきく そだつ。", created_at: "2022-07-12 06:22:59", updated_at: "2022-07-12 06:22:59">
> p 
=> #<Pokemon id: 1, name: "フシギダネ", number: 1, zokusei: "くさ", description: "うまれてから しばらくの あいだは せなかの タネから えいようを もら
って おおきく そだつ。", created_at: "2022-07-12 06:22:59", updated_at: "2022-07-12 06:22:59">

フシギダネの情報がimage以外表示されていたらOKです。

コンソールから出る場合はexitを入力すると戻る事が出来ます。

フシギダネの情報をページ上で表示させたいので、
app/views/pokemons/show.html.erbを下記のように編集しましょう。

app/views/pokemons/show.html.erb
<div class="pokemon-name">
  <div class="container">
    <p style="display: inline; padding-left: 40px;">
      NO.<%= @pokemon.number %>
      <%= @pokemon.name%>
    </p>
        
    <p class="p-type">
      <%= @pokemon.zokusei %>
    </p>
  </div>
</div>

<div class="columns">
      <div class="column is-4">
        <div class="pokemon-img">
          <%= image_tag @pokemon.image %>
        </div>
     </div>
    
      <div class="column is-8">
        <div class="p-description">
          <%= @pokemon.description %>
        </div>
      </div>
    </div>
  </div>
</div>

http://localhost:3000/pokemons/show
にアクセスしてください。
フシギダネの情報が表示されたかと思います。

課題1

@pokemon はどこで定義しましたか。

URLからパラメーターの取得

ポケモンのデータを取り出して表示するところまでうまくいきました!
すごい進歩です!

ただ、まだ不満点があります。
それは、 id:1 のポケモンのデータしか表示できていない点です。
理由は、Contoroller の show アクションをみると、
@pokemon = Pokemon.find(1)
となっているためです(id:1 のポケモンの情報しか見つけてきていない)

ここをidパラメーターが1以外も入力できるように変更するにはどうすればよいでしょうか。
@pokemon = Pokemon.find(params[:id])
とすることで、1以外のパラメーターを見つけてこれます。

app/controllers/pokemons_controller.rb
 def show
   @pokemon = Pokemon.find(params[:id]) # 変更する
 end

パラメーター(数値)は、どこで指定すればよいでしょうか。
URLにパラメーターを含めて渡すテクニックがあるので覚えておきましょう。
例)IDが2のポケモンの情報を取得したい場合 http://localhost:3000/pokemons/show/2
  このままではルーティングエラーが表示されます。
  pokemons/show へのリクエストに関しては記述していますが、
  pokemons/show/(数字) へのリクエストについては何も書いていない為です。

config/routes.rb を開いてください。
URLに含まれる数字をパラメーターとして取得するには、下記のように記述します。

config/routes.rb
Rails.application.routes.draw do
  get 'pokemons/index'
  get 'pokemons/show/:id', to:'pokemons#show', as: 'pokemon' # 変更する
  get 'pokemons/new'

end

こうすることで /pokemons/show/2 の 2の部分が、:id パラメーターとして利用可能になります。
( 利用するときは、params[:id] と書きます)

index と new は to: が書かれていませんね。
前章でも説明したとおり、Railsは、アクションが呼び出されると、
自動的に アクション名.html.erbが呼び出されるので、
下記と同じ意味になります。
get 'pokemons/index' to: 'pokemonss#index'
get 'pokemons/new', to: 'pokemons#new'

to: 'pokemons#show' 
pokemonsコントローラーの show アクションを呼び出す指示になります。

これで、任意のidのポケモンの情報を取得できるようになりました。

http://localhost:3000/pokemons/show/1
http://localhost:3000/pokemons/show/2

Model 検索

今ポケモンの情報の取り出しに id を利用していますが、
id 以外のカラムを用いて取り出す方法も覚えておくと便利です。

コンソールを起動してください。 ( ターミナルでrails cで起動 )
下記を参考に色々と試してみてください。

railsコンソール
>> Pokemon.all
   #pokemonテーブルのすべてのデータを取得します。
>> Pokemon.find_by(name: "ヒトカゲ")
   #条件に合ったデータを、1件だけ取得します。
>> Pokemon.where(zokusei: "みず")
   #条件に合ったデータを、すべて取得します。
>> Pokemon.where(zokusei: "みず").where(number: 7)
   #AND検索。 みずタイプで ずかん番号番を取得しています。
>> Pokemon.where("(zokusei = ?) OR (number = ?)","みず",7)
   #OR検索。 みずタイプ または ずかん番号7番のポケモンを取得しています。
>> Pokemon.order(create_at: :asc)
   #並び順を指定します。 作成日時の昇順で取得しています。

データ登録フォームの作成

データベースから情報を取り出したり加工したりする方法は覚えました。
しかしこのままではポケモンを登録することができません。

ポケモンを登録するための機能を作成する方法を学んでいきましょう。
form_withを使用します。

form_wirh

参考↓
【Rails】 form_withの使い方を徹底解説!

データベースに新しいデータを保存したいので、 Model を呼び出します。
app/views/pokemons/new.html.erbに登録フォームを置きたいので、
pokemons_controller.rbのnewアクション内に書きましょう。
新しいデータを登録するときは、 Model名.new とします。下記のコードを追記してください。

app/controllers/pokemons_controller.rb
  # (中略)
  def new
+   @pokemon = Pokemon.new
  end

new.html.erbに入力フォームを作成していきましょう。
railsでは、フォームを簡単につくれるform_withヘルパーというものがあります。

app/views/pokemons/new.html.erb
<div class="container mt-6">
  <div class="columns">
    <div class="column is-three-fifths is-offset-one-fifth">
      <%= form_with model: @pokemon, url: { action: :create }, local: true do |f| %>
        <!-- 	エラーメッセージ	 -->
        <% if @pokemon.errors %>
          <% @pokemon.errors.full_messages.each do |message| %>
		    <div class='alert'>
		      <ul>
               <li><%= message %></li>
			  </ul>
			</div>
          <% end %>
       <% end %>
		<!-- 	ここまでエラーメッセージ	 -->
        <div class="field">
          <%= f.label :name, "なまえ", class: 'label'%>
          <div class="control">
            <%= f.text_field :name, class:'input'%>
          </div>
        </div>
        <div class="field">
          <%= f.label :number, "ばんごう", class: 'label' %>
          <div class="control">
            <%= f.text_field :number, class: 'input'%>
          </div>
        </div>
        <div class='field'>
          <%= f.label :zokusei, "タイプ", class: 'label' %>
          <div class="control">
            <%= f.text_field :zokusei, class: 'input'%>
          </div>
        </div>
        <div class="field">
          <%= f.label :description, "せつめい", class: 'label' %>
          <div class="control">
            <%= f.text_area :description, class: 'textarea' %> 
          </div>       
        </div>
        
        <div class="file">
          <label class="file-label"></label>
        </div>
        <br/>
        <br/>
        <div class="file is-boxed">
            <label class="file-label">
            <%= f.file_field :image, class: 'file-input'%>
              <span class="file-cta">
                  <span class="file-icon">
                      <i class="fas fa-upload"></i>
                  </span>
                  <span class="file-label">
                    <%= f.label :image, 'がぞう', class: 'label'%>
                  </span>
             </span>
          </label>
        </div>
        
        <%= f.submit "登録", class: 'button is-link'%>
      <% end %>
    </div>
  </div>
</div>

ここでは重要な部分だけ、簡単に解説します。
上の form_withヘルパーにより、下記のような HTML が生成されます。(少しシンプル化してます)

<form action="/pokemons" accept-charset="UTF-8" data-remote="true" method="post">
  <input type="hidden" name="authenticity_token" value="Nbbcp8B2ekJyks0THuIdAQcyafXQJdj7reyZeAkZbkLreXymKvbIwE6rL9pXcN58G2ZOrdlWFDHz5uXAkMNNqQ==">
        <div class="field">
          <label class="label" for="pokemon_name">なまえ</label>
          <div class="control">
            <input class="input" type="text" name="pokemon[name]" id="pokemon_name">
          </div>
        </div>
        <div class="field">
          <label class="label" for="pokemon_number">ばんごう</label>
          <div class="control">
            <input class="input" type="text" name="pokemon[number]" id="pokemon_number">
          </div>
        </div>
          
        <div class="field">
          <label class="label" for="pokemon_zokusei">タイプ</label>
          <div class="control">
            <input class="input" type="text" name="pokemon[zokusei]" id="pokemon_zokusei">
          </div>
        </div>
        
        <div class="field">
          <label class="label" for="pokemon_description">せつめい</label>
          <div class="control">
            <textarea class="textarea" name="pokemon[description]" id="pokemon_description"></textarea>        
        </div>
        
         <div class="field">
          <div class="file">
            <label class="file-label">
              <%= f.file_field :image, class: 'file-input'%>
              <span class="file-cta">
                <span class="file-label">
                がぞうをえらんでください
                </span>
              </span>
            </label>
          </div>
        </div>
        <input type="submit" name="commit" value="登録" class="button is-link" data-disable-with="登録">
    </div></form>

ここで重要な属性は、
<form action="/pokemons" accept-charset="UTF-8" data-remote="true" method="post">
の中の、 action="/pokemons"method="post" の2つです。

この2つは送信ボタンが押されたら、
/pokemons に対して、 POST リクエストを送信する
という指示をしています。

なので、 /pokemons に対して、 POST リクエストがあった場合の処理を書いていきましょう。
送信したあとは、pokemons_controller の create アクションに飛ばしたいです。
(後ほどデータベースに保存する処理を create アクションに書いていきます)

post 'pokemons', to: 'pokemons#create'
コードはこのようになるので、 routes.rb に追記しましょう。

config/routes.rb
Rails.application.routes.draw do
   get 'pokemons/index'
    get 'pokemons/show/:id', to:'pokemons#show', as: 'pokemon' # 変更する
   get 'pokemons/new'
   post 'pokemons', to: 'pokemons#create'  # 追記する
end

1. 登録ボタンが押される
2. フォームに入力されたデータを、create アクションに飛ばす

という流れで、データが動いているので最後に、
create アクションの中で情報をデータベースに保存する処理を書きます。Modelを呼び出します。

Parameters: {...(中略)... "pokemon"=>{"name"=>"フシギダネ", "number"=>"1", "zokusei"=>"くさ", "description"=>"(中略)"

パラメーターをみると、二重の連想配列になっているのがわかると思います。
( parameters{} の中に pokemon{} が入っている )

通常の連想配列の場合は、params[:title] として取得できていました。
二重の連想配列の場合は、params[:pokemon][:title] とすることで取得できます。
pokemonキー の中のtitleキー のデータを取得しています )
 連想配列について詳しくはこちらを参照してください Array(配列)とHash(連想配列)入門

さて、ここまで理解できていれば create アクションの中身も想像できると思います。
( seed.rb の、ポケモンの情報が書かれていた部分をパラメーターの中身に書き換えるだけです )
def new ~ endの下に下記を追記してください

app/controllers/pokemons_controller.rb
(中略)
def create
    @pokemon = Pokemon.new
    @pokemon.name = params[:pokemon][:name]
    @pokemon.zokusei = params[:pokemon][:zokusei]
    @pokemon.number = params[:pokemon][:number]
    @pokemon.description  = params[:pokemon][:description]
    @pokemon.image = params[:pokemon][:image]
    @pokemon.save
    redirect_to pokemons_index_path
end

最後の、redirect_to '/pokemons/show/1' の部分ですが、
登録ボタンを押したあとに、画面遷移してほしいので、リダイレクト先を指定しました。

http://localhost:3000/pokemons/new ここでポケモンの情報を登録
http://localhost:3000/pokemons/show/1 ここで登録内容を確認

このままでは自由にポケモンを登録できる状態です。
numberは数値を入力してもらいたいので入力制限をかけてみましょう。

Rails では制限(validation)も簡単に設定することができます。

バリデーション

バリデーションとは

データを保存する前に、無効なデータでないことを検証する機能のこと。門番みたいなもの。
空のデータが保存されないようにしたり、数字以外は保存できないようにしたり、文字数に制限を設けたり、保存するデータに制限をかける時に使います。

app/models/pokemon.rb を開き、
下記の2行をclass Pokemon ~~ endの間に入力してください。

numericality: true
属性に数値のみが使われている事を検証する
presence: true
必須項目にする

app/models/pokemon.rb
class Pokemon < ApplicationRecord
  has_one_attached :image
  validates :name, :image,  presence: true # 追記する
  validates :number, numericality: true # 追記する
end

これだけで制限を設けることができます。

次にpokemons_controller.rbcreateメソッドを編集します

app/controllers/pokemons_controller.rb
def index
(中略)
def create
  (中略)
  # ここから追加する
  if @pokemon.save
    redirect_to controller: :pokemons, action: :index
  else
    render "new"
  end
  # ここまで
end 

Pokemon Model に追記しているので、 pokemons テーブルの numberカラムに対して制限をかけます。
実際に試してみると、ポケモンいちらんに登録されていません。

これでポケモンのばんごうを数値以外入力して保存すると
上部にメッセージが出ます。
そして数値を入力して保存するとポケモンいちらんページに遷移先します
スクリーンショット 2022-06-28 16.42.58.png

ポケモン一覧ページの作成

しかし、これだとポケモンを登録しても
遷移先の localhost:3000/pokemons/index は何も表示されていません
最後に登録したポケモンを一覧するページを作成しましょう。

まずはコントローラーの編集です。
先程コンソールでPokemon.allを実行するとすべてのポケモンが表示されましたね。
それを利用しましょう。

app/controllers/pokemons_controller.rb
class PokemonsController < ApplicationController
  def index
    @pokemons = Pokemon.all # これを追加する
  end
end

ビューの編集

app/views/pokemons/index.html.erbを編集しましょう。

app/views/pokemons/index.html.erb
<div class="container mt-6">
  <h1 class="title has-text-centered"> ポケモンいちらん </h1>
  <div class="columns is-multiline">
    <% @pokemons.each do |p| %>
      <div class="column is-one-quarter">
        <div class="pokemon-card">
          <%= image_tag p.image.variant(resize_to_limit: [100, 100])%>
          <div class="p-name">
            <p> NO. <%= p.number %> </p>
            <p class="vertical-middle"><%= link_to p.name, pokemon_path(p) %></p>
          </div>
        </div>
      </div>
      <% end %>
  </div>
</div>

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0