railsチュートリアルまとめ4 Rails風味のRuby

# 個人的リマインド用
参考
[Ruby on Rails チュートリアル プロダクト開発の０→１を学ぼう](https://railstutorial.jp/)

## Rails風味のRuby

### 組み込みヘルパー
application.htmlから抜粋
```
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
```
ここではRailsの組み込み関数stylesheet_link_tagを使って、application.cssをすべてのメディアタイプで使えるようにしている。この行には戸惑うRubyの概念が4つある。**Railsの組み込み関数、括弧を使わないメソッド呼び出し、シンボル、そしてハッシュ。**

### カスタムヘルパー
新しく作ったメソッドのことを**カスタムヘルパー**という。
例：full_titleというカスタムヘルパーを作って、titleのコードを書き換える。
```ruby
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
      "#{page_title} | #{base_title}"
    end
  end
end
```
このヘルパーを使うと
```erb
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
```
から
```erb
<title><%= full_title(yield(:title)) %></title>
```
になる。置き換えた結果
```erb
app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>　←追加
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta charset="utf-8">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>
```
```ruby
test/controllers/static_pages_controller_test.rb

require "test_helper"

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Ruby on Rails Tutorial Sample App" #←書き換え
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

  test "should get about" do
    get static_pages_about_url
    assert_response :success
    assert_select "title", "About | Ruby on Rails Tutorial Sample App"
  end
end
```
```erb
app/views/static_pages/home.html.erb

(テストをパスするためにprovideを消す)
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
  sample application.
</p>
```
### 文字列とメソッド
初歩的なところは飛ばしていく

式展開
```
first_name = "Michael"
"#{first_name} Hartl" ←文字列内に変数を展開
```
### オブジェクトとメッセージ受け渡し
Rubyではあらゆるものがオブジェクト。文字列やnilですらオブジェクト。
```
"foobar".length 文字列にlengthというメソッドを呼ぶと文字数が返ってくる
=> 6

"foobar".empty? 特定のメソッドの最後に?をつけると倫理値が帰ってくる
=> false 
```
```
nil.to_s.empty?
メソッドチェーンで繋げることもできる

puts "x is not empty" if !x.empty?
puts "x is not empty" unless x.empty?
!やunlessで否定形

!!nil 
=> false
!!を先頭につけると強制的に論理値を返すように。falseとnilがfalse。他は全部true
```
### メソッドの定義
**デフォルト値：** 引数に何も渡されない時に使う値
```
def string_message(str = '')
```
Rubyのメソッドには**暗黙の戻り値**がある。メソッドの最後に評価した値を自動的に返すというもの。returnを使えば明示的に返すことができる。

以上の知識で最初のコードを評価できる
```ruby
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
      "#{page_title} | #{base_title}"                 # 文字列の式展開
    end
  end
end
```
最後にmoduleに関しては、互いに関連する複数のメソッドをまとめる方法の1つで、includeメソッドを使ってモジュールを読み込むことができる。これを**ミックスイン**と呼ぶ。ちなみにRubyのコードを書くのならば、モジュールを作成するたびに明示的に読み込んで使うのが普通だが、**Railsでは自動的にヘルパーモジュールを読み込んでくれるので、includeを書かなくていい。つまりfull_titleメソッドは自動的に全てのビューで利用できるようになっている。**

### 配列に関して
**split**
```
"foo bar   baz".split #文字列を3つの要素を持つ配列に分割する
=> ["foo", "bar", "baz"]

"fooxbarxbaz".split('x') #空白ではなく指定の文字でも分割できる
```
**代入**
```
>> a = [42, 8, 17]
>> a.push(6)                  # 6を配列に追加する
=> [42, 8, 17, 6]
>> a << 7                     # 7を配列に追加する
=> [42, 8, 17, 6, 7]
>> a << "foo" << "bar"        # 配列に連続して追加する
=> [42, 8, 17, 6, 7, "foo", "bar"]
```
**join**
```
>> a
=> [42, 8, 17, 6, 7, "foo", "bar"]
>> a.join                       # 単純に連結する
=> "4281767foobar"
>> a.join(', ')                 # カンマ+スペースを使って連結する
=> "42, 8, 17, 6, 7, foo, bar"
```
**range**
```
>> 0..9
=> 0..9
>> (0..9).to_a 
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```
配列の取り出し
```
>> a = %w[foo bar baz quux]         # %wを使って文字列の配列に変換
=> ["foo", "bar", "baz", "quux"]
>> a[0..2]
=> ["foo", "bar", "baz"]
```
### ブロック
こういうの
```
>> (1..5).each { |i| puts 2 * i }
2
4
6
8
10
=> 1..5
```
{ |i| puts 2 * i }の部分がブロックと呼ばれている。
{}ではなくdo,endにすることもできる。その場合は1行では書けない。
```
>> (1..5).each do |i|
?>   puts 2 * i
>> end
2
4
6
8
10
=> 1..5
```
timesやmapを使った場合
```
>> 3.times { puts "Betelgeuse!" }   # 3.timesではブロックに変数を使っていない
"Betelgeuse!"
"Betelgeuse!"
"Betelgeuse!"
=> 3

>> (1..5).map { |i| i**2 }          # 「**」記法は冪乗 (べき乗)
=> [1, 4, 9, 16, 25]
>> %w[a b c]                        # %w で文字列の配列を作成
=> ["a", "b", "c"]
>> %w[a b c].map { |char| char.upcase }
=> ["A", "B", "C"]
>> %w[A B C].map { |char| char.downcase }
=> ["a", "b", "c"]
```
{ |char| char.メソッド名 }の部分を、&:メソッド名にすることもできる
```
>> %w[A B C].map { |char| char.downcase }
=> ["a", "b", "c"]
>> %w[A B C].map(&:downcase)
=> ["a", "b", "c"]
```
### ハッシュとシンボル
**ハッシュ**
キーと値を保存するもの
```
user["first_name"] = "Michael"
user["first_name"]
=> "Michael"
```
こういう書き方もあれば
```
user = { "first_name" => "Michael", "last_name" => "Hartl" }
```
こういう書き方もある。
しかしRailsでは文字列よりも**シンボル**を使う方が一般的。
```
>> user = { :name => "Michael Hartl", :email => "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> user[:name]              
=> "Michael Hartl"
>> user[:password]         
=> nil
```
そしてその後にJavaScriptみたいに書けるようになった
```
>> h2 = { name: "Michael Hartl", email: "michael@example.com" }
```
さらにハッシュの中にハッシュを入れられる(ネストされたハッシュ)
```
>> 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][:email]
=> "mhartl@example.com"
```
### CSSについて
上記の内容でcssの読み込み文が理解できるはず
```
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
```
**疑問点**
1.丸括弧がない
→Rubyではメソッド呼び出しの丸括弧は無視していい
```
# メソッド呼び出しの丸カッコは省略可能。
stylesheet_link_tag("application", "data-turbo-track": "reload")
# 上は以下のように書いても同じ
stylesheet_link_tag "application", "data-turbo-track": "reload"
```
2.ハッシュの波括弧がない
→ハッシュがメソッド呼び出しの最後の引数である場合は、波括弧を省略できる。
```
# 最後の引数がハッシュの場合、波カッコは省略可能。
stylesheet_link_tag("application", { "data-turbo-track": "reload" })
# 上は以下のように書いても同じ
stylesheet_link_tag("application", "data-turbo-track": "reload")
```
ちなみに最初の引数は、スタイルシートへのパスを指定する文字列。次の引数はTurbo(のちに説明)の設定を1個含んでいる。

### コンストラクタ
文字列のインスタンスを作成
```
s = "foobar"
s.class
=> String
```
これは文字列のオブジェクトを暗黙で作成する**リテラルコンストラクタ**
```
s = String.new("foobar")
s.class
=> String
s == "foobar"
=> true
```
これは明示的な**名前付きコンストラクタ**

配列でも、文字列と同様にインスタンスを生成できる。
```
a = Array.new([1, 3, 2])
=> [1, 3, 2]
```
ただしハッシュは少し異なり、配列のコンストラクタであるArray.newは配列の初期値を引数に取るが、Hash.newはハッシュのデフォルト値を引数に取る。
```
h = Hash.new
=> {}
h[:foo] #存在しない値にアクセス
=> nil 
h = Hash.new(0) #存在しないキーのデフォルト値をnilから0にする
h[:foo]
=> 0
```
メソッドがクラス自身(この場合はnew)に対して呼び出される時、このメソッドを**クラスメソッド**と呼ぶ。クラスのnewメソッドを呼び出した結果は、そのクラスのオブジェクトであり、これはクラスの**インスタンス**とも呼ばれる。lenggthのように、インスタンスに対して呼び出すメソッドは**インスタンスメソッド**と呼ばれる。

### クラスの継承
最初の方は飛ばす。

```
>> class Word < String             # WordクラスはStringクラスを継承する
>>   # 文字列が回文であればtrueを返す
>>   def palindrome?
>>     self == self.reverse        # selfは文字列自身を表します
>>   end
>> end
```
Rubyではselfを使うと自分自身を指定できる。Wordクラスの中では、selfはオブジェクト自身を指す。
```
self == self.reverse
```
Stringクラスの内部では、メソッドや属性を呼び出すときのself.も省略可能
```
self == reverse
```
### アクセサー
```ruby
class User
  attr_accessor :name, :email #←アクセサー

  def initialize(attributes = {})
    @name  = attributes[:name]
    @email = attributes[:email]
  end

  def formatted_email
    "#{@name} <#{@email}>"
  end
end
```
アクセサーを作成すると、そのデータを取り出すメソッド(getter)と、データに代入するメソッド(setter)をそれぞれ定義してくれる。具体的には、この行を実行したことにより、インスタンス変数@nameと@emailにアクセスするためのメソッドが用意される。

initializeは特殊なメソッドで、User.newを実行すると自動的に呼び出される。initializeメソッドはattributesという引数を1つとる。
```
  def initialize(attributes = {})
    @name  = attributes[:name]
    @email = attributes[:email]
  end
```
上のコードでattributes変数はからのハッシュをデフォ値としてもつため、名前やメールアドレスのないユーザーを作れる。存在しないキーに対してハッシュはnilを返すので、:nameキーがなければattributes[:name]はnilになる。