やること
-
Rails
に必要なRuby
の知識を学ぶ
動機
ヘルパー
- ビューで使用する関数
- 例:ページのタイトルを出力する関数
- ページタイトルの定義に依存
-
:title
はビュー側で設定-
:title
が未定義の場合はRuby on Rails Tutorial Sample App -
というタイトルになってしまう -
-
が余計
-
現在のタイトル行(レイアウト)
<title>Ruby on Rails Tutorial Sample App - <%= yield(:title) %></title>
具体的なビュー
<% provide(:title, 'Home') %>
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</p>
-
:title
が未定義でもちゃんとしたタイトルを出すfull_title
ヘルパーを作成
app/helpers/application_helper.rb
module ApplicationHelper
def full_title(page_title)
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
"#{base_title} - #{page_title}"
end
end
end
app/views/layouts/application.html.erbを変更
<title><%= full_title(yield(:title)) %></title>
文字列(string)とメソッド
-
Railsコンソール
- Railsアプリケーションを対話的に操作するためのCLIツール
- インタラクティブRuby(
irb
)上に構築されているため、Rubyの機能を全て使うことができる -
Ctrl-C
でスタックから抜ける -
Ctrl-D
でコンソールを終了
- 併せてRuby APIを参照するとよい
- Stringの場合はここ
Railsコンソールの起動
# rails cでも起動できる
$ rails console
# development環境で起動
# 他にはtest環境とproduction環境がある
Loading development environment (Rails 4.0.4)
>
コメント
コメントの確認
$ rails console
Loading development environment (Rails 4.0.4)
> 20 + 40 # 足し算
=> 60
文字列
- ダブルクォートによる文字列
- 文字列の連結は
+
で行う - 文字列の式展開が可能
- 文字列の連結は
ダブルクォートによる文字列
$ rails c
Loading development environment (Rails 4.0.4)
> "" # 空の文字列
=> ""
> "foo" # 空でない文字列
=> "foo"
> "foo" + "bar" # 文字列の連結
=> "foobar"
> first_name = "Michael" # 変数に文字列を設定
=> "Michael"
> "#{first_name} Hartl" # 文字列の式展開
=> "Michael Hartl"
> last_name = "Hartl" # 名前も変数定義
=> "Hartl"
> first_name + " " + last_name
=> "Michael Hartl"
> "#{first_name} #{last_name}"
=> "Michael Hartl"
- 文字列の標準出力
-
puts
- 改行あり
- 戻り値なし
-
print
- 改行なし
- 戻り値なし
-
p
- 改行あり
- 戻り値あり
-
文字の出力
$ rails c
Loading development environment (Rails 4.0.4)
> puts "foo" # 文字列の出力(改行あり)
foo
=> nil
> print "foo" # 文字列の出力(改行なし)
foo => nil
> print "foo\n" # \nで改行
foo
=> nil
> p "foo" # 文字列の出力+戻り値として返却
"foo"
=> "foo"
- シングルクォート
- ダブルクォートと大体同じだが、式展開できない
- 特殊文字など、エスケープしなければならない文字を多く含む場合に有用
シングルクォートによる文字列
$ rails c
Loading development environment (Rails 4.0.4)
> 'foo' # シングルクォートによる文字列
=> "foo"
> foo = 'foo' # 変数定義
=> "foo"
> "#{foo}" # ダブルクォートによる式展開
=> "foo"
> '#{foo}' # シングルクォートだと式展開されない
=> "\#{foo}"
> "\n" # ダブルクォートによる特殊文字
=> "\n"
> '\n' # シングルクォートだと改行と解釈されない
=> "\\n"
オブジェクトとメッセージ受け渡し
- オブジェクト
- メッセージに応答するもの
- メッセージは一般的にメソッドと呼ぶ
- メソッド
- 関数
- メソッド名の末尾に
?
のついているメソッドはboolean
を返す
オブジェクトとメッセージ受け渡し
> "foobar".length # 文字列にlengthというメッセージを渡す
=> 6
> "foobar".empty? # 空文字かどうかを判定
=> false
> "".empty? # 空文字かどうかを判定
=> true
- 条件分岐
if - elsif - else - end
-
unless
はif
の否定 - AND:
&&
、OR:||
、否定:!
条件分岐
> # 条件分岐
> s = "foobar"
=> "foobar"
> if s.empty?
> "The string is empty"
> else
> "The string is nonempty"
> end
=> "The string is nonempty"
> x = "foo"
=> "foo"
> y = ""
=> ""
> puts "Both strings are empty" if x.empty? && y.empty?
=> nil
> puts "One of the strings is empty" if x.empty? || y.empty?
One of the strings is empty
=> nil
> puts "x is not empty" if !x.empty?
x is not empty
=> nil
> puts "x is not empty" unless x.empty?
x is not empty
=> nil
-
nil
の扱い- 特殊なオブジェクト
- Javaの
null
と違って、メソッドを呼び出してもエラーにはならない - オブジェクトそのものが
false
になる-
nil
以外のオブジェクトはtrue
-
nilの確認
> # nilはfalse
> if nil
> true
> else
> false
> end
=> false
> # nil以外はtrue
> if 0
> true
> else
> false
> end
=> true
メソッドの定義
- メソッドの定義
def メソッド名(引数) ~ end
- 暗黙の戻り値を持つ
- 最後に評価された式の値が自動的に返却される
- 明示的に指定する場合は
return
を使用
メソッドの定義と戻り値
> def string_message(string)
> if string.empty?
> "It's an empty string!"
> else
> "The string is noempty."
> end
> end
=> nil
> puts string_message("")
It's an empty string!
=> nil
> puts string_message("foobar")
The string is noempty.
=> nil
returnを使って明示的に戻り値を返却
> def string_message(string)
> return "It's an empty string!" if string.empty?
> return "The string is noempty." # returnを使わなくても返却される
> end
=> nil
> string_message("foo")
=> "The string is noempty."
> string_message("")
=> "It's an empty string!"
モジュール
- モジュール
- 関連したメソッドをまとめる方法の1つ
- Rubyのクラスに
include
を使うことでミックスインすることができる-
Rails
の場合、module ApplicationHelper
は全てのビューで自動的にinclude
される
-
app/helpers/application_helper.rb
module ApplicationHelper
# 全てのビューでfull_titleメソッドを使用できる
def full_title(page_title)
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
"#{base_title} - #{page_title}"
end
end
end
他のデータ構造
配列と範囲演算子
-
split
- 文字列から配列を取得
- 区切り文字を引数として指定できる
- 引数未指定の場合は半角スペースで区切る
文字列を配列に分割(split)
> "foo bar baz".split # 文字列を3つの要素に分割
=> ["foo", "bar", "baz"]
> "foo,bar,baz".split(",") # 区切り文字を指定して分割
=> ["foo", "bar", "baz"]
- Rubyの配列
- 0始まり
- 文字列と数値が混在可能
- 定義
-
[42, 17, "a", "b"]
みたいな感じで定義 - 文字列だけなら
%w[a b c d]
のように定義できる
-
- アクセス
- 角括弧を使用
-
first
、second
、last
などでもアクセス可能 -
-1
で配列の末尾にアクセス、-2
で末尾から2番目に・・・という形で指定できる
- 長さの取得
length
- 並び替え(配列自身は変更しない。変更する場合は末尾に
!
をつける(破壊的なメソッド))-
sort
:昇順に並び替え -
reverse
:降順に並び替え -
shuffle
:ランダム?に並び替え
-
- 要素の追加/取り出し
-
push
:配列の末尾に追加 -
<<
:配列の末尾に追加 -
shift
:配列の先頭に追加 -
pop
:配列の末尾から要素を取り出し -
unshift
:配列の先頭から要素を取り出し
-
- 配列→文字列
join
Rubyの配列
> a = [42, 8, 17]
=> [42, 8, 17]
> a[0] # 配列の1つ目にアクセス
=> 42
> a.first # 配列の1つ目にアクセス
=> 42
> a[a.length-1] # 配列の末尾にアクセス
=> 17
> a.last # 配列の末尾にアクセス
=> 17
> a[-1] # 配列の末尾にアクセス
=> 17
> a[1] # 配列の2番目にアクセス
=> 8
> a.second # 配列の2番目にアクセス
=> 8
> a.length # 配列の長さを取得
=> 3
> a.sort # 配列を昇順に並び替え
=> [8, 17, 42]
> a # a自身は並び変わっていない
=> [42, 8, 17]
> a.reverse # 配列を降順に並び替え
=> [17, 8, 42]
> a.shuffle # 配列をランダムに並び替え
=> [17, 8, 42]
> a.shuffle # 配列をランダムに並び替え
=> [42, 8, 17]
> a.sort! # 配列を昇順に並び替え(破壊的なメソッド)
=> [8, 17, 42]
> a # a自身も並び変わる
=> [8, 17, 42]
> a.push(6) # 配列の末尾に6を追加
=> [8, 17, 42, 6]
> a.push(7).push(8) # 複数追加
=> [8, 17, 42, 6, 7, 8]
> a << 9 # 配列の末尾に9を追加
=> [8, 17, 42, 6, 7, 8, 9]
> a << 10 << 11 # 複数追加
=> [8, 17, 42, 6, 7, 8, 9, 10, 11]
> a.unshift(1) # 配列の先頭に1を追加
=> [1, 8, 17, 42, 6, 7, 8, 9, 10, 11]
> a.shift # 配列の先頭を取得+配列から除去
=> 1
> a
=> [8, 17, 42, 6, 7, 8, 9, 10, 11]
> a.pop # 配列の末尾を取得+配列から除去
=> 11
> a
=> [8, 17, 42, 6, 7, 8, 9, 10]
> a
=> [8, 17, 42, 6, 7, 8, 9, 10]
> a.join # 配列を結合して文字列に
=> "81742678910"
> a.join(", ") # 区切り文字を追加
=> "8, 17, 42, 6, 7, 8, 9, 10"
- 範囲
- 表記
-
0..9
で0123456789 -
'a'..'e'
でabcde
-
- 配列に変換
to_a
- 範囲を丸括弧で括る必要あり
(0..9).to_a
- 表記
範囲
> (0..9).to_a # 数値の範囲を配列に変換
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> ('a'..'e').to_a # 文字の範囲を配列に変換
=> ["a", "b", "c", "d", "e"]
> a = %w[foo bar baz quux]
=> ["foo", "bar", "baz", "quux"]
> a[0..2] # 配列の1、2、3番目を取得
=> ["foo", "bar", "baz"]
> a = (0..9).to_a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> a[2..(a.length-1)] # 配列の3~10番目を取得
=> [2, 3, 4, 5, 6, 7, 8, 9]
> a[2..-1] # 負の値を使用した場合
=> [2, 3, 4, 5, 6, 7, 8, 9]
ブロック
- ブロック
- 波括弧または
do ~ end
で表現可能 - 無名関数
- 配列の場合、
each
やmap
などと組合わせて使うことで強力な処理を実施可能
- 波括弧または
-
each
- 配列や範囲の各要素に対して、ブロックで指定した処理を実施
-
map
- 配列や範囲の各要素に対して、与えられたブロックを適用した結果を返す
-
times
- ブロックの内容を繰り返し処理
eachの使い方
> (1..5).each { |i| puts 2 * i } # {}を使ったブロック
2
4
6
8
10
=> 1..5
> (1..5).each do |i| # do end を使ったブロック
> puts 2 * i
> end
2
4
6
8
10
=> 1..5
> (1..5).each do |i| # 単一行の処理の場合は{}、複数行の処理はdo endを使う
> puts 2 * i
> puts "--"
> end
2
--
4
--
6
--
8
--
10
--
=> 1..5
mapの使い方
> (1..5).map { |i| i**2 } # 各要素に対して累乗した配列を返却
=> [1, 4, 9, 16, 25]
> %w[a b c].map { |char| char.upcase } # 各要素を大文字に変換した配列を返却
=> ["A", "B", "C"]
> %w[A B C].map { |char| char.downcase } # 各要素を小文字に変換した配列を返却
=> ["a", "b", "c"]
timesの使い方
> 3.times { puts "test" } # 3回ブロックの中身を処理する
test
test
test
=> 3
ハッシュとシンボル
- ハッシュ
- 配列とほぼ同じだが、インデックスとして整数値以外も使用できる
- キーと値のペアを波括弧で囲んで表現
- ブロックとは関係ない
- 並び順が保証されない
- 定義
h = {}
h["key1"] = "value1"
h = { "key1" => "value1", "key2" => "value2" }
ハッシュの実行例
> user = {} # ハッシュの定義
=> {}
> user["first_name"] = "Michael" # キーと値の設定
=> "Michael"
> user["last_name"] = "Hartl" # キーと値の設定
=> "Hartl"
> user # ハッシュの参照
=> {"first_name"=>"Michael", "last_name"=>"Hartl"}
> user["first_name"]
=> "Michael"
> user["last_name"]
=> "Hartl"
> user = { "first_name" => "Michael", "last_name" => "Hartl" } # ハッシュロケット(=>)による定義
=> {"first_name"=>"Michael", "last_name"=>"Hartl"}
- シンボル
- ハッシュのキーとして使用
- 文字列ではなくシンボルを使うのが普通
- 先頭に
:
をつける
- ハッシュのキーとして使用
シンボル
> "name".split('')
=> ["n", "a", "m", "e"]
> :name.split('')
NoMethodError: undefined method `split' for :name:Symbol
from (irb):72
from /home/asam-3/rails_projects/sample_app/vendor/bundler/ruby/2.0.0/gems/railties-4.0.4/lib/rails/commands/console.rb:90:in `start'
from /home/asam-3/rails_projects/sample_app/vendor/bundler/ruby/2.0.0/gems/railties-4.0.4/lib/rails/commands/console.rb:9:in `start'
from /home/asam-3/rails_projects/sample_app/vendor/bundler/ruby/2.0.0/gems/railties-4.0.4/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
> user = { :name => "Michael Hartl", :email => "michael@example.com" } # シンボルを使ったハッシュの定義
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
> user[:name]
=> "Michael Hartl"
> user[:email]
=> "michael@example.com"
> user[:password] # 存在しないキーについてはnil
=> nil
> user = { first_name: "Michael", last_name: "Hartl" } # シンボルを使った場合の別の記法
=> {:first_name=>"Michael", :last_name=>"Hartl"}
> user[:first_name]
=> "Michael"
> user[:last_name]
=> "Hartl"
- ハッシュのネスト
- ハッシュの値にハッシュを指定可能
ハッシュのネスト
> params = {}
=> {}
> params[:user] = { name: "Michael Hartl", email: "mhartl@example.com" } # ハッシュのネスト
=> {:name=>"Michael Hartl", :email=>"mhartl@example.com"}
> params
=> {:user=>{:name=>"Michael Hartl", :email=>"mhartl@example.com"}}
> params[:user]
=> {:name=>"Michael Hartl", :email=>"mhartl@example.com"}
> params[:user][:email]
=> "mhartl@example.com"
> params = { # {}の中でネストして記載することも可能
> user: {
> name: "Michael Hartl",
> email: "mhartl@example.com"
> }
> }
=> {:user=>{:name=>"Michael Hartl", :email=>"mhartl@example.com"}}
> params[:user][:name]
=> "Michael Hartl"
- ハッシュとeach
- ハッシュのキーと値のペア毎に処理を行う
- ブロックの変数は2つ
ハッシュとeach
> flash = { success: "It worked!", error: "It failed." }
=> {:success=>"It worked!", :error=>"It failed."}
> flash.each do |key, value| # 2つのキーと値の組み合わせについて処理
> puts "Key #{key} has value #{value}"
> end
Key success has value It worked!
Key error has value It failed.
=> {:success=>"It worked!", :error=>"It failed."}
> flash.each do |key, value| # inspectメソッドを使って、制御文字もそのまま出力するように設定
> puts "Key #{key.inspect} has value #{value.inspect}"
> end
Key :success has value "It worked!"
Key :error has value "It failed."
=> {:success=>"It worked!", :error=>"It failed."}
- オブジェクトを表現する文字列の返却
inspect
-
p
を使用すると、puts 配列.inspect
などと同等の表現になる
inspect
> puts (1..5).to_a # 配列を文字列として出力
1
2
3
4
5
=> nil
> puts (1..5).to_a.inspect # 配列のリテラルを出力
[1, 2, 3, 4, 5]
=> nil
> puts :name # シンボルを出力
name
=> nil
> puts :name.inspect # シンボルのリテラルを出力
:name
=> nil
> puts "It worked!" # 文字列を出力
It worked!
=> nil
> puts "It worked!".inspect # 文字列のリテラルを出力
"It worked!"
=> nil
> p :name # pでシンボルを出力→シンボルのリテラルを出力
:name
=> :name
> puts :name.inspect # putsで表現する場合はinspectメソッドを使用
:name
=> nil
レイアウトファイルの1行を見直し
-
stylesheet_link_tag
メソッドの呼び出し- メソッドの呼び出しに括弧は不要
- 第1引数:
application
文字列 - 第2引数:
media: "all", "data-turboliks-track" => true
ハッシュ- 最後の引数がハッシュの場合、
{}
の記述は不要 - シンボルだと
-
を使えないので、ハッシュロケット記法で記載
- 最後の引数がハッシュの場合、
apps/views/layouts/application.html.erb
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= stylesheet_link_tag("application", media: "all", "data-turbolinks-track" => true) # 丸括弧あり版 %>
<%= stylesheet_link_tag "application", { media: "all", "data-turbolinks-track" => true } # ハッシュを{}で表現した場合 %>
上記実行結果
<link data-turbolinks-track="true" href="/assets/application.css" media="all" rel="stylesheet" />
Rubyにおけるクラス
コンストラクタ
- コンストラクタ
- オブジェクトの生成に使用
-
new
メソッドで作成 -
class
メソッドでクラスを確認
文字列のコンストラクタ
> s = "foobar" # 文字列のリテラルコンストラクタ
=> "foobar"
> s.class
=> String
> s = String.new("foobar") # 文字列の名前付きコンストラクタ
=> "foobar"
> s.class
=> String
> s == "foobar"
=> true
配列のコンストラクタ
> a = [1, 3, 2] # 配列の暗黙的なコンストラクタ
=> [1, 3, 2]
> a.class
=> Array
> a = Array.new([1, 3, 2]) # 配列の名前付きコンストラクタ
=> [1, 3, 2]
> a.class
=> Array
- ハッシュのコンストラクタ
- キーが存在しない場合のデフォルト値を指定できる
ハッシュのコンストラクタ
> h = {} # ハッシュの暗黙的なコンストラクタ
=> {}
> h.class
=> Hash
> h[:foo] # 存在しないキーを指定するとnilを返す
=> nil
> h = Hash.new # ハッシュの名前付きコンストラクタ
=> {}
> h[:foo] # 存在しないキーを指定するとnilを返す
=> nil
> h = Hash.new(0) # 存在しないキーを指定した場合の戻り値を指定
=> {}
> h[:foo] # 存在しないキーを指定すると0を返す
=> 0
クラス継承
- クラス継承
-
superclass
メソッドで親クラスを確認 -
BasicObject
>Object
>クラス
という形の継承階層になっている
-
クラス継承の確認
> s = "foobar"
=> "foobar"
> s.class # sのクラス:String
=> String
> s.class.superclass # sの親クラス:Object
=> Object
> s.class.superclass.superclass # sの親クラスの親クラス:BasicObject
=> BasicObject
> s.class.superclass.superclass.superclass
=> nil
- クラスの定義
class クラス名 end
- 継承する場合は
class クラス名 < 親クラス名 end
独自のクラス定義(Word)
> class Word
> def palindrome?(string)
> string == string.reverse
> end
> end
=> nil
> w = Word.new
=> #<Word:0x00000006055d60>
> w.palindrome?("foobar")
=> false
> w.palindrome?("level")
=> true
> w.class
=> Word
> w.class.superclass # 独自クラスでも親クラスはObject
=> Object
> w.class.superclass.superclass
=> BasicObject
Wordクラスの改善:Stringを継承
> class Word < String
> # 文字列が鏡文字であればtrueを返す
> def palindrome?
> self == self.reverse # selfはクラス自身をあらわす
> end
> end
=> nil
> s = Word.new("level") # コンストラクタに値を渡す
=> "level"
> s.palindrome?
=> true
> s.length
=> 5
> s = Word.new("foobar")
=> "foobar"
> s.palindrome?
=> false
組み込みクラスの変更
- Rubyの組み込み基本クラスは拡張が可能
- よほどのことがない限り、組み込みクラスにメソッドを追加すべきではない
- Railsにおける組み込みクラスの変更
- いくつか行われている
- 例:
String
クラスにblank?
メソッドを追加- 空文字または半角スペースのみの場合に
true
- Rails独自での組み込みクラスの変更なので、
irb
においてはblank?
は使えない -
nil.blank?
もtrueとなるようにObject
クラスも変更している
- 空文字または半角スペースのみの場合に
blank?メソッド
> "".empty? # 空文字の場合はtrue
=> true
> "".blank? # 空文字の場合はtrue
=> true
> " ".empty? # 空白文字の場合はfalse
=> false
> " ".blank? # 空白文字の場合もtrue
=> true
> nil.empty? # nilに使用すると実行時例外
NoMethodError: undefined method `empty?' for nil:NilClass
from (irb):16
from /home/asam-3/rails_projects/sample_app/vendor/bundler/ruby/2.0.0/gems/railties-4.0.4/lib/rails/commands/console.rb:90:in `start'
from /home/asam-3/rails_projects/sample_app/vendor/bundler/ruby/2.0.0/gems/railties-4.0.4/lib/rails/commands/console.rb:9:in `start'
from /home/asam-3/rails_projects/sample_app/vendor/bundler/ruby/2.0.0/gems/railties-4.0.4/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
> nil.blank? # nilの場合もtrue
=> true
コントローラクラスの見方
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
end
def help
end
def about
end
def contact
end
end
StaticPagesControllerのクラス継承階層を確認
> controller = StaticPagesController.new
=> #<StaticPagesController:0x00000002c16978 @_routes=nil, @_action_has_layout=true, @_headers={"Content-Type"=>"text/html"}, @_status=200, @_request=nil, @_response=nil>
> controller.class
=> StaticPagesController
> controller.class.superclass
=> ApplicationController
> controller.class.superclass.superclass
=> ActionController::Base
> controller.class.superclass.superclass.superclass
=> ActionController::Metal
> controller.class.superclass.superclass.superclass.superclass
=> AbstractController::Base
> controller.class.superclass.superclass.superclass.superclass.superclass
=> Object
> controller.home
=> nil
-
StaticPagesController
の継承階層ApplicationController
ActionController::Base
ActionController::Metal
AbstractController::Base
Object
- Railsにおいては、個々のクラスの実装について理解しておく必要はない
- 各アクションについて、戻り値は特に不要
ユーザークラス
- ユーザークラス
- 第6章で使用する
User
クラスを作成
- 第6章で使用する
example_user.rb
class User
attr_accessor :name, :email
def initialize(attributes = {})
@name = attributes[:name]
@email = attributes[:email]
end
def formatted_email
"#{@name} <#{@email}>"
end
end
-
attr_accessor
- アトリビュートアクセサを作成
-
@name
と@email
のgetterとsetterを生成 - Railsではビューで自動的に使用できるようになる
example_user.rbをRailsコンソールで実行してみる
> require './example_user'
=> true
> example = User.new
=> #<User:0x00000003b4c0a0 @name=nil, @email=nil>
> example.name
=> nil
> example.email
=> nil
> example.name = "Example User"
=> "Example User"
> example.email = "user@example.com"
=> "user@example.com"
> example.formatted_email
=> "Example User <user@example.com>"
> example2 = User.new(name: "Example2 User", email: "user@example.com")
=> #<User:0x0000000532c350 @name="Example2 User", @email="user@example.com">
> example2.formatted_email
=> "Example2 User <user@example.com>"
最後に
コミット
# 不要なので削除
$ rm -f example_user.rb
$ git add .
$ git commit -m "Add a full_title helper"