本記事は初心者がエンジニアになる為の学習まとめです。
4.1
下記コードではRubyの戸惑う概念が4つある
・Railsの組み込み関数
・カッコを使わないメソッド呼び出し
・シンボル
・ハッシュ
これらをまずは理解するために復習していきたい。
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</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" %>
<%= javascript_importmap_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
こちらのコード抜粋
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
これらのコードには先ほど上記に述べたコードの4つの要素が含まれているとのこと。
chatGPTで分析させてみました。
Railsの組み込み関数
stylesheet_link_tag
はRailsのヘルパーメソッドの一つで、指定されたスタイルシートファイルへのリンクタグを生成します。このメソッドはRailsのActionViewモジュールによって提供され、HTMLにスタイルシートを組み込む際に非常に便利です。
ActionViewモジュールがリングタグを作成していると解釈
カッコを使わないメソッド呼び出し
Rubyでは、メソッドを呼び出す際に引数が明確であれば、カッコを省略することができます。上の例では、stylesheet_link_tag "application", "data-turbo-track": "reload"
としてメソッドを呼び出しており、カッコが使われていません。これはRubyの構文が非常に柔軟であることを示しています。
他の言語だとカッコ表記でごちゃごちゃしてるけど、Rubyならその表記が省略できると解釈
シンボル
:reload
のようにコロンで始まる識別子は、Rubyのシンボルです。シンボルは文字列に似ていますが、同じシンボルはプログラム全体で一意のオブジェクトを参照するため、効率的に使用されます。ここでは、"data-turbo-track"
という属性に :reload
という値を割り当てています。
属性に対して:から始まる識別子(reroad)を割り当てデータ参照するものだと解釈
ハッシュ
キーと値のペアを表すデータ構造で、この行では "data-turbo-track"``: "reload"
がハッシュの構文を使用しています。このハッシュは、stylesheet_link_tag
メソッドに属性を渡すために使われています。ハッシュのキーはシンボルか文字列であることが多く、ここではキーが文字列で値がシンボルです。
よくわからないので更に質問してみた
あなたが挙げた例では、stylesheet_link_tag "application", "data-turbo-track": "reload" というコードがあります。この中で "data-turbo-track": "reload" は、stylesheet_link_tag メソッドに属性を渡すためのハッシュです。ここでは文字列 "data-turbo-track" をキーとし、文字列 "reload" を値としています。
このハッシュの使用例は、HTML要素にカスタムデータ属性(この場合は data-turbo-track)を動的に追加するために使われます。Railsの stylesheet_link_tag メソッドは、このハッシュを解析し、生成される HTMLタグに適切な属性を組み込みます。これにより、ページがリロードされるたびにブラウザは指定されたスタイルシートを再読み込みするように指示を受けます。
キーとシンボルの組み合わせ=ハッシュ
ハッシュとはメソッドに渡す存在でここではリロードする度にスタイルシートを読み込んでねという指示をしている
と解釈しました。
4.1.2 カスタムヘルパー
新しく作ったメソッドをカスタムヘルパーと呼ぶ
<%= yield(:title) %> | Ruby on Rails Tutorial Sample App
先ほどの上記コードに注目
この行はページタイトルに依存しているとのこと
この定義はビューでprovide
が使われている。
<% provide(:title, "Home") %>
<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>
特定のページで必要に応じて異なるタイトルを設定するオプションを提供することが一般的。provide メソッドを用いてページ固有のタイトルを指定しており、このメソッドの呼び出しを削除すると、そのページでは基本タイトルが表示されるようになる。
つまりtitleを設定していないと表示がされず空欄になる。
ページタイトルが正しく表示されない問題を解決するために、full_titleというヘルパーを作成する
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
このApplicationHelperモジュール内にあるfull_titleメソッドは、Ruby on Railsアプリケーションでページのタイトルを動的に生成するために使用されます。
更にchatGPTで調べてみた
メソッド定義と引数:
full_titleメソッドは、page_titleという名前のオプショナルな引数を持ち、デフォルト値は空文字列''です。
基本タイトルの設定:
base_title変数には、"Ruby on Rails Tutorial Sample App"という文字列が格納されており、これがすべてのページの基本となるタイトルです。
条件分岐:
if文を用いて、引数page_titleが空かどうかをチェックします。
もしpage_titleが空の場合(.empty?メソッドがtrueを返す場合)、base_titleのみをそのページのタイトルとして返します。
page_titleに何か内容がある場合は、page_titleとbase_titleを" | "で区切った形式で組み合わせ、より詳細なページタイトルを生成します。
戻り値:
条件に応じて、単一のbase_titleまたはpage_titleとbase_titleを組み合わせた文字列が戻り値として返されます。
このヘルパーメソッドfull_titleは、ページごとにタイトルが設定されているかを確認するために使用されるものであり、titleが空なのかどうかでbase_titleを返すのかpage_titleとbase_titleを返すのかという
helperと解釈しました。
ここですごくアホな質問なのですが、どこにもapplication_helper.rbを読み込むコードがないけど何でtitleが記述されるの?と疑問に思いました。
chatGPTに聞いてみました。
自動読み込み:
Railsでは、app/helpersディレクトリ内のファイルは自動的に読み込まれます。このため、ApplicationHelperがapp/helpers/application_helper.rbというファイルに定義されている場合、Railsは起動時にこのファイルを読み込み、アプリケーション内のどのビューからでもヘルパーメソッドが利用可能になります。
命名規則:
Railsは規約に基づいて動作するため、ファイル名とモジュール名が一致している必要があります。例えば、ApplicationHelperモジュールはapplication_helper.rbという名前のファイルに記述されるべきです。
モジュールの使用:
ヘルパーメソッドは、ビューファイル内で直接呼び出すことができます。例えば、full_titleメソッドをビューで使用したい場合、特別なインポートやインクルードなしにfull_title("My Page Title")のように直接呼び出すことが可能です。
コントローラとの関連:
Railsでは、特定のコントローラに関連付けられたヘルパーファイルもありますが、ApplicationHelperは全コントローラで共通して使用されるため、すべてのビューで利用できるヘルパーを定義するのに適しています。
application_helperは全ビューで適用される。と解釈しました。
4.2.4 title Helper再び
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
ApplicationHelperモジュールについての解説では、Rubyのモジュールがメソッド群をまとめるための手段であり、ミックスインとして他のクラスやモジュールに組み込むことができる。通常Rubyではモジュールを明示的に読み込む必要がありますが、Railsではヘルパーモジュールが自動的に読み込まれるため、個別にincludeを記述する必要はありません。その結果、full_titleメソッドのようなヘルパーメソッドは全てのビューで自動的に利用可能となっている。
4.3.2ブロック
配列と範囲はいずれも、ブロックを伴う様々なメソッドに対して応答することができます。ブロックは、Rubyの極めて強力な機能であり、かつわかりにくい機能でもあります。
確かに14章完走してもどういうことなのか?わからなかったです!改めて確認していきます。
>> (1..5).each { |i| puts 2 * i }
2
4
6
8
10
=> 1..5
each メソッドを使って範囲内の各数値に対し、ブロック { |i| puts 2 * i } を実行しています。このブロック内で、i というブロック変数を使い、それぞれの数値を2倍して出力しています。ブロック変数は縦棒「|」で囲まれ、範囲内の値が順に代入され、処理が行われる。
.eachは要素の集まりに対して繰り返し行う処理である
1~5までの変数をiに代入し*iの部分で1~5までの範囲で掛け算が行われ
各数字が出力されていると解釈
>> (1..5).each do |i|
?> puts 2 * i
>> end
2
4
6
8
10
=> 1..5
ブロックであることを示すには波カッコ で囲みますが、次のようにdoとendで囲んで示すこともできるとのこと。
chat GPTより解説
波括弧 {}:
一般的に、単一行のブロックや短いブロックに使用されます。
記述が簡潔で、ブロックの内容がすぐに把握できる場合に適しています。
do...end:
複数行にわたるブロックや、内容が複雑なブロックに使われることが多いです。
視覚的に始点と終点が明確なため、長いブロックでの読みやすさが向上します
4.3.3ハッシュとシンボル
>> user = {} # {}は空のハッシュ
=> {}
>> user["first_name"] = "Michael" # キーが "first_name" で値が "Michael"
=> "Michael"
>> user["last_name"] = "Hartl" # キーが "last_name" で値が "Hartl"
=> "Hartl"
>> user["first_name"] # 要素へのアクセスは配列の場合と似ている
=> "Michael"
>> user # ハッシュのリテラル表記
=> {"last_name"=>"Hartl", "first_name"=>"Michael"}
ハッシュは、キーと値のペアを波カッコで囲んで表記する。
キーと値のペアを持たない波カッコの組({})は空のハッシュ。
ハッシュの波カッコは、ブロックの波カッコとはまったく別物であるという点
ハッシュは配列と似ていますが、1つの重要な違いとして、ハッシュでは要素の「並び順」が保証されないという点がある。要素の順序が重要である場合は、配列を使う必要がある。
とりあえずブロックとハッシュの波括弧は別物ということを認識
ハッシュの1要素を角カッコを使って定義する代わりに、次のようにキーと値をハッシュロケットと呼ばれる=> によってリテラル表現するほうが簡単らしい。
なぜ簡単なのか?
ハッシュロケット(=>)を使用することで、キーと値の関係が「キー => 値」と非常に明確に表現されるため、ハッシュの定義が直感的で理解しやすくなります。特に、キーに文字列や複雑な式を使用する場合に便利です。また、シンボル以外のキーも使用できるため、ハッシュの定義が柔軟になります。
>> user = { "first_name" => "Michael", "last_name" => "Hartl" }
=> {"last_name"=>"Hartl", "first_name"=>"Michael"}
なるほど、そう思うと簡単ですね。
さらにRailsならではの独自文化があるとのこと。
ここまではハッシュのキーとして文字列を使っていましたが、Railsでは文字列よりもシンボルを使う方が普通です。シンボルは文字列と似ていますが、クォートで囲む代わりにコロンが前に置かれている点が異なります。例えば:nameはシンボルです。もちろん、余計なことを一切考えずに、シンボルを単なる文字列とみなしても構いません
>> "name".split('')
=> ["n", "a", "m", "e"]
>> :name.split('')
undefined method `split' for :name:Symbol (NoMethodError)
>> "foobar".reverse
=> "raboof"
>> :foobar.reverse
undefined method `reverse' for :foobar:Symbol (NoMethodError)
つまり{}にあったハッシュは文字列に置き換えることができる。
慣れておけってことですね。
そして文字列(name)はシンボルの1つとのこと。
なんかよくわからなかったのでchatGPTに聞いてみた。
**文字列(String)**は、可変的なテキストです。文字列はメモリ上に何度も異なるコピーが存在することがあり、文字列の内容を変更することができます。
**シンボル(Symbol)**は、不変的な識別子として使われます。同じシンボルはプログラム全体でただ一つのインスタンスしか存在せず、そのため比較が非常に高速です。シンボルは通常、識別子やキーとして使用されますが、文字列のような操作(分割や逆順など)はできません。
Rubyでは、他にも多くのデータ型(Integer, Float, Array, Hash, Booleanなど)があり、これらも一種のシンボルとして扱われることがあります。ただし、Symbol という型が特に意味するのは、プログラムのキーとして使われる固定的なテキスト(識別子)です。
String型とSymbol型の違いを説明している。stringの時は可変的だが
Symbolになったらキーとして認識されるので文字を動かすことができるにエラーが起きていると解釈
4.4.2クラスの継承
Rubyではクラスの機能(メソッドなど)を受け継いで別のクラスを作ることができ、これを「継承」と呼ぶ。
Rubyでは、このような継承階層がすべてのオブジェクトにおいて成り立つ。
あらゆるオブジェクトはクラスから生成され、そのクラスの継承階層を上に辿っていくと、 必ずBasicObjectクラスに辿り着く。
演習
"racecar" の文字列の長さはいくつですか? lengthメソッドを使って調べてみてください。
>> "racecar".length
=> 7
reverseメソッドを使って、"racecar"の文字列を逆から読むとどうなるか調べてみてください。
>> "racecar".reverse
=> "racecar"
変数sに "racecar" を代入してください。その後、比較演算子(==)を使って変数sとs.reverseの値が同じであるかどうか、調べてみてください。
>> s = "racecar"
=> "racecar"
>> s == s.reverse
=> true
リスト 4.8を実行すると、どんな結果になるでしょうか? 変数sに "onomatopoeia" という文字列を代入するとどうなるでしょうか?(ヒント: 上矢印、またはCtrl-Pコマンドを使って以前に使ったコマンドを再利用すれば、コマンドを全部入力せずに済むので便利です。)
いずれもnil
リスト 4.9の(コードを書き込む)の部分を適切なコードに置き換え、回文かどうかをチェックするメソッドを定義してみてください。(ヒント: リスト 4.8の比較方法を参考にしてください。)
>> def palindrome_tester(s)
>> if s.reverse
>> puts "It's a palindrome!"
>> else
>> puts "It's not a palindrome."
>> end
>> end
上で定義したメソッドを使って “racecar” と “onomatopoeia” が回文かどうかを確かめてみてください。1つ目は回文である、2つ目は回文でない、という結果になれば成功です。
>> palindrome_tester("racecar")
It's a palindrome!
=> nil
>> palindrome_tester("onomatopoeia")
It's not a palindrome.
=> nil
文字列「A man, a plan, a canal, Panama」を ", " で分割して配列にし、変数aに代入してみてください。
>> a = "A man, a plan, a canal, Panama".split(", ")
=> ["A man", "a plan", "a canal", "Panama"]
今度は、変数aの要素を連結した結果 (文字列) を、変数sに代入してみてください。
>> s = a.join
=> "A mana plana canalPanama"
変数sを半角スペースで分割した後、もう一度連結して文字列にしてください。(ヒント: メソッドチェーンを使うと1行でもできます。)リスト 4.9で使った回文をチェックするメソッドを使って、(現状ではまだ)変数sが回文ではないことを確認してください。downcaseメソッドを使って、s.downcaseは回文であることを確認してください。
>> s = s.split.join
=> "AmanaplanacanalPanama"
>> palindrome_tester(s)
It's not a palindrome.
=> nil
>> palindrome_tester(s.downcase)
It's a palindrome!
=> nil
aからzまでの範囲オブジェクトを作成し、7番目の要素を取り出してみてください。同様にして、後ろから7番目の要素を取り出してみてください。(ヒント: 範囲オブジェクトを配列に変換するのを忘れないでください。)
>> a = ('a'..'z').to_a
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u","v", "w", "x", "y", "z"]
>> a[6]
=> "g"
>> a[-7]
=> "t"
本章のまとめ(引用)
・Rubyは文字列を扱うためのメソッドを多数持っている
・Rubyの世界では、すべてがオブジェクトである
・Rubyではdefというキーワードを使ってメソッドを定義する
・Rubyではclassというキーワードを使ってクラスを定義する
・Railsのビューでは、静的HTMLの他にERB(埋め込みRuby: Embedded RuBy)も使える
・Rubyの組み込みクラスには配列、範囲、ハッシュなどがある
・Rubyのブロックは、他の似た機能と比べると柔軟で、添え字を使ったデータ構造よりも自然にイテレーションができる
・シンボルとはラベルである。追加的な構造を持たない(代入などができない)文字列みたいなもの
・Rubyではクラスを継承できる
・Rubyでは組み込みクラスですら内部を見たり修正したりできる
・「deified」という単語は回文である
感想
端折ったところもあるが、大体コードのリーディングする際に疑問に思っていたことは解決できた。
文法の読み方に慣れないといけないなと思うところもあるし、読みつづけて
経験を積まなければいけないという点も理解できた。
定期的にこの第4章は振り返りをしなければいけないと戒めももちつつ習得していきたい。
以上、めろんぱんでした。