##第2章
第1章では、AWS Cloud9でRubyを使うための環境構築、Githubにリモートプッシュ、Herokuにデプロイを行った。
第2章では、scaffold
というスクリプトを使って簡単にCRUD機能を持ったアプリケーションを作成する。また、RESTアーキテクチャについて触れていく。
##Toy_app
・流れ
toy_app作成→Gemfile設定→gemインストール→Git管理下に配置→リモートレポジトリにプッシュ
①先ずは、新たにtoy_app
アプリを生成
$ cd ~/environment
$ rails _6.0.3_ new toy_app ←railsチュートリアルは基本的にバージョン指定
$ cd toy_app/
②Gemfileを設定する。
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '6.0.3'
gem 'puma', '4.3.6'
gem 'sass-rails', '5.1.0'
gem 'webpacker', '4.0.7'
gem 'turbolinks', '5.2.0'
gem 'jbuilder', '2.9.1'
gem 'bootsnap', '1.4.5', require: false
group :development, :test do
gem 'sqlite3', '1.4.1'
gem 'byebug', '11.0.1', platforms: [:mri, :mingw, :x64_mingw]
end
group :development do
gem 'web-console', '4.0.1'
gem 'listen', '3.1.5'
gem 'spring', '2.1.0'
gem 'spring-watcher-listen', '2.0.1'
end
group :test do
gem 'capybara', '3.28.0'
gem 'selenium-webdriver', '3.142.4'
gem 'webdrivers', '4.1.2'
end
group :production do
gem 'pg', '1.1.4'
end
# Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
railsチュートリアルをしているとGemfile
というファイルをよく使います。
Q:Gemfileとは?
A:gemの一覧を記載しているファイルのこと。因みにgem
はruby
のライブラリのこと
③gemのインストール
$ bundle install --without production
--without production
とすることで本番環境を除いたgemをインストールできる。
④Toy_appをGitのバージョン管理下に置く。
$ git init
$ git add -A
$ git commit -m "Initialize repository"
⑤リモートリポジトリにプッシュ
$ git remote add origin https://github.com/<あなたのGitHubアカウント名>/toy_app.git
$ git push -u origin master
ここまで出来れば準備完了。
第1章と同様にhello world
と表示する。
・コントローラーとアクションの設定
class ApplicationController < ActionController::Base
def hello
render html: "hello, world!"
end
end
MVCのViewはどこ?
MVCのViewはどこかという話ですが、render html: "hello, world!"
の箇所でrender
メソッドを使って描画しています。(本来ならば、Viewファイルを作って呼び出します。)
・ルートルーティングの設定
Rails.application.routes.draw do
root 'application#hello'
end
・変更のコミットは、Heroku&Githubにプッシュ
$ git commit -am "Add hello"
$ heroku create
$ git push && git push heroku master
git push && git push heroku master
の一文について、**&&
という箇所があるが、&&
**で連結すると一つ目のコマンドが成功した場合に限り実行される。
なので、この場合はgithub
へのプッシュが出来たら、heroku
にもプッシュするということ。
##usersモデル
・users → テーブル名(テーブル名は複数形を使うのが慣例)
・id:integer → 一意のid(数字のダブりがない。整数型)
・name:string → 名前(文字列型)
・email:string → 電子メール(文字列型)
id、name、emailは属性と呼びカラム(column)に相当
カラムとレコードのお話
カラム(column)は列で、レコード(record)は行と言われますが、どちらが縦で横か昔はごっちゃになった事があったので記載。
columnやlineといった単語にl(エル)
が含まれてますね。そう、こっちが縦です。(日本語だと列)
recordやrowは、r
がありますね。R
は横向きに線が生えていますね。(無理やりですが)。こっちが横です。(日本語だと行)
片方覚えればいいと思います。
##micropostsモデル
参照:railsチュートリアル第6版
user_id
というのがあるが、これは、usersモデルのid
と後で結びつく。
stringとtextのお話
ちょうざっくり説明します。
string型 255文字まで
text型 それ以上
##usersリソース
上記でusersテーブルがいきなり出てきたが、ここからscaffold
を使って、同時にusersテーブルも作成していく。
以下scaffold
コマンド
$ rails generate scaffold User name:string email:string
scaffold
の後にUser
と入力後、name:string
とemail:string
を追記する。
Q:scaffold
の後のUser
はなぜ複数形じゃない?
A:scaffold
の後のUser
はモデル名のため単数形を使用する。
できたらデータベースをマイグレートする。
$ rails db:migrate
データベースマイグレートをすることで、データベースを更新しusers
データモデルを作成するため。
##ユーザーページ
scaffold
を使ったことで簡単なCRUD機能を持ったページが作られている。
CRUD:CREATE(作成)/READ(読み取り)/UPDATE(更新)/DELETE(削除)
scaffold
でCRUD機能が実装できた。
(scaffold
は便利ですが、未知数の部分が多いので、基本的に使用せず1からCRUDを作っていきます)
##MVCの動き
MVCの詳しい動作について解説
1.ブラウザから「/users」というURLのリクエストをRailsサーバーに送信する。
2.「/users」リクエストは、Railsのルーティング機構(ルーター)によってUsersコントローラ内のindexアクションに割り当てられる。
3.ndexアクションが実行され、そこからUserモデルに、「すべてのユーザーを取り出せ」(User.all)と問い合わせる。
4.Userモデルは問い合わせを受け、すべてのユーザーをデータベースから取り出す。
5.データベースから取り出したユーザーの一覧をUserモデルからコントローラに返す。
6.Usersコントローラは、ユーザーの一覧を@users変数(@はRubyのインスタンス変数を表す)に保存し、indexビューに渡す。
7.indexビューが起動し、ERB(Embedded RuBy: ビューのHTMLに埋め込まれているRubyコード)を実行して HTMLを生成(レンダリング)する。
8.コントローラは、ビューで生成されたHTMLを受け取り、ブラウザに返す5
railsチュートリアルから引用
・resources :users
とroot 'users#index'
を設定
Rails.application.routes.draw do
resources :users
root 'users#index'
end
resources :users
は、第4章で触れるので、ここではスルー
root 'users#index'
は、コントローラー名#アクション名で、users
コントローラーのindex
アクションを実行する。
ではusers
コントローラーのindex
アクションの中身はどうなっているか?は下記のコード(一部省略)
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
@users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
@user = User.new
end
# GET /users/1/edit
def edit
end
まずは、index
アクションの動作について解説。
@users = User.all
は、Userモデルにある全レコードを取得し、@users
に代入するという意味。なおメソッドにおける変数の定義には、@を付けて@users
のような形でインスタンス変数を定義できる。
インスタンスの簡単な説明
インスタンスは、クラスから生成されたオブジェクトの事。
クラスはインスタンスの型を作るためのもの。
プログラミングの本とか読んでいると、「クラスは、クッキー(お菓子の方)の型を取る道具で、実際に型取られたクッキーがインスタンス!」だとか、「クラスは、自動車の設計図で、それを元に作られた車がインスタンス」とかそんな説明が書いてあります。
次いで、UsersController
内には、様々なアクションがあると思いますが、これらはscaffold
で作成されたもの。
第二章はREST
アーキテクチャの概念についての理解があったので、ここで記載する。
Q:REST(レスト)って?
A:REpresentational State Transferの略。既に幅広く普及したWEBの仕組み(HTTPとか)をそのまま利用して、容易にWEBサービスを可能にするもの。
@users
変数に全ユーザーが格納されたら、今度はビューを呼び出す。Railsのコントローラー内でインスタンス変数を宣言したことで、この変数はビューでも使えるようになる。
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Destroy', user, method: :delete,
data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
1行目に@users
なるものがあることがわかる。railsチュートリアルでは、このコードの説明は省略しているが、少し説明を加えます。
@users
に格納されたユーザーに関わるデータを一人ずつ|user|
に代入して、各ユーザーの名前やメールアドレスを表示するというものです。この作業を人数分繰り返すという訳です。
###Usersリソースの欠点
scaffold
という便利な機能がありますが、問題点があります。
・データ検証がされない
→ユーザ名が空白でも、メールアドレスが適当でも通ってしまう。
・ユーザー認証がない
→誰でも制限なしに操作できる。
・テストがない
→必要なレベルのテストまでは書かれていない。
・レイアウトやスタイルが整ってない
→なんかかっこよくない。
・理解が困難
→scaffold
は自動であるがゆえに、コード理解が難しい。
###Micropostsリソース
Usersリソースと同様にMicropostsリソースも作成
$ rails generate scaffold Micropost content:text user_id:integer
データベースの更新
$ rails db:migrate
ルーティングの確認
Rails.application.routes.draw do
resources :microposts
resources :users
root 'users#index'
end
resources :microposts
がscaffold
で自動で追加され、これにより各アクションに対応するようになる。
参照:railsチュートリアル
次いで、microposts_controller
の中身も確認(一部省略)
class MicropostsController < ApplicationController
before_action :set_micropost, only: [:show, :edit, :update, :destroy]
# GET /microposts
# GET /microposts.json
def index
@microposts = Micropost.all
end
# GET /microposts/1
# GET /microposts/1.json
def show
end
# GET /microposts/new
def new
@micropost = Micropost.new
end
# GET /microposts/1/edit
def edit
end
UsersController
の中身と同じであることが分かる。
###マイクロポストに制限
現在は投稿する際の文字制限がない。なので、文字数制限を与えてみる。
railsでは、バリデーションという機能を使うことで様々制限を加えられる。
class Micropost < ApplicationRecord
validates :content, length: { maximum: 140 }
end
このコードは、直感的に見た通りの動作をする。コンテンツの最大長さが140文字という内容をそのまま解釈できる。
コードを実装したので、実際に141以上打ち込んでみると、、、
###データモデル同士の関連付け
ユーザーモデルとマイクロポストモデルを関連付ける。
class User < ApplicationRecord
has_many :microposts
end
class Micropost < ApplicationRecord
belongs_to :user
validates :content, length: { maximum: 140 }
end
・ユーザーモデルは、沢山のマイクロポストを持っているため、has_many
な関係
・マイクロポストはあるユーザーのみに属しているので、belongs_to
の関係
①rails console起動
ubuntu:~/environment/toy_app (master) $ rails console
Running via Spring preloader in process 9488
Loading development environment (Rails 6.0.3)
②最初のユーザーを取得し、first_user
に格納
2.6.3 :001 > first_user = User.first
(0.4ms) SELECT sqlite_version(*)
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "名前あり", email: "名前ありメール", created_at: "2021-05-17 22:43:11", updated_at: "2021-05-17 22:44:23">
③first_user
に紐づいたマイクロポストを取得
2.6.3 :002 > first_user.microposts
Micropost Load (0.1ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? LIMIT ? [["user_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Micropost id: 1, content: "すっごい眠い", user_id: 1, created_at: "2021-05-18 22:31:59", updated_at: "2021-05-18 22:31:59">]>
④first_user
の最初のマイクロポスト(microoist id:1
)をmicropost
に代入
2.6.3 :003 > micropost = first_user.microposts.first
Micropost Load (0.2ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."id" ASC LIMIT ? [["user_id", 1], ["LIMIT", 1]]
=> #<Micropost id: 1, content: "すっごい眠い", user_id: 1, created_at: "2021-05-18 22:31:59", updated_at: "2021-05-18 22:31:59">
⑤mircropost.user
でUser id
が1の人の情報を表示
2.6.3 :004 > micropost.user
=> #<User id: 1, name: "名前あり", email: "名前ありメール", created_at: "2021-05-17 22:43:11", updated_at: "2021-05-17 22:44:23">
has_many
とbelong_to
を使うことでそれぞれ違ったモデルを結び付けてデータを表示することが出来る。
##継承
railsチュートリアル的に、ここは何となくの理解でもOK
ざっくりと説明
Q:継承って?
A:モデルに親子関係があるよ!子は親のクラスを引き継いで、使用できる。親のできることが、子にもできるようになること。
Rubyでは、継承関係を<
で表す。
class User < ApplicationRecord
class Micropost < ApplicationRecord
User
とMicropost
はApplicationRecord
を継承しており、ApplicationRecord
はActiveRecord::Base
を継承している。
このような継承関係は、モデルだけではなくコントローラーも同様である。
class UsersController < ApplicationController
class MicropostsController < ApplicationController
ApplicationController
は、ActionController::Base
を継承
class ApplicationController < ActionController::Base
継承機能が備わっている事で、子クラスでも親クラスで定義しているルールが適用される。そのため、よく使う共通のルールは、親クラスに作成すると良いって話。
演習の内容確認
1つ目
class ApplicationController < ActionController::Base
def hello
render html: "hello, world!"
end
end
2つ目
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
##デプロイ
第2章の内容をデプロイ
$ git status #追加の前にこうやって状態を確認するのはよい習慣です
$ git add -A
$ git commit -m "Finish toy app"
$ git push
Gitコミットはこまめにしておくと良いとのこと。
$ git push heroku
herokuにもpushして出来たら完了
#おわりに
第二章で学んだ事
・scaffold
でCRUD機能を作った
・MVCの挙動
・User
リソースとMicropost
リソースの結びつけ
・継承関係
第二章までは、ほぼ自動的にCRUDの機能を作ってきましたが、これからは自分でやるため段々と難しくなってきます。