はじめに
本投稿は講義資料であり、Rubyの基礎は理解しているが、Ruby on Railsチュートリアルで躓く読者を対象としています。
今回作るものの完成図
ポケモン図鑑一覧ページ
ポケモン詳細ページ
ポケモン登録ページ
今回はポケモンずかんの開発を進める中で、webサービス開発の基礎知識を学んでいきます。
講義は基本的にテキスト通りに進めますが、
講師が実際に現場で使われている経験や知識を交えながら進行していきます。
区切りの良いところで止めて、教室を見回るので詰まっている方は気軽に呼び止めてください。
目次
Railsでポケモン図鑑を作ろう ◀ いまここ
Railsでポケモン図鑑を作ろう 課題
前置き:講義を進める前に注意事項
1. コマンドについて
本資料では、下のような画像を多数載せています。
これらにはターミナルに打ち込むコードや、プログラムを記述しています。
行頭に>
と記述されている行は、ターミナルへのコマンドであることを示しています。
その下の行は、コマンドの実行結果です
コードをコピーする際は行頭の>
を除いてください。
↓サンプル↓
> cd /D Z:\
> mkdir rails_app
> cd rails_app
> rails new pokemon_zukan
2.記述場所
↓サンプル↓
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は、橋渡しの役割を担う
例) /usersのindexページをブラウザで開くという操作を行う時
- ブラウザから
/users
へのリクエストをRailsサーバーに送信する -
router
によって、/users
はUsers controller
のindex
アクションを呼び出す -
index
アクションから、User Model
が呼び出される -
User Model
はDataBase
からデータを取り出す - 取り出したデータを、
Controller
に返す - 受け取ったデータを
@users
に保存し、 View (indexアクションなので index.html.erb) に渡す。 - ERBを実行し、
@users
のデータを含んだ HTMLを生成し、Controller
へ返す -
Controller
は、受け取ったHTMLをブラウザにわたす
今後もModel View Controller を構築していくので、適宜図を見返してください。
下準備
1.Railsアプリケーションを作成する
まずはRailsアプリケーションを作成しましょう。
コマンドプロンプトを開き、(左下のwindowsのアイコンをクリック→検索バーににcmdと入力すると検索結果が表示されますので、その中から「コマンドプロンプト」をクリックして下さい)
>
からコマンドを入力してEnterキーを押して実行します。
Zドライブ > rails_app > pokemon_zukan を作業ディレクトリとしたい場合を例に講義を進めていきます。
下の4つのコマンドを1つずつ実行してください。
> cd /D Z:\
> mkdir rails_app
> cd rails_app
> rails new pokemon_zukan
コマンドの説明を軽く説明します。
cd
はchange directory
の略でディレクトリを移動する時に使用します。
mkdir
はmake directory
の略でディレクトリを作成する時に使用します。
rails new
は 新しいRailsアプリケーションを作成する時に使用します。
自分が今どのフォルダにいるか確認したい場合は、@cd
コマンドで確認できます。
下の画像のようにコマンドを入力するところに戻ったら、Railsアプリケーションが正常に作られています。
次にrails s
を実行して、ブラウザで表示してみましょう。
rails s
コマンド(rails server
の略です)を実行すると、開発用のPC上でWebブラウザを経由してRailsアプリケーションにアクセスすることができます。
下の2つのコマンドを1つずつ実行してください。
> cd pokemon_zukan
> rails s
Use Ctrl-C to stop
と出たらwebブラウザでアクセスができるようになります。
ブラウザを立ち上げて http://localhost:3000 にアクセスすると、Railsアプリケーションが動作します。
1. CSSフレームワークを導入してみよう
今回はBulmaというCSSフレームワークを使用します。
erbファイルに追記する
Visual Studio Code等のエディタにてファイルにコードを書いていきます。
app/views/layouts/application.html.erb
をエディタで開いてください。
下記のコードを
<%= csp_meta_tag %>
の下の空いてる行にコピー&ペーストしてください。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
2.Font Awesomeの導入
次に、webフォントアイコンを導入しましょう。
webフォントアイコンとは
HTMLのタグや特有のクラス名を付与することで、簡単にWebサイト上にアイコンを表示できるサービス。
フォントとしてアイコンを利用することができるので、CSSで簡単にサイズや色を変更できるため、使い勝手にも優れている。
font-awesome-sass
というgemを使用します。
まずはGemfileを開きましょう。
pokemon_zukanのGemfileをクリックすると、下の画像の様なコードが表示されると思います。
開いたGemfileの4行目のruby "2.7.6"
の下に
gem 'font-awesome-sass'
を追加しましょう。
gem 'font-awesome-sass'
追記したら上書き保存しましょう。(Ctrlキーを押しながらSキーを押す)
現在起動中のコマンドプロンプトは、railsサーバを実行しているため、新たに別のコマンドプロンプトを起動させてください。
新しく起動したコマンドプロンプトで下の3つのコマンドを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
にファイル名を変更してください。
application.scss
をVisual Studio Code等のエディタで開いて、
一番下に下の1行を追加します。
// ( #### 省略 #### )
/*
* 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行ずつ実行してください。
> 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
を実行してください。
gem 'mini_magick'
gem 'image_processing', '~> 1.2'
> bundle install
ここでも
Bundle complete!
と表示されていたらOKです
3.3 config/application.rbの編集
エディタでconfig/application.rb
を開いてください。
12行目にあるconfig.load_defaults 7.0
の下に下記の1行を追記してください。
config.active_storage.variant_processor = :mini_magick
追記した結果↓
追記したら上書き保存し、サーバを再起動してください。
新たに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
を追記してください。
class ApplicationController < ActionController::Base
protect_from_forgery # これを追加する
end
これで下準備は完了です。
次にページを作っていきます。
ページを作成する方法
ポケモン図鑑一覧ページ
ポケモン詳細ページ
ポケモン登録ページ
ページを作成するには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_controller のindex アクションを呼び出すというものです。
今回indexアクションの中身が空なので、Model は呼び出されず、単に対応するView (index.html.erb) が実行されるだけです。(MVCの図の3,4,5の部分が素通りされます)
ルーティングがうまくいってみるか確認するために、試しにアクセスしてみましょう。
(サーバーを起動していない場合はコマンドプロンプトでrails s
を実行してください)
indexページにアクセスしてみましょう。
localhost:3000/ に続いて
pokemons/index
を追記してアクセスしてください。
このように表示されていることを確認してください
ここで準備したCSSフレームワークが適用されているか確認してください。
(画像と同じスタイルになっていたら正しく適用されています。)
教材配布 > 基礎演習 > images にあるPNG画像12枚をapp/assets/imagesフォルダ内に移動させてください。
フォルダごとではなく中にある画像12枚を移動させてください。
デザインの変更
まずはpokemons.scss
というファイルを新規作成します。
(新規ファイルは、コードエディタのNew Text File等から作成可能です)
pokemons.scss
をコードを追記します。
"▶"マークをクリックすると、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
にあるコードを削除し、
下記を追記してください。
<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 を開いてみてください。
class PokemonsController < ApplicationController
def index
end
def show
end
def new
end
end
データベース内のデータを取り出して表示するには、まずControllerのアクション内で
Model を呼び出して取り出します。
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というエラーがでます。
(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
を見てみましょう。
開いてみると、下記のようなコードがあると思います。
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を編集しましょう。
`▶`をクリックしてソースコードを開き、 丸々コピー&ペーストしてください
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
で行います。
$ rails db:seed
データが保存されたかの確認はrails c
でコンソールを起動すると確認できます。
$ 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行ずつ入力していきます。
>> 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
を下記のように編集しましょう。
<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
にアクセスすると、フシギダネの情報が表示されたかと思います。
フシギダネが表示されずに
Can't resolve image into URL: undefined method persisted? for nil:NilClass
とエラーが出た場合、以下のコマンドを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[:カラム名]で値を受け取ることができます。
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に含まれる数字をパラメーターとして取得するには、下記のように記述します。
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
localhost:3000pokemons/show/3
Model 検索
今ポケモンの情報の取り出しに id を利用していますが、
id 以外のカラムを用いて取り出す方法も覚えておくと便利です。
コンソールを起動してください。 ( ターミナルでrails c
で起動 )
下記を参考に色々と試してみてください。
>> 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.rb
のnewアクション
内に書きましょう。
新しいデータを登録するときは、 Model名.new
とします。下記のコードを追記してください。
# (中略)
def new
@pokemon = Pokemon.new # これを追加する
end
ここまでの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
ヘルパーというものがあります。
<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 に追記しましょう。
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アクション
を作成しましょう。
# (中略)
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 ここでポケモンの情報を登録
localhost:3000/pokemons/show/[ID]
ここで登録内容を確認
このままでは自由にポケモンを登録できる状態です。
numberは数値を入力してもらいたいので入力制限をかけてみましょう。
Rails では制限(validation)も簡単に設定することができます。
バリデーション
バリデーションとは
データを保存する前に、無効なデータでないことを検証する機能のこと。門番みたいなもの。
空のデータが保存されないようにしたり、数字以外は保存できないようにしたり、文字数に制限を設けたり、保存するデータに制限をかける時に使います。
app/models/pokemon.rb
を開き、
下記の2行をclass Pokemon ~~ end
の間に入力してください。
class Pokemon < ApplicationRecord
has_one_attached :image
validates :name, presence: true # 追記する
validates :number, numericality: true # 追記する
end
numericality: true
属性に数値のみが使われている事を検証する
presence: true
必須項目にする
これだけで制限を設けることができます。
次にpokemons_controller.rb
のcreate
メソッドを編集します
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カラムに対して制限をかけます。
実際に試してみると、ポケモンいちらんに登録されていません。
これでポケモンのばんごうを数値以外入力して保存すると
上部にメッセージが出ます。
そして数値を入力して保存するとポケモン一覧ページに遷移先します
ポケモン一覧ページの作成
しかし、これだとポケモンを登録してもポケモン一覧ページは何も表示されていません
最後に登録したポケモンを一覧するページを作成しましょう。
まずはコントローラーの編集です。
先程コンソールでPokemon.all
を実行するとすべてのポケモンが表示されましたね。
それを利用しましょう。
class PokemonsController < ApplicationController
def index
@pokemons = Pokemon.all # これを追加する
end
# (省略)
今までshowアクションやnewアクションでは@pokemonと単数形になっていたのに、
indexアクションでは@pokemonsと複数形になっています。
分かりやすく説明してる記事があるので、参考にしてください。
ビューの編集
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>
このようにseed.rb
で入れたデータや自分で入力したデータが表示されていれば完成です、お疲れ様でした!