1
1

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 3 years have passed since last update.

Railsチュートリアル(第6版) 第2章 Toyアプリケーション

Last updated at Posted at 2021-05-19

##第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を設定する。

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の一覧を記載しているファイルのこと。因みにgemrubyのライブラリのこと

③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と表示する。

・コントローラーとアクションの設定

application_controller.rb
class ApplicationController < ActionController::Base

  def hello
    render html: "hello, world!"
  end
end
MVCのViewはどこ?

MVCのViewはどこかという話ですが、render html: "hello, world!"の箇所でrenderメソッドを使って描画しています。(本来ならば、Viewファイルを作って呼び出します。)

・ルートルーティングの設定

routes.rb
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モデル

image.png
参照:railsチュートリアル第6版

・users → テーブル名(テーブル名は複数形を使うのが慣例)
・id:integer → 一意のid(数字のダブりがない。整数型)
・name:string → 名前(文字列型)
・email:string → 電子メール(文字列型)

id、name、emailは属性と呼びカラム(column)に相当

カラムとレコードのお話

カラム(column)は列で、レコード(record)は行と言われますが、どちらが縦で横か昔はごっちゃになった事があったので記載。

columnやlineといった単語にl(エル)が含まれてますね。そう、こっちが縦です。(日本語だと列)
recordやrowは、rがありますね。Rは横向きに線が生えていますね。(無理やりですが)。こっちが横です。(日本語だと行)
片方覚えればいいと思います。

##micropostsモデル
image.png
参照: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:stringemail:stringを追記する。

Q:scaffoldの後のUserはなぜ複数形じゃない?
A:scaffoldの後のUserはモデル名のため単数形を使用する。

できたらデータベースをマイグレートする。

$ rails db:migrate

データベースマイグレートをすることで、データベースを更新しusersデータモデルを作成するため。

一応hello worldと表示されていることを確認
image.png

##ユーザーページ
scaffoldを使ったことで簡単なCRUD機能を持ったページが作られている。
CRUD:CREATE(作成)/READ(読み取り)/UPDATE(更新)/DELETE(削除)

image.png
参照:railsチュートリアル

まずは、/usersページ
image.png

/users/newページ
image.png

ユーザー作成
image.png

/users/editページ
image.png

ユーザーアップデート
image.png

/users/showページ
image.png

scaffoldでCRUD機能が実装できた。
(scaffoldは便利ですが、未知数の部分が多いので、基本的に使用せず1からCRUDを作っていきます)

##MVCの動き
MVCの詳しい動作について解説

image.png
参照:railsチュートリアル

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 :usersroot 'users#index'を設定

config/routes.rb
Rails.application.routes.draw do
  resources :users
  root 'users#index'
end

resources :usersは、第4章で触れるので、ここではスルー
root 'users#index'は、コントローラー名#アクション名で、usersコントローラーのindexアクションを実行する。

ではusersコントローラーのindexアクションの中身はどうなっているか?は下記のコード(一部省略)

app/controllers/users_controller.rb
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のような形でインスタンス変数を定義できる。

インスタンスの簡単な説明

インスタンスは、クラスから生成されたオブジェクトの事。
クラスはインスタンスの型を作るためのもの。

プログラミングの本とか読んでいると、「クラスは、クッキー(お菓子の方)の型を取る道具で、実際に型取られたクッキーがインスタンス!」だとか、「クラスは、自動車の設計図で、それを元に作られた車がインスタンス」とかそんな説明が書いてあります。

なぜ`User.all`が全ユーザーを返すのか。 継承の機能によってUserモデルは、**Active Record**というRubyのライブラリがあるおかげで、`User.all`というリクエストに対し、データベース上の全ユーザーを返してくれる。

次いで、UsersController内には、様々なアクションがあると思いますが、これらはscaffoldで作成されたもの。
第二章はRESTアーキテクチャの概念についての理解があったので、ここで記載する。

Q:REST(レスト)って?
A:REpresentational State Transferの略。既に幅広く普及したWEBの仕組み(HTTPとか)をそのまま利用して、容易にWEBサービスを可能にするもの。

・usersリソースのREST対応表
image.png

@users変数に全ユーザーが格納されたら、今度はビューを呼び出す。Railsのコントローラー内でインスタンス変数を宣言したことで、この変数はビューでも使えるようになる。

app/views/users/index.html.erb
    <% @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

ルーティングの確認

config/routes.rb
Rails.application.routes.draw do
  resources :microposts
  resources :users
  root 'users#index'
end

resources :micropostsscaffoldで自動で追加され、これにより各アクションに対応するようになる。
image.png
参照:railsチュートリアル

次いで、microposts_controllerの中身も確認(一部省略)

app/controllers/microposts_controller.rb
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の中身と同じであることが分かる。

マイクロポストを投稿してみた。
image.png

image.png

###マイクロポストに制限
現在は投稿する際の文字制限がない。なので、文字数制限を与えてみる。
railsでは、バリデーションという機能を使うことで様々制限を加えられる。

app/models/micropost.rb
class Micropost < ApplicationRecord
  validates :content, length: { maximum: 140 }
end

このコードは、直感的に見た通りの動作をする。コンテンツの最大長さが140文字という内容をそのまま解釈できる。
コードを実装したので、実際に141以上打ち込んでみると、、、
image.png

###データモデル同士の関連付け

ユーザーモデルとマイクロポストモデルを関連付ける。

app/models/user.rb
class User < ApplicationRecord
  has_many :microposts
end
app/models/micropost.rb
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.userUser 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_manybelong_toを使うことでそれぞれ違ったモデルを結び付けてデータを表示することが出来る。

##継承
railsチュートリアル的に、ここは何となくの理解でもOK

ざっくりと説明
Q:継承って?
A:モデルに親子関係があるよ!子は親のクラスを引き継いで、使用できる。親のできることが、子にもできるようになること。

Rubyでは、継承関係を<で表す。

app/models/user.rb
class User < ApplicationRecord
app/models/micropost.rb
class Micropost < ApplicationRecord

継承の図式はこのような感じ
image.png
参照:railsチュートリアル

UserMicropostApplicationRecordを継承しており、ApplicationRecordActiveRecord::Baseを継承している。

このような継承関係は、モデルだけではなくコントローラーも同様である。

app/controllers/users_controller.rb
class UsersController < ApplicationController
app/controllers/microposts_controller.rb
class MicropostsController < ApplicationController

ApplicationControllerは、ActionController::Baseを継承

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base

image.png
参照:railsチュートリアル

継承機能が備わっている事で、子クラスでも親クラスで定義しているルールが適用される。そのため、よく使う共通のルールは、親クラスに作成すると良いって話。

演習の内容確認
1つ目

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
    
  def hello
    render html: "hello, world!"
  end
end

2つ目

app/models/application_record.rb
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の機能を作ってきましたが、これからは自分でやるため段々と難しくなってきます。

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?