はじめに
記念すべき DMM WEBCAMP Advent Calendar 2021 1日目を担当します @SawaShuyaです!
Railsで開発を進めていると、3 ~ 4カ月ほどで設計から実装まである程度自力で開発できるようになってくると思います!
今回は、railsをある程度自力で書くことができるようになった方向けに、次にどのようなことを学んでいけばいいのかを書いていきたいと思います
構成は
1. rubyを学ぶ
2. railsの開発スキルを磨く
3. 周辺知識を学ぶ
となっておりますので、興味のある部分だけでも見ていただけたらと思います!
1. Rubyを学ぶ
railsはすべてrubyで書かれてます。rubyを深めていくことで、これまでは何気なく扱っていたclassやmodule、オブジェクトなどを理解することができ、より効率の良い開発ができるようになります!
では突然ですが、以下のコードを実行した時にどういった結果になるでしょうか?
class Fuga
def display
"fuga display"
end
def self.display
"fuga class display"
end
end
class Hoge < Fuga
def display
"hoge display"
end
def self.display
super
"hoge class display"
end
def self.message
p "message : " + display
end
end
Hoge.message
こちらのコードはRubyの基本的な文法やオブジェクトへの理解があると解くことができます!
こちらが難しいなと感じた方は、是非一緒にrubyを世界を覗きましょう
rubyを知り開発能力を上げていきましょう!
解答・解説
【解説】
Hoge.message
でクラスメソッドのmessageが呼び出されます。
def self.message
p "message : " + display
end
そのなかでdisplayメソッドを呼び出していますが、rubyではselfが省略されているため、実質self.displayを呼び出していることになります。今クラスメソッド内であるためselfにはHogeが代入されています。そのため、クラスメソッドのdisplayが呼び出されます。クラスメソッドのdisplayは、classの継承があるのでFugaクラスのものとHogeクラスの2種類が存在します。同名であれば自分のクラスのメソッドが優先されるため、Hogeクラス内のクラスメソッドのdisplayが呼び出されることになります。
class Hoge < Fuga
def self.display
super
"hoge class display"
end
end
super
でFugaクラスのクラスメソッドのdisplayが呼び出されますが、rubyではreturnを記述していない場合、一番下のコードが戻り値になるため、"hoge class display"が返されるという流れです。
〇 基本文法
rubyの基本文法を知ることで、コード量を減らすことができます!
ここでは条件分岐の構文を中心に、いくつか基本文法を紹介したいと思います!
基本文法
三項演算子(条件演算子)
ifを使った条件文はよくお使いなるかと思いますが、三項演算子を用いた条件文の記述もあります!
今、a, bの変数に整数が与えられたとき、if文を用いて小さい値を出力するプログラムが以下のようにあったとします
# 値の小さいほうを出力
if a < b
result = a
else
result = b
end
p result
こちらでも問題なく動作するのですが、条件演算子を使うと楽にコードを記述できます!
# 条件演算子
# (条件式) ? (trueの時の値) : (falseの時の値)
result = a < b ? a : b
p result
5行の記述を1行にまとめることができました!使いどころによっては、非常に簡単にコードを書けるのでお勧めです
論理演算子
if文を書いていると、ついついif文をネストしすぎてしまうことありますよね...
そんなときは論理演算子を使って、if文のネストを解消しましょう!
# 論理演算子
(条件式1) && (条件式2)
=> 条件式1も条件式2もtrueのときtrueを返す
※条件式1がfalseのときは条件式2は評価されない
(条件式1) || (条件式2)
=> 条件式1もしくは条件式2のどちらかtrueのときtrueを返す
※条件式1がtrueのときは条件式2は評価されない
(正確には最後に評価したオペランドの値を返すのですが、条件式では上のように認識で問題ないです)
今、a, b, cの変数に整数が与えられたとき、if文を用いてその最小値を出力するプログラムが以下のようにあったとします
if a < b
if a < c
result = a
else
result = c
end
else
if b < c
result = b
else
result = c
end
end
p result
これを論理演算子を用いると
if a < b && a < c
result = a
elsif b < a && b < c
result = b
else
result = c
end
p result
ネストがないシンプルな形になりました!
case式
条件分岐ではif
やunless
をよく使うかと思いますが、case
を用いた方法もあります!
# case式
case (式)
when (条件式)
....
when (条件式)
....
else
....
end
caseによって指定した式の評価値を、それぞれのwhenにて(条件式) === (式)
で評価し、最初にマッチしたwhen節内の処理を行います!(===
は包含判定です。式の評価値が条件式の範囲内か評価します)
式を複数回書く必要がないため、スッキリとした表記をすることができます!
今、a, bに自然数が与えられ、それらの和が0~9、10~29、20以上かを判断するプログラムが以下にあったとします
if (0..9) === (a + b)
p "0~9"
elsif (10..19) === (a + b)
p "10~19"
else
p "20~"
end
(a + b)という式を複数回記述していますが、これをcase文に書き換えると
case (a + b)
when (0..9)
p "0~9"
when (10..19)
p "10~19"
else
p "20~"
end
となります!スッキリしましたね!
〇 オブジェクト指向
オブジェクト指向とはrubyなど多くのプログラミング言語が採用している、システム構成のことを指します!
classとは何か、継承とは何かなどなど、少しのイメージを持つだけで、プログラミング自体の構造を把握することができ、railsへの理解がグッと高まります!pythonやC++, JAVAなどなど、多くの言語で採用されてますので、ruby以外の言語にチャレンジするときにも、非常に役に立つ知識になるでしょう
ここでは図を交えながら、ざっくりとしたイメージを伝えたいと思います!
オブジェクト指向
クラスとインスタンス
まずはクラスとインスタンスについてお話します!
クラスとは同じ性質を持たせる集まりのことを指します!
例えば、動物も魚もいる動物園のアプリケーションがあった際には以下のように、まとまりごとにクラスを作成します!その中で一つのオブジェクト(データ)をインスタンスと呼びます。
それぞれのクラスには、インスタンスメソッド、クラスメソッドが設定されており、それらを実行することで処理を行います
インスタンスメソッドは同クラスのインスタンス(個別データ)に対して、クラスメソッドはそのクラス全体に対して処理をかけます。基本的に他のクラスのメソッドは使うことができません。
クラスの継承
図にある通り、「情報の保存・更新」機能はすべてのクラスに共通した機能です。同じ機能であれば、1か所で管理したほうが、コードの修正などが行いやすくなるため、これらをまとめていく必要があります。
その際に登場するのがクラスの継承です
クラス継承は、他のクラスのメソッドを自由に使うことができるようにできる機能です!
そのため、図のように情報の保存・更新といった機能を一つのクラスを管理し、それを継承することで、機能の共有をすることができます!
railsを覗いてみる
実はこの構造はrailsアプリケーションでも確認することができます。
railsの場合保存する機能を扱うクラスはActiveRecordです!それをApplicationRecordが継承して、他のモデルはApplicationRecordを継承して、.save
や.update()
を使うことができるようになります!
railsのmodel内のファイルを確認すると、class名や継承先が以下になっているようなことがわかります!
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
class Employee < ApplicationRecord
def work_time
......
end
def self.sort_for_number
......
end
end
ここではclassと継承周りでざっくりと解説を行いました!
オブジェクト指向はシステムを理解する上でも、効率の良い開発を目指す上でも、かなり強力な知識になります!
今回は一部省いている部分もあるので、ぜひ一度学習してみるといいと思います
その際には昨年のDMM WEBCAMP Advent Calendar 2020の記事が参考になるので、こちらもまた是非ご覧ください!
〇 組み込みクラス
rubyにはもともと備わっている組み込みクラスがあり、他の言語と比較しても便利なメソッドが多く備わっているといわれています!
ここでは、開発に便利そうなメソッドを紹介したいと思います!
組み込みクラス
Arrayクラス
配列に対するメソッドになります!配列はrailsにおいてwhereメソッドなどで検索をかけたときなどにも登場するため、Arrayクラスのメソッドは覚えておくと、開発効率が上がります!
Arrayクラスのメソッド
each_with_index
each文のように一つずつ値を取り出して処理を行う際に、取り出した順番も値として保持することができるメソッドです。
a = ["hoge", "fuga", "piyo"]
a.each_with_index do |value, i|
p i, value
end
# => 0 "hoge" 1 "fuga" 2 "piyo"
map
each文のように値を取り出して、ブロック内の処理を行い、結果を配列で返すメソッド。要素すべてに何か処理を行いたいときに使用すると便利です。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# すべての要素を2倍にして配列で返す
p a.map {|k| k * 2}
sort
配列の順番を変えることのできるメソッドです。ブロックを持たせるとその評価に従って任意の順番に並べ替えることができます。
<=>
はUFO演算子などと呼ばれ、sortメソッドではこれの評価値をもとに順番を決定しています。
# UFO演算子
1 <=> 2 # => -1
2 <=> 2 # => 0
3 <=> 2 # => 1
a = [3, 10, 1, 9, 8, 5, 6, 7, 4, 2]
p a.sort # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 隣り合う2つの数を左から取り出して、2つ目の値が1つ目の値より大きければ入れ替え
p a.sort{|a, b| b <=> a} # => [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
first, last
配列の最初と最後の要素を取得します。引数を持たせることで取り出す要素数を指定できます。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
p a.first # => 1
p a.first(3) # => [1, 2, 3]
p a.last # => 10
p a.last(3) # => [8, 9, 10]
sum
合計を出すことができます。each文でなどで一つ一つ取り出すより、処理スピードが格段に速いです。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
p a.sum # => 55
Hashクラス
{"orange" => "fruit", "warter" => "drink"}
のように{(key) => (value), ....}
といった形式をHashといいます!
こちらもrailsを開発をしていると、パラメータやenumなど様々な場面で見ることがあります!配列ほど登場回数は多くないので、基本的な部分を抑えていきましょう!
Hashクラスのメソッド
[]
keyを入力することでvalueを取り出すことができます。
a = {"orange" => "fruit", "warter" => "drink"}
p a["orange"] # => "fruit"
keys
Hashのkeyの部分を取り出し、配列として出力します。
a = {"orange" => "fruit", "warter" => "drink"}
p a.keys # => ["orange", "water"]
values
Hashのvalueの部分を取り出し、配列として出力します。
a = {"orange" => "fruit", "warter" => "drink"}
p a.values # => ["fruit", "drink"]
数値型クラス
プログラミングに数値計算は必須です!数値クラスはNumeric, Float, Integer, Fixnum, Rational, Complexなど多くのクラスがあります!一つ一つ重要ではありますが、今回はその中でもrails開発に使えそうなものだけピックアップしてみました!
数値型クラスのメソッド
times
Integerクラスのtimes メソッドでも繰り返し文を作成することが可能です!レシーバー(整数)の回数分ブロックの処理を行います!
繰り返しの回数が決まっていて、シンプルに書きたいときにおすすめです!
sum = 0
# 10回分(iは0から9まで)の処理
10.times {|i| sum += 1}
p sum # => 45
modulo
Fixnumクラスのmoduloは、剰余(数を割ったときのあまり)を出力します!idが3の倍数の時に処理したい!!などというときに使ったりします! %
も同様の処理を行います。
p 9.modulo 3 # => 0
p 10.modulo 3 # => 1
p 11 % 3 # => 2
2. Railsの開発スキルを磨く
railsの技術の向上にはrails自身をより使いこなしていく必要もあります!
初級レベルから中級レベルになるために意識したいことや、便利なツールをまとめましたので、ご参考ください!
〇可読性の高いコードを目指す
railsに限らず、プログラミングは複数人での作業を行ったり、また自分のコードをデバッグするなどの作業を行います。そのため、出来る限り見やすいコードを書く癖をつけていくことが望ましいです。どういった観点に着目をするべきかまとめてみました!
また、自分のコードが正しく書ているのかをざっくりチェックしてくれるRubocupというGemもあります
可読性を上げるために意識すること
インデント
インデントを正しく使用することで、コードが一段と見やすくなります!
ruby自体はインデントがなくとも動作はするのですが、どこから開始してどこで終了するかが一目でわかると、エラーの発見が早くなることがあります!
- インテンドを意識する
命名(変数名、クラス名、カラム名 など)
rubyは動的型付け言語であるため、変数に自動で型が割り振られます。そのため、より一層変数の中にどんな情報が入っているのかを分かりやすくする必要があります!また、railsはデータベースも扱うため、それぞれ適切な命名が必要になります!以下の点に気を付けてみましょう!
- 単数形、複数形の変数を区別して使えているか
- 不要な部分でインスタンス変数を使っていないか
- 不要な引数を取っていないか
- クラス名やメソッド名から何の処理を行うか判別ができるか
- カラム名は誰から見ても同じ認識となる名前となっているのか
複数個所で共通コード
プログラミングにはDry(Don't Repeat Yourself)原則(もしくはOAOO(Once and Only Once)原則)というものがあります!同じコードを2か所以上で使用しないことを提唱しています。
複数個所で同じコードを管理していると、1つに修正を加えた際に他の修正も必要になるため、無駄な労力やエラーの原因に繋がります。そのため、メソッドとして処理をまとめることや、部分テンプレートを使ってViewをまとめるなど、共通する部分は1か所で管理することが望ましいです!
- 共通する処理はメソッドを作成してまとめる
- viewで共通する箇所は部分テンプレートを用いてまとめる
長いコード
ついつい開発に夢中になっていると、コントローラに非常に長い処理を書いてしまう場合があります!
基本的にはコントローラでは簡潔に変数の代入や、リダイレクトの設定を行うため、このようなプログラミング処理については、メソッドとしてまとめていく必要があります!
- 長くなってしまったコードは処理ごとにメソッドにまとめる
- if文などのネスト構造は最小限にとどめる
〇 開発効率が上がるおすすめGem
rubyには開発効率のあがる便利なGemがたくさんあります!また、こんな機能を実装したいなぁと思ったときには、まずGem探しからやってみると、意外とあったりします!
Gemを有効的に活用し、開発効率を上げていきましょう!
ここでは、そのなかでも私がよく使っている便利Gemを紹介したいと思います
おすすめGem
better_errors
better_errorsはデバッグ用のGemになります!
railsのデフォルトのエラー画面でも十分わかりやすいですが、デバッグをする際にはこちらが便利です!
better_errorsを導入すると、エラーが出た際には以下のような画面になります
①エラー内容
②エラー箇所
③エラーコードとコンソール
④パラメーターや呼び出しているアクション、変数に格納されている値など
デフォルトのエラー画面では表示されない、変数を一覧で見ることができます!またエラー箇所で処理が止まり、byebugやbinding.pryのようにコンソールでコードを入力できるので、デバッグ効率が格段にあがります!
slim
slimはテンプレートエンジンのGemになります!
railsはデフォルトでerbとなっておりますが、erbでの記述は<% %>
などの記述が多く、長いviewを書くときにはやや面倒に感じてしまいます...
そこでコードの記述が少なくて済むテンプレートエンジンとしてslimをお勧めします!
以下のようにerbの記述があったとします
<h1 id = "title">Title</h1>
<p id = "sub-title">Subtitle</p>
<div class = "links">
<%= link_to "top", root_path %>
</div>
<table class = "items">
<% @items.each do |item| %>
<tr>
<td><%= item.name %></td>
<td><%= item.introduction %></td>
</tr>
<% end %>
</table>
これをslimに直すと以下のようになります!
h1#title
| Title
p#sub-title
| Subtitle
.links
= link_to "top", root_path
table.items
- @items.each do |item|
tr
td
= item.name
td
= item.introduction
"<", "%", ">", "end"は不要で、htmlタグも括弧や閉じタグを省略します!
基本的にインデントで階層を判断されます!
コード量はerbと比較すると非常に少なくなるので、開発効率は良くなります!
途中までerbで書いてしまっていても、html2slimのようなGemもあり、自動で変換してくれるので、是非活用してみてください
他にもhamlといった読み込み速度がはやいテンプレートエンジンのGemもあるので、興味があればこちらも使ってみてください!
ridgepole
ridgepoleはCookPadが開発した、migrationファイルなしでデータベースを扱うことができるGemになります!
railsはデフォルトでmigrationファイルを使ってデータベースの操作を行いますが、開発が大規模になるとたくさんのマイグレーションファイルに溢れてしまいます...
またカラムの追加や削除、型の変更などなど、変更にもすべて新規のmigrationファイルが必要で非常にややこしくなります...
そこで便利なのがridgepoleです!こちらはdb
ディレクトリ直下に○○.schema
ファイルを作成し、普段migrationファイルに記述する内容を記載します!
create_table "items", force: :cascade do |t|
t.string "name", null: false
t.text "introduction", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
カラムの変更がしたいときは、ここに追加や変更をし、ridgepoleを実行するだけです!
ファイルが増えることも、ややこしくなることもありません
3. 周辺知識を学ぶ
railsはwebアプリを簡単に作成できるフレームワークです!
railsは非常に強力なフレームワークであるため、データベースやOSの知識がなくとも楽々と開発をすることができます!
しかしながら裏を返せば、何も意識しなければrails以外の知識を身に着ける場面がないということになります...
本来webアプリに必要な知識はたくさんあります!それらを少しずつ学習していくことで、バックエンド領域全体としての理解を深めることができrails以外の言語をやることになっても、必ず役に立つでしょう
〇 データベース
railsではデフォルトでSQLiteと呼ばれるデータベースを扱ってます!
他にもMySQLやPostgreSQLなどといった有名なデータベースを使うこともできます!
ここではざっくりとrailsとデータベースの関連をみていきたいと思います!!
データベース
それぞれのデータベースは"SQL"と呼ばれるデータベース言語を使うことによって、テーブルの作成やカラムの作成を行うことができます!
ではrailsではデータベースを扱っていますが、どこでSQLが書かれているのでしょうか?
それはrailsにもともと備わるActiveRecordが担ってくれています!
例えば
item = Item.find(1)
# => #<Item id: 1, name: "hoge">
item.update(name: "fuga")
このようなコードが実行できたときターミナルでは以下のような文章が表示されているかと思います!
:
# Item Update (0.4ms) UPDATE `items` SET `updated_at` = '20xx-xx-xx xx:xx:xx', `title` = 'fuga' WHERE `id` = 1 SQL (0.8ms) COMMIT
:
これがActiveRecordによって生成されたSQLです!.update
メソッドの実行のみでSQLに変換して更新作業をしてくれています!
このActiveRecordはSQLを知らなくてもデータベースを触れてしまうという、非常に強力な機能です!まさにrailsの強みですね
railsを使っているだけではSQLを学ぶ必要に迫られることはありませんが、データベースを扱っている以上は知っておいて損はない知識かと思います!SQLも様々な構文があるのでprogateやSQL攻略でお手軽に練習できますので、ぜひ学んでみてください!
〇 システムインフラ
ミドルウェアから深い部分をシステムインフラと呼ぶことがあります!(ミドルウェアは主にサーバー関連を指しています)
railsで開発を進めても、いざ公開しようとした際には、このシステムインフラの知識が必要になります
これらは非常に深い領域ですので、ここではざっくりとした内容と、その学習のおすすめをお伝えしたいと思います!
システムインフラ
railsやphp、JAVAなどで作るアプリケーションはすべてシステムインフラの上で稼働しています。
すなわち、アプリを公開するにはこれらの知識が少なからず必要になってきます!
ただ近年はIaas(Infrastructure as a Service)のAWS, Azul, GCPなどを使って公開することが多いため、ミドルウェア ~ OSの領域の理解があるといいでしょう!それぞれの概要は以下の通りです
-
ミドルウェア
-
webサーバー: Apacheやnginxが主流で、ユーザーからのリクエストを処理します。
-
Apサーバー: アプリケーションとしての処理を行います。
rails s
で起動しているのがApサーバーで、railsではPumaを使います。 -
DBサーバー: データベース関連の処理を行います。
-
-
OS
Linux各種(Ubuntu, CentOs, Amazon Linux etc.), mac, windows
Herokuなどこれらをひっくるめていい感じに公開してくれるツールもありますが、無料枠ではURL指定などができないことや、連続駆動時間が決まっていることなど制限が多くあります...
自分の思い通りに公開をしたいのであれば、これらインフラ周りの知識は少なからず必要になるかと思います!
すべてを学ぶににはAWSなどを使って、アプリを公開してみるのが一番手っ取り早いと思いますが、料金がかかってしまうことや学習コストが大きいと感じます...
そのため学習の際には、まずDockerなどを使って、自分で一からrailsの環境構築を行ってみるといいと思います!
OSを設定して必要なパッケージなどをインストールしてということを、手を動かしながら無料でできるのでおすすめです!
終わりに
いかがでしたでしょうか?
今回は紹介させていたことがすべてではありません!自分のスキルアップは自分で行っていくものですので、自分流の学習を実践していただけるとよろしいかと思います!
ただその中でも、みなさまのrailsの開発スキルアップの参考になれば嬉しく思います
明日は@nabekikikiさんです!おたのしみに!!