現場で使える Ruby on Rails 5速習実践ガイド(ISBN978-4-8399-6222-7)
理解したこと
書籍サイト
サポートサイト
https://book.mynavi.jp/supportsite/detail/9784839962227.html
書籍情報
Railsアプリの基本から実践的なノウハウまでこの1冊で!本書は、Ruby on Rails(以下Rails)を使ってWebアプリケーションを開発するための解説書です。
RailsでどのようにWebアプリケーションを作るのかという基本的なところから、現場のニーズに合わせてどのように機能を追加していくのか、テストはどのように行うのか、複数人で開発していく場合の方法といった実践的なトピックまで、幅広くカバーしています。
本書を読んだ方が単にRailsでWebアプリケーションを作れるようになるだけでなく、「Railsらしいアプリケーションコード」を書けるようになり、そして開発チームの仲間とともに実現したいことを実現できるように、という視点で必要な情報をまとめた1冊です。
なお、本書の対応バージョンはRuby 2.5/Rails5.2です。Rails5.2から導入されたActive Storageやcredentials.yml.encについても解説しています。macOS/Windows 10(64ビット版)対応。
■読者対象について
Ruby以外の言語でのWebアプリケーションの開発や、オブジェクト指向プログラミングについては知識・経験があるものの、RubyやRailsについては初めて学ぶ方を主な対象にしています。
ただし、Webアプリケーションやオブジェクト指向が初めての方にも理解しやすいように説明するように努めています。
■構成と内容について
本書の構成は以下の通りです。
<入門編> Chapter 1 RailsのためのRuby入門 Chapter 2 Railsアプリケーションをのぞいてみよう Chapter 3 タスク管理アプリケーションを作ろう
<レベルアップ編> Chapter 4 現実の複雑さに対応する Chapter 5 テストをはじめよう Chapter 6 Railsの全体像を理解する Chapter 7 機能を追加してみよう
<発展編> Chapter 8 RailsとJavaScript Chapter 9 複数人でRailsアプリケーションを開発する Chapter 10 Railsアプリケーションと長く付き合うために
章ごとの内容は以下の通りです。
Chapter1では、Railsのアプリケーションのコードを読み書きするために最低限必要となるようなRubyの基礎知識を解説していきます。
Chapter2では、RubyやRailsが動作する環境を構築するとともに、簡単なサンプルアプリケーションを作成し、中身の構成を解説していきます。
Chapter3では、シンプルなタスク管理アプリケーションの作成を通じて、CRUDと呼ばれるソフトウェアの基本的な機能をRailsで実装する方法について学んでいきます。
Chapter4では、Chapter3で作成したアプリケーションに、いくつかの機能を追加していきます。具体的には「データ内容の制限」「検証」「コールバック」「フィルタ」「ログイン機能の追加」「関連」「検索」について解説していきます。
Chapter5では、Railsにあらかじめ用意されている「自動テスト」という仕組みについて、利用方法や注意事項を解説します。
Chapter6では、Railsの備える機能や、Railsを取り巻く世界の全体像を改めて一望し、これまで取り上げる機会のなかったいくつかの重要な要素について解説していきます。
Chapter7では、Railsアプリケーションで比較的よくある具体的な機能を実現するやり方を、Chapter4までで作成したアプリケーションへの機能追加という形で紹介していきます。
Chapter8では、Railsを利用する際のJavaScriptの扱い方について解説していきます。モダンなJavaScriptについても扱っています。
Chapter9では、複数人で開発を行う場合に重要になってくる知識や、注意すべきポイントについて解説していきます。
Chapter10では、Railsアプリケーションと長く付き合っていくために特に重要なテーマとして、「バージョンアップに対してどのように取り組むべきか」「Railsアプリケーションコードが複雑になっていくことにどうに立ち向かい、メンテナンスしやすい状態の維持を図るのか」について扱います。
<入門編>
Chapter 1 RailsのためのRuby入門
1-1 オブジェクトを理解しよう
1-1-1 万物がオブジェクト
- オブジェクトという存在になれましょう
- ※詳細割愛
1-1-2 irb
-
Rubyには、
irb(アイアールビー)という、対話的な実行環境が付属している -
オブジェクトがどういうものかを体験していただくために操作しながら読みすすめる
-
以下から実行環境を取得しておいた
1-1-3 文字列
- ダウブルクォーテーションかシングルクォーテーションで文字列を囲む
1-1-4 数値
1-1-5 オブジェクトに、自分が何者かを聞いてみる
irb(main):006:0> "氏名".class=> Stringirb(main):007:0> 1.class=> Integerirb(main):008:0> 1.1.class=> Floatirb(main):009:0> true.class=> TrueClassirb(main):010:0> false.class=> FalseClassirb(main):013:0> "氏名".object_id=> 300irb(main):014:0> "氏名".object_id=> 320irb(main):015:0> "氏名".object_id=> 340irb(main):016:0> 1.object_id=> 3irb(main):017:0> 1.object_id=> 3// 数値は同じオブジェクトIDを取るが、文字列は異なるオブジェクトIDを取る// この辺はJavaのプリミティブ型、参照型と同じ概念のよう1-1-6 クラスとインスタンス
- 「オブジェクトXのクラスがAであるとき、XはAのインスタンス(オブジェクト)である」といいます。
1-1-7 オブジェクトの機能はクラスで決まる
- オブジェクトの種類により、プロパティなどが異なりますよという説明
1-1-8 変数
-
ローカル変数の記載
- スネークケースで先頭は小文字か
_(アンダースコア)で記載されるのでこれに習おう- sample_message
- part2
- _user
- スネークケースで先頭は小文字か
-
定数は大文字で始まる名前にすること。
1-1-9 コメント
# 1行をコメントアウトname = "氏名" # 途中からも可能1-1-10 メソッド
class cat def run(ネズミ) puts "一生懸命 #{ネズミ} を追いかけた..." # 画面にメッセージを出力します endend
タマ = cat.new- メソッドの基本的な説明
- メソッドを呼び出すときにかっこを省略できる
irb(main):066:0> message1 = "こんにちは"=> "こんにちは"irb(main):067:0> message2 = "こんばんは"=> "こんばんは"irb(main):068:0* split = ^Cirb(main):068:0> split = "|"=> "|"irb(main):069:0> message3 = "あいさつ!"=> "あいさつ!"irb(main):070:0> message3.concat message1, message2=> "あいさつ!こんにちはこんばんは"1-2 自分でクラスを作ってみよう
1-2-1 クラスを作る
1-2-2 Userクラスを作る
1-2-3 Userクラスにメソッドを定義する
1-2-4 インスタンス変数
- インスタンス変数:オブジェクトが抱えている変数
class User def name=(name) @name = name end
def name @name endend1-2-5 ローカル変数とインスタンス変数の違い
1-2-6 属性
- 一般的にオブジェクトが抱えるデータのことを「属性(Attribute)」
- 属性とインスタンス変数はよく似た概念と言える
1-2-7 ゲッターやセッターを簡単に定義する
class User #attr_accessor :name #attr_reader :name #attr_writer :nameend1-2-8 住んでいる場所やEメールアドレスを持たせる
class User attr_accessor :name, :address, :emailend1-2-9 メソッドからメソッドを使う
1-2-10 まとめ - オブジェクトの振る舞いとデータ
1-3 Rubyプログラムの基礎知識
1-3-1 演算子
- 目新しい演算子はないので割愛
1-3-2 nil
# nilにするvalue = nil# nilかどうか確かめるvalue.nil?1-3-3 真偽
- Rubyでは0も真になるので注意!
1-3-4 条件分岐
number = 1if number == 1 puts '数値は1です'elsif number == 2 puts '数値は2です'else puts '数値は1や2以外です'end# ifは評価結果を返すことを抑えておくnumber = 100message = if number > 50 "numberは50より大きいです" else "numberは50以下です" end# elseがなくどのオブジェクトにも当てはまらない場合はnilオブジェクト# 当てはまらない場合に分岐する unless# ifの裏返しを表現する方法# これは使わなくても良さそう わかりにくくなるage = 16unless age >= 20 puts "未成年者には酒類を提供できません!"end# 後置ifputs 'おはようございます' if trueputs 'お疲れ様でした' if false1-3-5 配列
# eachメソッドa = [1,2,3]a.each do |element| puts elementend
# forでもかけるfor element in a puts elementend- Rubyに慣れている人は、For文よりもeachを好んで使うとのこと
# 配列に要素を追加する場合は<<を使うa = [1,2,3]a << 41-3-6 ハッシュ
- 内部的にデータをキーと対応づけて格納しておくデータ構造
pref = { tokyo: 13636222, kanagawa: 9144572 }
irb(main):060:0> pref=> {:tokyo=>13636222, :kanagawa=>9144572}irb(main):061:0> pref[:tokyo]=> 136362221-4 少し高度なテクニック
1-4-1 initialize
class User attr_reader :name, :address, :email def initialize(name, address, email) @name = name @address = address @email = email endend
user = User.new("田中太郎","東京都",nil)1-4-2 メソッドの呼び出しに制限をかける
class Person def initialize(money) @money = money end def billionaire? money >= 1000000000 end
# privateキーワード以降のメソッドはプライベートメソッドとなる # initializeメソッドはprivate指定しなくても自動的にプライベートになる private
def money @money endend
person = Person.new(1000000000)
# privateなのでエラーになる!person.money1-4-3 引数にデフォルト値を指定する
# デフォルト値を指定することができるdef name(full = true, with_age = true) n = if full "#{given_name} #{family_name}" else given_name end n << "(#{age})" if with_ageend1-4-4 キーワード引数
# キーワード引数の定義def name(full: true, with_age: true) n = if full "#{given_name} #{family_name}" else given_name end n << "(#{age})" if with_ageend
# デフォルト値の省略も可能def name(full: true, with_age:)end
# どんな順序で呼び出してもいいperson.name(full: true, with_age: false)person.name(with_age: false, full: true)1-5 似たところのあるクラスを作りたいとき
1-5-1 継承
# < で継承ができるclass Book def title '本のタイトル' endend
class Magazine < Book # オーバーライド def title '雑誌のタイトル' endend1-5-2 モジュールによる共通化(Mix-in)
- Rubyの基本単位のオブジェクトであり、オブジェクトの設計図としてクラスがある
- ある一連の振る舞いの設計図を一箇所にまとめた存在として「モジュール(Module)」という概念がある
module Chatting def chat "hello" endend
class Dog include Chattingendモジュールをクラスに取り込んで振る舞いを追加することをRubyでは、「Mix-in」(ミックスイン)と呼びます
Column クラスメソッド
- クラスに対して呼び出せるクラスメソッドという概念が存在する
class Tax def self.rate 1.08 endend1-6 プログラムの異常を検知しよう(例外捕捉)
- 独自例外を作成するときはStandardErrorを継承して作成する
beginrescueensureend
# メソッド内の例外処理なら以下のようにかけるdef method rescue # 例外に対応するコード ensure # 例外が発生してもしなくても必ず実行したいコードend
begin do_somethingrescue SomeSpecialError => e # エラーオブジェクトを変数として受け取る方法 puts "#{e.class} (#{e.message})が発生しました。処理を続行します。"end1-7 読めると便利!Rubyっぽい書き方
1-7-1 nil ガード
number ||= 10number || (number = 10)
def children @children ||= []end# childrenがnilの状態であっても必ず配列で初期化されるので安心1-7-2 ぼっち演算子 &.
user = User.newuser.name
object = nilobject&.name# => ここでエラーにならない1-7-3 %記法
# すべての要素が文字列である配列は、通常の配列記法の他に、「%w」というキーワードを使って書くことができるary1 = ['apple','banana','orange']puts ary1# irb(main):001:0> ary1 = ['apple','banana','orange']# => ["apple", "banana", "orange"]# irb(main):002:0> puts ary1# apple# banana# orange# => nil
irb(main):003:0> ary2 = %w(apple banana orange)=> ["apple", "banana", "orange"]
# すべての要素がシンボルの場合は、「%i」というキーワードを使ってかけるirb(main):004:0> ary2 = %i(apple banana orange)=> [:apple, :banana, :orange]1-7-4 配列の各要素から特定の属性だけを取り出す
class User attr_accessor :nameend
user1 = User.newuser1.name = 'テスト1'user2 = User.newuser2.name = 'テスト2'user3 = User.newuser3.name = 'テスト3'
users = [user1, user2, user3]
# ------ 名前だけが入った配列を求める方法1 --------
names = []user.each do |user| names << user.nameend
p names
# ------ 名前だけが入った配列を求める方法2 --------
names = users.map do |user| user.nameend
# ------ 名前だけが入った配列を求める方法3 --------
names = users.map { |user| user.name }
# ------ 名前だけが入った配列を求める方4 -------- ※これが一番簡潔!
nemes = users.map(&:name)- ※なれないとわからない書き方だと思った
Chapter2 Railsアプリケーションをのぞいてみよう
2-1 コマンド実行環境を準備しよう
2-1-1 Windowsでコマンド実行環境を用意する
windows環境のWSLでubuntuを動かしてそこにRubyを入れる
wsl -u root
wslにログインしてupdate打つ際に管理者権限が必要なのだが、
Windowsユーザだとパスワード通らなかったのでrootではいって更新コマンド売った
sudo apt update
# Cドライブ直下ls /mnt/c2-2 rbenvをインストールしよう
2-2-1 macOSでrbnevをインストール
2-2-2 Windows(WSL)でrbenvをインストール
git clone https://github.com/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrcecho 'eval "${rbenv init -}"' >> ~/.bashrcexit
# 再度ログインwsl -u root
rbenv -v# => バージョンが表示されること
# rbenvでのRubyのインストールを簡単にするプラグイン、ruby-buildをセットアップgit clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
# こちらのコマンドはhttps://github.com/rbenv/ruby-build/wiki を参照sudo apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev libdb-dev
# libgdbm6 このパッケージが見つからなかった# sudo apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline-dev # zlib1g-dev libncurses5-dev libffi-dev libgdbm libgdbm-dev libdb-dev# Reading package lists... Done# Building dependency tree# Reading state information... Done# E: Unable to locate package libgdbm2-3 Rubyのインストール
rbenv install 2.5.1rbenv global 2.5.1
ruby -vwhich ruby
# うまく行かなかったので以下を参照して設定した# <https://qiita.com/yuma-ito-bd/items/00f89ca0c04909c7c467>2-3-1 Rubyのパッケージ管理ツール「RubyGems」
- Rubyは本体だけでも動作するが、公開されているサードパーティのライブラリを利用することで素早く生産的にプログラミング可能
- これらのライブラリは「gem」という形式でパッケージ化されている
- 本書で取り扱っていくRailsもgemの1つ
- Rubygemsと呼ばれるパッケージ管理ツールがgemのインストールや管理を簡単にしてくれる
gem update --system
gem -v
gem list2-3-2 Bundlerのインストール
- Bundler:gemをどのバージョンで利用するのかを管理する仕組み
- プロジェクトのディレクトリに
Gemfileという名前のファイルを作成し、gemの名前を記載しておくとそのとおりにインストールしたり、それらのgemをRubyから利用したりすることができるようになる
gem install bundlerbundle install: Gemfileに記述したgemをインストールするbundle exec [コマンド]: Bundlerが管理するgemを利用できる状態でコマンドを実行するbundle initbundle update
2-4 Railsのインストール
gem install rails -v 5.2.1rails -v
2-4-1 Node.jsのインストール
Javascriptランタイムとしてnodejsをインストールする
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt install nodejs
nodebrewインストール参考
<https://www.kimoton.com/entry/20190215/1550166179>
2-5 データベースのインストールとセットアップ
2-5-1 macOSの場合
2-5-2 Windows(WSL)の場合
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/${lsb_release -cs}-pgdg main" > /etc/apt/sources.list.d/pgdg.list'wget --quiet -P - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -sudo apt updatesudo apt install postgresql
# 資料に記載の手順でpostgresqlインストールできなさそうだったので以下の手順で実施# 参考)<https://www.digitalocean.com/community/tutorials/how-to-install-postgresql-on-ubuntu-20-04-quickstart-ja>sudo apt updatesudo apt install postgresql postgresql-contrib# サービスが起動しているか確認し起動していなければ立ち上げるservice postgresql statusservice postgresql start2-5-3 トラブルシューティング:RailsでPG::ConnectionBadというエラーになるとき
2-6 Railsに触れてみよう
2-6-1 実際にアプリケーションを動かしてみよう
# 雛形生成rails new scaffold_app -d postgresql# 確認cd scaffold_appls# データベース作成# railsコマンドではなく、bin/railsコマンドを利用する# このスクリプトだと、bundle exec railsとして実行したときと同様に、Gemfile通りのgemを利用できる環境上でrailsコマンドを実行することができるbin/rails db:create
# サーバー起動bin/rails s- うまくRails立ち上がらないので、書籍とは別のバージョンを入れる
- https://qiita.com/Gushi_maru/items/f3b5cc43e135e678085f
apt-get install libpq-dev
# 問題:postgresqlが5432portで立ち上がらない問題# 原因:Windows側でインストールしているPostgresqlがすでに5432ポートで立ち上がっていたため# 対策:Windows側で立ち上がっていたサービスを停止した上で起動root@DORAEMON:/etc/postgresql/10/main# service postgresql start * Starting PostgreSQL 10 database server * Removed stale pid file.Error: /usr/lib/postgresql/10/bin/pg_ctl /usr/lib/postgresql/10/bin/pg_ctl start -D /var/lib/postgresql/10/main -l /var/log/postgresql/postgresql-10-main.log -s -o -c config_file="/etc/postgresql/10/main/postgresql.conf" exited with status 1:2021-03-28 04:08:07.395 JST [210] LOG: could not bind IPv4 address "127.0.0.1": Permission denied2021-03-28 04:08:07.395 JST [210] HINT: Is another postmaster already running on port 5432? If not, wait a few seconds and retry.2021-03-28 04:08:07.395 JST [210] WARNING: could not create listen socket for "localhost"2021-03-28 04:08:07.395 JST [210] FATAL: could not create any TCP/IP sockets2021-03-28 04:08:07.396 JST [210] LOG: database system is shut downpg_ctl: could not start serverExamine the log output.
# 問題:DB作成ができない問題root@DORAEMON:/mnt/c/users/Tomo/ruby-work/scaffold-app# bin/rails db:createFATAL: role "root" does not existCouldn't create 'scaffold_app_development' database. Please check your configuration.rails aborted!PG::ConnectionBad: FATAL: role "root" does not exist/mnt/c/users/Tomo/ruby-work/scaffold-app/bin/rails:9:in `<top (required)>'/mnt/c/users/Tomo/ruby-work/scaffold-app/bin/spring:15:in `<top (required)>'bin/rails:3:in `load'bin/rails:3:in `<main>'Tasks: TOP => db:create(See full trace by running task with --trace)-
そもそもPostgresqlにユーザ作成しておく必要がありそうなので対応
-
Postgresqlにユーザを作成する手順
-
パスワードは環境変数に設定しておき読み込む
-
ユーザ作成

- railsはHTTPサーバとしてpumaを使用している
- Pumaは広く使用されており、Railsの機能を利用する上で不足はありません。
2-6-1-2 ユーザ管理画面の雛形を作る
# ユーザーに関するscaffoldを自動生成するbin/rails generate scaffold user name:string address:string age:integer
# ユーザ管理機能に使うデータベースを作成するbin/rails db:migrate
# 準備が整ったところで再度アプリケーションを起動するbin/rails s2-6-1-4 コードの通り道
- Controllerからページテンプレート周りの簡単な説明
2-6-1-5 ディレクトリ構成
-
ディレクトリ構成(割愛)
-
database.yml- データベースと接続するための設定ファイル
- development,test,productionという環境用にそれぞれ作成
| 項目名 | 説明 |
|---|---|
| adapter | データベースの接続に使用するアダプタの名前を指定します。アダプタには各データベースに対応するsqlite3,postgresql,mysql2,oracle_enhancedなどがある |
| encoding | 文字コード |
| pool | コネクション数の上限 |
| database | データベース名 |
| username | データベースに接続するユーザ名 |
| password | データベースに接続するユーザのパスワード |
| host | データベースが動作しているホスト名またはipアドレス |
# PostgreSQL. Versions 9.3 and up are supported.## Install the pg driver:# gem install pg# On macOS with Homebrew:# gem install pg -- --with-pg-config=/usr/local/bin/pg_config# On macOS with MacPorts:# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config# On Windows:# gem install pg# Choose the win32 build.# Install PostgreSQL and put its /bin directory on your path.## Configure Using Gemfile# gem 'pg'#default: &default adapter: postgresql encoding: unicode # For details on connection pooling, see Rails configuration guide # https://guides.rubyonrails.org/configuring.html#database-pooling pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development: <<: *default database: scaffold_app_development
# The specified database role being used to connect to postgres. # To create additional roles in postgres see `$ createuser --help`. # When left blank, postgres will use the default role. This is # the same name as the operating system user that initialized the database. #username: scaffold_app
# The password associated with the postgres role (username). #password:
# Connect on a TCP socket. Omitted by default since the client uses a # domain socket that doesn't need configuration. Windows does not have # domain sockets, so uncomment these lines. #host: localhost
# The TCP port the server listens on. Defaults to 5432. # If your server runs on a different port number, change accordingly. #port: 5432
# Schema search path. The server defaults to $user,public #schema_search_path: myapp,sharedapp,public
# Minimum log levels, in increasing order: # debug5, debug4, debug3, debug2, debug1, # log, notice, warning, error, fatal, and panic # Defaults to warning. #min_messages: notice
# Warning: The database defined as "test" will be erased and# re-generated from your development database when you run "rake".# Do not set this db to the same as development or production.test: <<: *default database: scaffold_app_test
# As with config/credentials.yml, you never want to store sensitive information,# like your database password, in your source code. If your source code is# ever seen by anyone, they now have access to your database.## Instead, provide the password as a unix environment variable when you boot# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database# for a full rundown on how to provide these environment variables in a# production deployment.## On Heroku and other platform providers, you may have a full connection URL# available as an environment variable. For example:## DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"## You can use this database configuration with:## production:# url: <%= ENV['DATABASE_URL'] %>#production: <<: *default database: scaffold_app_production username: scaffold_app password: <%= ENV['SCAFFOLD_APP_DATABASE_PASSWORD'] %>Column YAMLの基本
- エイリアスとアンカー問機能
animal: &animal cat: 'ネコ' dog: 'イヌ'
animal_shop_1: <<: *animal hamster: 'ハムスター'
animal_shop_2: <<: *animal parrot: 'オウム'routes.rb- アプリケーションのルーティングを定義するファイル
- リクエストに対応するレスポンスを作るためにどの処理を実行するかを定義したもの
# すべてのルーティングを確認できるbin/rails routes