この記事では、Ruby on Rails(以下 Rails)を理解するために最低限知っておきたいRubyの基本文法を解説します。
Railsを学び始めたとき、
- 書き方は真似できるけど、意味がよく分からない
- なぜこのコードで動くのか説明できない
- Railsが「魔法」に見えてしまう
と感じたことはないでしょうか。
その原因の多くは、Rubyの基本文法を「Railsの文脈で」理解できていないことにあります。
この記事では、Railsを「読める・理解できる」ようになるために 最低限必要なRuby文法 だけに絞って解説します。
なぜRailsを書くにはRubyが必要なのか
Railsは、Rubyで作られたWebアプリケーションフレームワークです。
Railsで書くコードは、Rails専用の特別な言語ではなく、Rubyの構文を使って記述します。
ただし、Railsは単なるRubyの集まりではありません。
Rubyの仕組みを活用しながら、Webアプリ開発を効率化するための独自のメソッドや書き方(DSL)を提供しています。
そのため、Railsを書くためには、
- Rubyの文法
- RubyをもとにRailsが独自に提供している仕組み
この2つを理解することが重要になります。
※ 本記事ではまず 「Rubyの文法」 に焦点を当てます。
※ 「Railsが追加している仕組み」 については、別記事「Railsとは|MVCの基本とRails APIの全体像をわかりやすく解説(準備中)」で解説します。
Rubyの文法としてのRailsコード
たとえば、RailsのModelは次のように定義します。
class Post < ApplicationRecord
end
このコードは、Rails独自の特別な記法ではありません。
Rubyのクラス定義そのものです。
Rubyの基礎を理解していると、
classはクラス定義であること<は継承を表していることApplicationRecordは親クラスであること
が自然に読み取れるようになります。
つまり、Rubyの文法が分かるようになると、 Railsのコードを「意味のあるRubyコード」として読めるようになります。
Railsコードに頻出するRuby文法
Railsを読む・書くうえで、頻出するRuby文法は実は多くありません。
この記事では、次の文法に絞って解説します。
- class / def / end(クラスとメソッド定義)
- メソッド呼び出し
- 継承
- インスタンス変数
- 配列 / ハッシュ・シンボル
- if(ロジックを作る)
また、Railsを書く上では必須ではありませんが、Railsの仕組みが理解しやすくなるRubyの文法として、
- initialize
- attr_reader
にも軽く触れます。
それでは、Railsのコードを読み解くために、Rubyの基本文法を一つずつ見ていきましょう。
class / def / end(クラスとメソッド定義)
Rubyでは、クラスやメソッドを次のように定義します。
class User
def greet
"Hello"
end
end
以下は Userクラスを定義 しています。
class User
end
また、クラスの中には、以下のように メソッド(名前は任意) を定義できます。
def greet
"Hello"
end
Railsとのつながり
RailsのModelやControllerも、これらと同じRubyのクラスです。
class Post < ApplicationRecord
def published?
published_at.present?
end
end
上記の例では、
Postクラスを定義しているpublished?というメソッドを定義している
という、純粋なRubyのコードになっています。
メソッド呼び出し
それでは、Ruby/Railsにおけるメソッド呼び出しを見ていきましょう。
インスタンスメソッドの呼び出し
以下のように、クラス内で def メソッド名 と定義するのが インスタンスメソッド です。
class Post
def published?
true
end
end
インスタンスメソッドを呼び出すには、Postクラスをインスタンス化して、Postオブジェクトを作成します。
post = Post.new
作成したオブジェクトに対し「.」をつけて、Postクラス内で定義したインスタンスメソッドを呼び出すことができます。
post.published?
クラスメソッドの呼び出し
以下のように、クラス内で def self.メソッド名 と定義するのが クラスメソッド です。
class Post
def self.unpublished?
true
end
end
※ ここでは「クラスメソッドの呼び出し方」を説明するため、戻り値は常に true にしています。
クラスメソッドを呼び出すには、オブジェクトを作成する必要はありません。
Postクラスに「.」をつけて、Postクラス内で定義したクラスメソッドを呼び出すことができます。
Post.unpublished?
Railsとのつながり
例えば、Rails(正確にはActiveRecord)が用意している、以下の all や find といったクラスメソッドがあります。これらも同様にクラスに「.」をつけて、メソッドを呼び出すことができます。
Post.all
Post.find(1)
継承
Rubyでは、クラスは 他のクラスを継承 できます。
class クラスA < クラスB
end
上記のように書くと、
クラスAはクラスBを継承しているクラスBに定義されたメソッドや定数を使える
という意味になります。
Railsとのつながり
RailsのModelの例を以下に記載します。
class Post < ApplicationRecord
end
これは、
PostクラスがApplicationRecordクラスを継承している
という意味です。
その結果、Post クラスでは ApplicationRecord が持つ機能を使えるようになります。
※ 補足:ApplicationRecord はさらに ActiveRecord::Base を継承しています。そのため find や where などの ActiveRecord の機能が使えるようになっています。
Controllerも同様です。
class PostsController < ApplicationController
end
以上のように、Railsの便利な機能は 継承によって使えるようになっている、という理解がとても重要です。
インスタンス変数
Rubyでは、@ から始まる変数を インスタンス変数 と呼びます。
この仕組みは、Railsの内部でも同じように使われています。
インスタンス変数の特徴は、
- オブジェクトに紐づく
- 同じオブジェクトを扱うクラス内の複数のメソッドから参照できる(※ サブクラスに定義されたメソッドであっても、同じオブジェクトであれば参照できます)
という点です。
インスタンス変数を、シンプルな例で見てみましょう。
class Counter
def initialize
@count = 0
end
def increment
@count += 1
end
def current
@count
end
end
counter = Counter.new
counter.increment # 1回目のincrement呼び出し
counter.increment # 2回目のincrement呼び出し
counter.current # 「2」が出力される
この例では、
@countはCounterオブジェクトに紐づくインスタンス変数initialize・increment・currentという 複数のメソッドから共有 されている
ということが分かります。
※ 同じメソッド内でしか使わない変数は、インスタンス変数にする必要はありません。その場合は、ローカル変数 を使うのが一般的です。
※ 補足:通常のRails(APIモードでない場合)では、Controllerで定義したインスタンス変数はViewからも参照できます。
配列 / ハッシュ・シンボル
配列・ハッシュ・シンボルはRubyの基本的な仕組みで、Railsでも同じように使われています。
配列
Rubyでは、複数の値をまとめて扱うために 配列 を使います。
以下のコード例では、1,2,3の値が配列の形で numbers変数 に格納されています。
numbers = [1,2,3]
ちなみに、以下のように定義すると、中身が何もない空の配列を作ることができます。
numbers = []
配列は、以下のように each を使って中身を取り出せます。
配列.each do |取り出す値(名前は任意)|
# 配列の中身に対する処理
end
以下が配列の中身を取り出すコード例です。
numbers.each do |number|
puts number
end
ハッシュ・シンボル
ハッシュは、キーと値のセットでデータを管理する形式のことです。
以下は、titleというキー・"Hello"という値のセット、bodyというキー・"Sample"という値のセットが params変数 に格納されています。
params = { title: "Hello", body: "Sample" }
ハッシュの中身を取り出すときは、以下のように指定します。
params[:title]
ハッシュが格納された変数[:キー名] のように指定することで、params ハッシュの中から titleキーの値(ここでは"Hello")を取得できます。
:title のような形式をシンボルと言い、Railsでは、ハッシュのキーとしてシンボルがよく使用されます。
if(ロジックを作る)
Railsのロジックは、Rubyの 条件分岐文法 を使って書かれます。
以下のコードは、「post が公開済み(published? が true)であれば、if ~ end の中の処理を実行する」という意味です。
if post.published?
puts post.title
end
【補足】initialize / attr_reader
initialize
initialize は、オブジェクト生成時に呼ばれるメソッドです。
以下のように、User.new を実行すると、initialize メソッドが自動的に呼ばれ、インスタンス変数の初期化などが行われます。
# クラス定義
class User
def initialize
@name = "Guest"
end
end
# 呼び出し側(Userオブジェクト生成)
user = User.new
Railsでは多くの場合、Rails 内部で initialize を利用しているため、私たちがアプリケーション側で明示的に定義する機会は多くありません。
attr_reader
attr_reader は、インスタンス変数の値を呼び出し側(外部)から取得できるようにする仕組みです。
この仕組みは、Railsの内部でも同じように使われています。
attr_reader :インスタンス変数名 のように attr_reader を定義している場合は、外部からの呼び出しの際に、 post.title のように値を参照することができます。
# クラス定義
class Post
attr_reader :title
def initialize(title)
@title = title
end
end
# 呼び出し側
post = Post.new("Hello")
post.title
→ "Hello" が出力される。
ちなみに、 attr_reader を定義すると、内部的には以下のようなメソッドが定義されます。
def title
@title
end
そのため、 post.title は インスタンス変数に直接アクセスしているのではなく、 「title という メソッドを呼び出して、その戻り値として @title を受け取っている」 という形になっています。
attr_reader を定義していない場合は、外部からの呼び出しの際に NoMethodError が発生し、インスタンス変数を参照することができません。
# クラス定義
class Post
def initialize(title)
@title = title
end
end
# 呼び出し側
post = Post.new("Hello")
post.title
→ NoMethodError: undefined method 'title' が発生する。
post.@title のように、オブジェクトの属性(インスタンス変数)に直接アクセスすることは Ruby では禁止されているため、構文エラーになります。
おわりに
この記事では、Railsのコードを読むために最低限知っておきたいRubyの基本文法を解説しました。
Railsで書かれているコードは特別な記法ではなく、
class / def / endによるクラスとメソッド定義- インスタンスメソッド・クラスメソッドの呼び出し
- 継承による機能の引き継ぎ
- インスタンス変数によるオブジェクト内の状態管理
- 配列・ハッシュ・シンボルといった基本データ構造
ifを使った条件分岐
といった、Rubyの文法そのもので構成されています。
また補足として、
initializeは「オブジェクト生成時に一度だけ呼ばれる初期化処理」attr_readerは「インスタンス変数を外部から読むためのメソッドを定義する仕組み」
であることも確認しました。
これらを理解することで、
Railsのコードを「なんとなく動いているもの」ではなく、 「意味の分かるRubyコード」として読めるようになります。
最初はRailsのコード量やメソッドの多さに圧倒されるかもしれませんが、その土台にあるのはシンプルなRubyの文法です。
本記事が、Railsのコードを怖がらずに読み進めるための最初の一歩になれば幸いです。
