Ruby

Rails Tutorialsで勉強のメモ その4(Ruby)

More than 3 years have passed since last update.


やること



  • 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を参照するとよい




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


    • unlessifの否定

    • 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]のように定義できる



    • アクセス


      • 角括弧を使用


      • firstsecondlastなどでもアクセス可能


      • -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で表現可能

    • 無名関数

    • 配列の場合、eachmapなどと組合わせて使うことで強力な処理を実施可能




  • 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クラスを作成




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"