0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Railsでポケモン図鑑を作ろう

Last updated at Posted at 2023-05-12

はじめに

本投稿は講義資料であり、Rubyの基礎は理解しているが、Ruby on Railsチュートリアルで躓く読者を対象としています。

今回作るものの完成図

ポケモン図鑑一覧ページ

image.png

ポケモン詳細ページ

スクリーンショット 2023-04-19 12.42.11.png

ポケモン登録ページ

スクリーンショット 2023-04-19 12.42.37.png

今回はポケモンずかんの開発を進める中で、webサービス開発の基礎知識を学んでいきます。

講義は基本的にテキスト通りに進めますが、
講師が実際に現場で使われている経験や知識を交えながら進行していきます。
区切りの良いところで止めて、教室を見回るので詰まっている方は気軽に呼び止めてください。

目次

Railsでポケモン図鑑を作ろう ◀ いまここ
Railsでポケモン図鑑を作ろう 課題


前置き:講義を進める前に注意事項

1. コマンドについて

本資料では、下のような画像を多数載せています。
これらにはターミナルに打ち込むコードや、プログラムを記述しています。

行頭に>と記述されている行は、ターミナルへのコマンドであることを示しています。

その下の行は、コマンドの実行結果です

コードをコピーする際は行頭の>を除いてください。

↓サンプル↓
コマンドプロンプト(1行ずつ実行してください)
> cd /D Z:\ 
> mkdir rails_app
> cd rails_app
> rails new pokemon_zukan
2.記述場所

↓サンプル↓ 

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

  def show
  end

  def new
  end
end

コードを記述するファイルの場所は、枠内左上に記載しています。
(このコードだと場所はapp/controllers/pokemons_controller.rb)
どこに書くのか確認しつつすすめてください。
(新しくファイルを作成する場合もあれば、既に作成されているファイルに追記する場合もあります)


本テキストではポケモン図鑑を作りながら、Railsでのwebアプリケーション
開発を学んでいきます。

まず下記の2つのページの解説を読んでください。

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


Webフレームワーク -MVCとは

MVCに関しては後でも説明するので、いまはふわっとした理解で大丈夫です。

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

MVC-02.png

例) /usersのindexページをブラウザで開くという操作を行う時

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

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

下準備

1.Railsアプリケーションを作成する

まずはRailsアプリケーションを作成しましょう。
コマンドプロンプトを開き、(左下のwindowsのアイコンをクリック→検索バーににcmdと入力すると検索結果が表示されますので、その中から「コマンドプロンプト」をクリックして下さい)
>からコマンドを入力してEnterキーを押して実行します。

image.png

Zドライブ > rails_app > pokemon_zukan を作業ディレクトリとしたい場合を例に講義を進めていきます。

下の4つのコマンドを1つずつ実行してください。

コマンドプロンプト(1行ずつ実行してください)
> cd /D Z:\ 
> mkdir rails_app
> cd rails_app
> rails new pokemon_zukan

コマンドの説明を軽く説明します。
cdchange directoryの略でディレクトリを移動する時に使用します。
mkdirmake directoryの略でディレクトリを作成する時に使用します。
rails newは 新しいRailsアプリケーションを作成する時に使用します。

自分が今どのフォルダにいるか確認したい場合は、@cdコマンドで確認できます。

下の画像のようにコマンドを入力するところに戻ったら、Railsアプリケーションが正常に作られています。
スクリーンショット (15).png

次にrails sを実行して、ブラウザで表示してみましょう。

rails sコマンド(rails serverの略です)を実行すると、開発用のPC上でWebブラウザを経由してRailsアプリケーションにアクセスすることができます。
下の2つのコマンドを1つずつ実行してください。

コマンドプロンプト(1行ずつ実行してください)
> cd pokemon_zukan
> rails s

Use Ctrl-C to stopと出たらwebブラウザでアクセスができるようになります。
スクリーンショット (16).png

ブラウザを立ち上げて http://localhost:3000 にアクセスすると、Railsアプリケーションが動作します。

下記の画像のようになっていれば、正常に動作しています!
スクリーンショット (58).png


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

今回はBulmaというCSSフレームワークを使用します。

erbファイルに追記する

Visual Studio Code等のエディタにてファイルにコードを書いていきます。

app/views/layouts/application.html.erbをエディタで開いてください。

下記のコードを
<%= csp_meta_tag %>の下の空いてる行にコピー&ペーストしてください。

app/views/layouts/application.html.erb
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">

  

結果
スクリーンショット (37).png

2.Font Awesomeの導入

次に、webフォントアイコンを導入しましょう。

webフォントアイコンとは

HTMLのタグや特有のクラス名を付与することで、簡単にWebサイト上にアイコンを表示できるサービス。
フォントとしてアイコンを利用することができるので、CSSで簡単にサイズや色を変更できるため、使い勝手にも優れている。

font-awesome-sassというgemを使用します。
まずはGemfileを開きましょう。
pokemon_zukanのGemfileをクリックすると、下の画像の様なコードが表示されると思います。
スクリーンショット 2023-05-24 17.03.06.png

開いたGemfileの4行目のruby "2.7.6"の下に
gem 'font-awesome-sass'を追加しましょう。

Gemfile(下記の1行を追記してください)
gem 'font-awesome-sass'

結果
スクリーンショット 2023-05-12 16.58.17.png

追記したら上書き保存しましょう。(Ctrlキーを押しながらSキーを押す)

現在起動中のコマンドプロンプトは、railsサーバを実行しているため、新たに別のコマンドプロンプトを起動させてください。

新しく起動したコマンドプロンプトで下の3つのコマンドを1つずつ実行します。

コマンドプロンプト(1つずつ実行してください)
> cd /D Z:\ 
> cd rails_app/pokemon_zukan
> bundle install

bundle installとは先程Gemfileに入力したfont-awesome-sassを使えるようにするコマンドです。

Bundle complete!と表示されるとインストール完了です。

stylesheetの編集

まずはapplication.cssを右クリック⇒名前を変更(Rename)より
application.scssにファイル名を変更してください。

スクリーンショット (21).png

application.scssをVisual Studio Code等のエディタで開いて、
一番下に下の1行を追加します。

app/assets/stylesheets/application.scss
// ( #### 省略 #### )
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */

 @import 'font-awesome';  // これを追加する

上記の方法でRailsにFontAwesomeが入らない人はこの記事を見てください

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

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

3.1 Active Strageのインストール

Active StrageをRailsアプリケーションに追加します。
コマンドプロンプトで下記のコマンドを1行ずつ実行してください。

コマンドプロンプト(1行ずつ実行してください)
> rails active_storage:install
> rails db:migrate

  
rails active_storage:installをした結果👇

> rails active_storage:install
Copied migration 20230711043149_create_active_storage_tables.active_storage.rb from active_storage

rails db:migrateをした結果👇

数字は人によって異なります
> rails db:migrate
== 2023071104314[ここの日付は人により異なります] CreateActiveStorageTables: migrating ========================
-- create_table(:active_storage_blobs, {:id=>:primary_key})
   -> 0.0035s
-- create_table(:active_storage_attachments, {:id=>:primary_key})
   -> 0.0023s
-- create_table(:active_storage_variant_records, {:id=>:primary_key})
   -> 0.0014s
== 20230711043149 CreateActiveStorageTables: migrated (0.0099s) ===============

3.2 Gemfile に追加

Gemfileの6, 7行目あたり(先程追加したgem 'font-awesome-sass'の下)に下記の2つのGemを追記し上書き保存した後、bundle installを実行してください。

Gemfile(下記の2行を追記してください)
gem 'mini_magick'
gem 'image_processing', '~> 1.2'

追記した結果👇
スクリーンショット 2023-05-12 15.39.00.png

コマンドプロンプト(ターミナルで実行してください)
> bundle install

ここでも
Bundle complete!
と表示されていたらOKです

3.3 config/application.rbの編集

エディタでconfig/application.rbを開いてください。

12行目にあるconfig.load_defaults 7.0の下に下記の1行を追記してください。

config/application.rb
config.active_storage.variant_processor = :mini_magick

   
 
追記した結果↓
スクリーンショット 2023-05-12 15.51.04.png
追記したら上書き保存し、サーバを再起動してください。

新たにgemを入れたあとはサーバーを起動し直しましょう。
でないと、追加したgemが反映されません。

rails sを実行してるコマンドプロンプトをクリックしアクティブにした状態でCtrl + C を同時に押すとサーバーを止めることができます。

もう一度rails sを実行してください

【サーバーが起動しないときの対処法 2つ】
A:
Ctrl + C せずにターミナルを消してしまったときに、rails serverを再起動できないことがあります。下記のコマンドでPIDを指定しタスクを終了させることができます。

PIDが仮に 12345 であるなら↓

>taskkill /pid 12345 
(実際には終了させたいプロセスIDを入力してください)

 PIDは rails s実行時に下記のように表示されています。

         PID: 16672
* Listening on http://[::1]:3000
* Listening on http://127.0.0.1:3000
Use Ctrl-C to stop

B:
 rails サーバを別のポートを指定して起動することもできます。

> rails s -p 3001

その場合、アプリケーションを確かめるには ブラウザのURL欄より
http://localhost:3001
を開いてください。

4. protect_from_forgeryの追加

app/controllers/application_controller.rbの3行目にprotect_from_forgeryを追記してください。

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

これで下準備は完了です。
次にページを作っていきます。

ページを作成する方法

ポケモン図鑑一覧ページ

image.png

ポケモン詳細ページ

スクリーンショット 2023-04-19 12.42.11.png

ポケモン登録ページ

スクリーンショット 2023-04-19 12.42.37.png

ページを作成するにはcotrollerとviewが必要になります。

Controller と View の作成

作成は基本的に generate コマンドを用います。
(gは generateコマンドの短縮形です)
gの後は、controller に続けて、コントローラーの名前(複数形)を書きます。

rails g controller Pokemons index show new

そのうしろ(引数といいます)に書いたもの(index,show,new)は、
同名のviewとアクションが自動生成されます。

(Viewは views/pokemons の中に、アクションは app/pokemons_controller.rbの中に生成されています`)

コマンドプロンプト
> 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

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

コマンドプロンプト
> 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に対するリクエストがあれば、 pokemons_controllerindex アクションを呼び出すというものです。
今回indexアクションの中身が空なので、Model は呼び出されず、単に対応するView (index.html.erb) が実行されるだけです。(MVCの図の3,4,5の部分が素通りされます)

ルーティングがうまくいってみるか確認するために、試しにアクセスしてみましょう。
(サーバーを起動していない場合はコマンドプロンプトでrails sを実行してください)

indexページにアクセスしてみましょう。
localhost:3000/ に続いて
pokemons/indexを追記してアクセスしてください。

スクリーンショット 2023-05-16 14.08.45.png

このように表示されていることを確認してください
ここで準備したCSSフレームワークが適用されているか確認してください。
(画像と同じスタイルになっていたら正しく適用されています。)

教材配布 > 基礎演習 > images にあるPNG画像12枚をapp/assets/imagesフォルダ内に移動させてください。
フォルダごとではなく中にある画像12枚を移動させてください。

デザインの変更

まずはpokemons.scssというファイルを新規作成します。
(新規ファイルは、コードエディタのNew Text File等から作成可能です)

pokemons.scssをコードを追記します。

"▶"マークをクリックすると、pokemons.scssのコードが表示されます。

表示されたコードを app/assets/stylesheets/pokemons.scss にコピー&ペーストして上書き保存してください。

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

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

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

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

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

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

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

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

Viewの変更

Viewを変更してみましょう。
indexページに「ポケモンいちらん」という文字を表示させる為に

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/chapters/filling_in_the_layout?version=5.0#sec-partials
を読むことでより深く理解できます

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

findメソッドは主キー(RailsではID)を指定して1件のレコードを取得するメソッドです。
引用元【Rails】findとwhereの違いを徹底解説【初心者向け】

しかし、このままpokemons/showにアクセスしても
uninitialized constant PokemonsController::Pokemonというエラーがでます。
スクリーンショット (61).png

(Modelも、ポケモンの情報も作っていないからです)

ですので、次は先程使用したrails gコマンドを使用して、Modelを作成していきます。

情報のやりとり(データベース) の使用方法

Modelの作成

次にデータベースを作ります。
データベースについて分からない人は下の記事を読んで理解しましょう。

pokemonsテーブルには、
ポケモンの名前(name) : string型(文字列)
図鑑番号(公式の図鑑番号を使います)(number): integer型(数値)
ポケモンのタイプ(zokusei): string型(文字列型)
ポケモンの説明(description): text型(長い文字列型)
ポケモンの画像(image): attachment型(ActiveStorage用の属性を追加するときに使う)
を持たせていきます。

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

コマンドプロンプト
> 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を実行すると読み込まれ、データベースに反映されます。
rails db:migrateを実行しましょう。

コマンドプロンプト
> rails db:migrate
== 20220426050238 CreatePokemons: migrating ===================================
-- create_table(:pokemons)
   -> 0.0052s
== 20220426050238 CreatePokemons: migrated (0.0058s) ==========================

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

db/migrate/[作成日付]_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.rbにコードを書いて読み込む必要があります。

大量のデータを手入力するのは手間なので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/kame-ru.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
unning via Spring preloader in process 6309
Loading development environment (Rails 6.0.3.2)
irb(main):001:0>  (ここにコマンドを入力する)

このような文字が表示されたらコンソールは起動されています。
irb(main):001:0>に下記のコマンドを1行ずつ入力していきます。

(irb(main):001:0に以下のコマンドを1行ずつ入力して実行してください)
>> p = Pokemon.find(1)
>> p

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

コンソール
irb(main):001:0> p = Pokemon.find(1)
  Pokemon Load (0.2ms)  SELECT "pokemons".* FROM "pokemons" WHERE "pokemons"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=>
#<Pokemon:0x00000274bee2c608
...
irb(main):002:0> p
=>
#<Pokemon:0x00000274bee2c608
 id: 1,
 name: "フシギダネ",
 number: 1,
 zokusei: "くさ",
 description: "うまれてから しばらくの あいだは せなかの タネから えいようを もらって おおきく そだつ。",
 created_at: Tue, 11 Jul 2023 06:35:19.247315000 UTC +00:00,
 updated_at: Tue, 11 Jul 2023 06:35:19.837892000 UTC +00:00>
irb(main):003:0>

コンソールから出る場合は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>

localhost:3000/pokemons/show
にアクセスすると、フシギダネの情報が表示されたかと思います。
image.png

フシギダネが表示されずに
Can't resolve image into URL: undefined method persisted? for nil:NilClassとエラーが出た場合、以下のコマンドを1行ずつ実行しなおしてみてください。

コマンドプロンプト(1行ずつ実行してください)
> rails db:drop
> rails db:setup
> rails db:migrate
> rails db:seed

このコマンドはデータベースを作り直し、seed.rbを読み込んでいます。

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

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

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

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

params[:id]について
paramsは送られてきたパラメーターを入れる箱のようなメソッドです。
パラメーター(情報)はコントローラーはそのままの形で受け取れません
なので箱に入れてから送ります

送られてくる情報(リクエストパラメータ)は主に、getのクエリパラメータとpostでフォームから送信されるデータの2つです

params[:カラム名]で値を受け取ることができます。

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

パラメーター(数値)は、どこで指定すればよいでしょうか。
URLにパラメーターを含めて渡すテクニックがあるので覚えておきましょう。
例)IDが2のポケモンの情報を取得したい場合 
localhost:3000/pokemons/show/2
  このままではルーティングエラーが表示されます。config/routes.rbを見ると
  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のポケモンの情報を取得できるようになりました。

localhost:3000/pokemons/show/2

スクリーンショット 2023-04-19 12.31.03.png

localhost:3000pokemons/show/3

スクリーンショット 2023-04-19 12.31.53.png

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_with

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

app/controllers/pokemons_controller.rb
  # (中略)
  def new
    @pokemon = Pokemon.new # これを追加する
  end

ここまでのapp/controllers/pokemons_controller.rbです。
自分のコードとあってるか確認してください。

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

  def show
    @pokemon = Pokemon.find(params[:id])
  end

  def new
    @pokemon = Pokemon.new
  end
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 アクションに飛ばしたいです。
(後ほどデータベースに保存する処理をpokemons_controller.rbの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キー のデータを取得しています )
 連想配列について詳しくはこちらを参照してください 

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

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 @pokemon
end

最後の、redirect_to @pokemonの部分ですが、
登録ボタンを押したあとに、作成したポケモンの詳細ページに画面遷移してほしいので、リダイレクト先を指定しました。

http:localhost:3000/pokemons/new ここでポケモンの情報を登録

スクリーンショット 2023-04-19 12.32.59.png

localhost:3000/pokemons/show/[ID]
ここで登録内容を確認

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

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

バリデーション

バリデーションとは

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

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

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

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

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

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

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
  if @pokemon.save # も保存が成功した時の処理
	redirect_to controller: :pokemons, action: :index
  else #バリデーションにひっかかり、保存が失敗した時の処理
    render :new, status: :unprocessable_entity # もう一度登録ページにリダイレクトする
  end
end

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

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

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

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

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

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

今までshowアクションやnewアクションでは@pokemonと単数形になっていたのに、
indexアクションでは@pokemonsと複数形になっています。
分かりやすく説明してる記事があるので、参考にしてください。

ビューの編集

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 %>
          <div class="subtitle has-text-centered">
            <p> NO. <%= p.number %> </p>
            <p class="title has-text-centered"><%= link_to p.name, pokemon_path(p) %></p>
          </div>
        </div>
      </div>
      <% end %>
  </div>
</div>

スクリーンショット 2023-04-19 12.39.04.png

このようにseed.rbで入れたデータや自分で入力したデータが表示されていれば完成です、お疲れ様でした!

ポケモン図鑑一覧ページ

スクリーンショット 2023-04-19 12.41.37.png

ポケモン詳細ページ

スクリーンショット 2023-04-19 12.42.11.png

ポケモン登録ページ

スクリーンショット 2023-04-19 12.42.37.png

0
0
0

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
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?