Ruby on Rails tutorialを通してのメモ (第4章)
前回まで
- application.html.erbにRubyのコードを挿入し、ページのタイトルが実際にアクセスしたページのタイトルになるように少し動的なページを作成することができました。
- 今回から4章に入ります。Rubyのコードについて学んで行きましょう。
4章
@ 4.1 動機
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
- Railsのviewでは膨大な数の組み込み関数が使え、新しい関数を作成することができます。
<%= yield(:title) %> | Ruby on Rails Tutorial Sample App
- こちらではページタイトルの定義に依存しています。
<% 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>
- このようにviewでprovideが使われています。
- タイトルが与えていなかった場合に、タイトルが空欄になります。
- 全てのページで異なるタイトルに変更できるようにオプションを与える必要があります。
- このviewからprovideを削除すると
| Ruby on Rails Tutorial Sample App
- 余分な" | "が表示されてしまいます。
- ページタイトルが正しく表示されない場合に、full_titleというヘルパーを作成します。
- このヘルパーはページタイトルが定義されていない場合は基本タイトル「Ruby on Rails Tutorial Sample App」を返し、定義されている場合は基本タイトルに" | "とページタイトルを追加して返すようにします。
リスト4.2: 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 page_title + " | " + base_title end end end
- このヘルパーを作成すると、
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
- このapplication.html.erbのレイアウトが、
<title><%= full_title(yield(:title)) %></title>
- このように端的に書くことができます。
リスト4.3: full_titleヘルパーを使ったWebサイトのレイアウト
app/views/layouts/application.html.erb
<!DOCTYPE html> <html> <head> <title><%= full_title(yield(:title)) %></title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> </body> </html>
- このヘルパーを定義することで、Homeページにこれまで表示されていた余分なHomeという単語を表示せず、基本タイトルのみを正しく表示することができます。
- これを行うために以前のテストコードを"Home"という文字が表示されないことを確認するように更新します。
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
- ここでテストスイートを実行し、テストが失敗することを確認します。
$ rails test 3 tests, 6 assertions, 1 failures, 0 errors, 0 skips
- テストが失敗したことが確認できたでしょうか
<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>
- 最初の行を削除した結果、テストはパスするはずです。
@ 4.2 文字列とメソッド
@ 4.2.1 コメント
@ 4.2.2 文字列
- オブジェクトは、 メッセージに応答する。
- オブジェクトに渡されるメッセージは一般的にメソッドと呼ばれる。
- メソッドの実体は、そのオブジェクト内で定義されたメソッドです。
- lengthメソッドは文字列の文字数を返す。"footbar"は6文字なので返り値は'6'になります。
>> "foobar".empty? => false >> "".empty? => true
- empty?メソッドは文字列が空なら(長さがゼロ)ならtrue,文字列が存在するときはfalseを返すメソッドです。
- Rubyではempty?のような疑問符があるメソッド(?)ようにtrue,またはfalseという論理値(boolean)を返すことを、末尾の疑問符で示す慣習があります。論理値(boolean)は、特に処理の流れを変更する時に有用です。
>> s = "foobar" >> if s.empty? >> "The string is empty" >> else >> "The string is nonempty" >> end => "The string is nonempty"
- こちらでは変数sに文字列"foobar"を代入して、if文で empty?メソッドにより文字列の有無で論理値を返すプログラムが書かれています。
>> if s.nil? >> "The variable is nil" >> elsif s.empty? >> "The string is empty" >> elsif s.include?("foo") >> "The string includes 'foo'" >> end => "The string includes 'foo'"
- 条件文を二つ以上含めたい場合は、elsif(else + if)を使います。
- 条件が一つの時(一つ前のプログラム)はelseによる条件は一つしか使っていませんでしたね?
>> 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
- 論理値はそれぞれ&&(and)や| |(or),!(not)で表すこともできます。
- nilがメソッドに対応する例は
>> nil.to_s => ""
- nilに対してメソッドを複数繋げてチェーン(chain)として渡せることを確認します。
- ↑の記事は有用だと思いました。😂
puts "x is not empty" if !x.empty?
- このコードはifが中盤に書かれています。これは、ifの後の条件式が真(true)の時のみ実行される式(後置if)になっています。
- 簡潔にコードを書くことができます。
- もし、falseを返したい時は、unlessをキーワードとして使えます。
>> string = "foobar" >> puts "The string '#{string}' is nonempty." unless string.empty? The string 'foobar' is nonempty. => nil
- Rubyのオブジェクトでは、オブジェクトの論理値がfalseになるのは、false自身とnilの二つです。
- !!を使用するとそのオブジェクトを2回否定するのでどのオブジェクトも論理値(true,false)に変換できます。
>> !!nil => false
>> !!0 => true
@ 4.2.4 メソッドの定義
- Railsコンソールでもhomeアクションや4.2で作成したヘルパーと同じ方法でメソッドを定義することができる。
- 引数を1つ取り、引数が空かどうかに基づいたメッセージを返すstring_messageというメソッドを定義してみる。
>> def string_message(str = '') >> if str.empty? >> "It's an empty string!" >> else >> "The string is nonempty." >> end >> end => :string_message >> puts string_message("foobar") The string is nonempty. >> puts string_message("") It's an empty string! >> puts string_message It's an empty string!
- 最後の「puts string_message」のようにメソッドの引数を省略することも可能です。 (引数にデフォルト値を含めているので)
def string_message(str = '')
- str変数に引数を渡すことも渡さないこともできる。渡さない場合は指定のデフォルト値が自動的に使われる。
- Rubyメソッドには「暗黙の戻り値がある」
- メソッド内で最後に評価された式の値が自動的に返される。
- 引数のstrがそらかどうかに応じて2つのメッセージ文字列のうちいずれかを返す。Rubyでは戻り値を明示的に指定することもできる。
>> def string_message(str = '') >> return "It's an empty string!" if str.empty? >> return "The string is nonempty." >> end
- このメソッドは先ほどのメソッドと同じ結果を返す。
- 2番目のreturnはなくとも良い。
- メソッド内の最後に置かれた式("The string is nonempty.")は、returnキーワードがなくても暗黙で値を返す。
- 両方にteturnを使う方が見た目の対称性が保たれる。
- メソッドで引数の変数名にどんな名前を使用しても、メソッドの呼び出し側には何の影響も生じない。
- 最初の例のstrを別の変数名(the_function_arugumentなど)に変更しても、メソッドの呼び出し方は全く同じ。
@ 4.2.5 titleヘルパー、再び
- full_titleヘルパーのコードを理解するための準備が整った。
- コメントを使用して各行に注釈を追加している。
リスト4.11: 注釈付きのtitle_helper.
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
- Webサイトのレイアウトで使うコンパクトなヘルパーメソッドでは、以下のような要素が投入される。
- メソッドの定義
- 変数割り当て
- 論理評価
- 制御フロー
- 文字列の式展開
- module ApplicationHelperについて
- モジュールは関連したメソッドをまとめる方法の一つ
- includeメソッドを使ってモジュールを読み込むことができる。(mixed inと呼ばれる)
- Railsでは自動的にヘルパーモジュールを読み込んでくれるため、include行を書く必要がない。
- full_titleメソッドは自動的にすべてのビューで利用できるようなっている。
@ 4.3 他のデータ構造
@ 4.3.1 配列と範囲演算子
- 配列(array)は、特定の順序を持つ要素のリストのこと。
- 配列を理解することはハッシュやRailsのデータモデル(関連付け、後述する。)を理解するための重要な基盤となる。
- splitメソッドを使用すると、文字列を自然に変換した(整数)配列を得ることができる。
>> "foo bar baz".split # 文字列を3つの要素を持つ配列に分割する
=> ["foo", "bar", "baz"]
- このsplitメソッドを使用することにより、三つの文字列からなる配列が返ってきた。
- デフォルトで空白が区切り文字として使われるが、次のように区切り文字を指定することもできる。
>> "fooxbarxbaz".split('x') => ["foo", "bar", "baz"]
- 配列なので、ゼロオリジンを採用している。 (配列は0から始まるがなぜか?↓結構難しい。配列は0から始まるものだ。と理解した方が一旦はよさそう。)
- 配列の最初の要素のインデックスが0から始まり、2番目は1...と続く。
>> a = [42, 8, 17] => [42, 8, 17] >> a[0] # Rubyでは角カッコで配列にアクセスする => 42 >> a[1] => 8 >> a[2] => 17 >> a[-1] # 配列の添字はマイナスにもなれる! => 17
- 配列の要素にアクセスするには角カッコを使う。Rubyではそれ以外のアクセス方法もある。
>> a # 配列「a」の内容を確認する => [42, 8, 17] >> a.first => 42 >> a.second => 8 >> a.last => 17 >> a.last == a[-1] # == を使って比較する => true
- 最後の行ではa.last(42)とa[-1](aという配列の後ろからマイナス1番目つまり最初の42)を「==」により比較している。因みに等しくないは「!=」という比較演算子で表現できる。
>> x = a.length # 配列も文字列と同様lengthメソッドに応答する => 3 >> x == 3 => true >> x == 1 => false >> x != 1 => true >> x >= 1 => true >> x < 1 => false
- 配列はlengthメソッド(文字列の長さを返すメソッド)以外にも対応している。
>> a => [42, 8, 17] >> a.empty? => false >> a.include?(42) => true >> a.sort => [8, 17, 42] >> a.reverse => [17, 8, 42] >> a.shuffle => [17, 42, 8] >> a => [42, 8, 17]
- 上の様々なメソッド を実行した場合にもaの値は変更されていない。
- 配列の内容を変更したい場合は、そのメソッドに対応する「破壊的」メソッドを使用する。つまり「!」を追加したものを使用する。
>> a => [42, 8, 17] >> a.sort! => [8, 17, 42] >> a => [8, 17, 42]
- 「!」を使用することにより配列の要素の順番が変わっていることが確認できる。
- pushメソッドまたは「 << 」演算子 を使用して配列に要素を追加できる。
>> 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"]
- 最後の例(a << "" << "")のように要素の追加をチェーン(chain)することができている。
- 他の多くの言語の配列とは異なり、Rubyでは異なる型が配列の中で共存できる。(整数と文字列)
- 文字列を整数に変換するとき、splitメソッドを使用した。joinメソッドはこれとは逆で区切りをなくした要素を作る。
>> a => [42, 8, 17, 6, 7, "foo", "bar"] >> a.join # 単純に連結する => "4281767foobar" >> a.join(', ') # カンマ+スペースを使って連結する => "42, 8, 17, 6, 7, foo, bar"
- to_aメソッドを使用してみる。
>> 0..9 => 0..9 >> 0..9.to_a # おっと、9に対してto_aを呼んでしまっていますね NoMethodError: undefined method `to_a' for 9:Fixnum >> (0..9).to_a # 丸カッコを使い、範囲オブジェクトに対してto_aを呼びましょう => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- 括弧が必要 らしい。
- [0...2]のような範囲は配列の要素を取り出すのに便利。
>> a = %w[foo bar baz quux] # %wを使って文字列の配列に変換 => ["foo", "bar", "baz", "quux"] >> a[0..2] => ["foo", "bar", "baz"]
- インデックスに-1という値を指定できる。配列の長さを知らなくても最後の用を指定でき、配列を特定の開始位置から最後の要素までを一度に選択できる。
>> a = (0..9).to_a => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >> a[2..(a.length-1)] # 明示的に配列の長さを使って選択 => [2, 3, 4, 5, 6, 7, 8, 9] >> a[2..-1] # 添字に-1を使って選択 => [2, 3, 4, 5, 6, 7, 8, 9]
@ 4.3.2 ブロック
- 配列と範囲( [ ] や... ) )はさまざまなメソッドに対して応答することができる。
>> (1..5).each { |i| puts 2 * i } 2 4 6 8 10 => 1..5
- このコードでは、範囲オブジェクトである(1..5)に対してeachメソッドを呼び出している。
- { |i| puts 2 * i }はブロックと呼ばれる。
- |i|は変数名が「 | 」に囲まれている。eachメソッドでは、iという変数を使用してブロックを操作できる。 範囲( ... )に含まれるそれぞれの値をこの変数( i )に代入してブロックを実行する。
- doとendを使用して示すことができる。(私はこちらの方が使用したことが多いです。😉)
>> (1..5).each do |number| ?> puts 2 * number >> puts '--' >> end 2 -- 4 -- 6 -- 8 -- 10 -- => 1..5
- each do の後の変数「 i 」の代わりに「 number 」を使用している。
- mapメソッドを使用したブロックの使用例↓,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"]
- 後半の2つの例では、mapのブロックで内で宣言した(char)に対してメソッドを呼び出している。
- 次のように書き方を省略することができる。( => (&:downcase) ) メソッドにシンボル( : )が使われている。
>> %w[A B C].map { |char| char.downcase } => ["a", "b", "c"] >> %w[A B C].map(&:downcase) => ["a", "b", "c"]
- ブロックの例として単体テストの場合↓
est "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Ruby on Rails Tutorial Sample App" end
- テストコードにdoが含まれている。テスト本体がブロックでできている。
- 文字列(説明文)とブロックを引数にテストが実行される時ブロック内の文が実行される。
('a'..'z').to_a.shuffle[0..7].join
- ↑のコードについて理解してみる。↓
>> ('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'..'z').to_a.shuffle # シャッフルする => ["c", "g", "l", "k", "h", "z", "s", "i", "n", "d", "y", "u", "t", "j", "q", "b", "r", "o", "f", "e", "w", "v", "m", "a", "x", "p"] >> ('a'..'z').to_a.shuffle[0..7] # 配列の冒頭8つの要素を取り出す => ["f", "w", "i", "a", "h", "p", "c", "x"] >> ('a'..'z').to_a.shuffle[0..7].join # 取り出した要素を結合して1つの文字列にする => "mznpybuj"
- 今更ですが結構分かりやすい説明で助かります。。🤔
@ 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"}
- ハッシュはキーと値をペアとして「 { } 」で囲む。
- キーと値のペアを持たない「 { } 」は空のハッシュ。
- 「 { } 」はブロックの「 { } 」とは別もの。
- ハッシュと配列の大きな違いは、並び順が保証されていないということ。順序を決める場合は配列を使う必要がある。
- ↓のようにハッシュロケットの表現方法がある。
>> user = { "first_name" => "Michael", "last_name" => "Hartl" } => {"last_name"=>"Hartl", "first_name"=>"Michael"}
>> "name".split('') => ["n", "a", "m", "e"] >> :name.split('') NoMethodError: undefined method `split' for :name:Symbol >> "foobar".reverse => "raboof" >> :foobar.reverse NoMethodError: undefined method `reverse' for :foobar:Symbol
- シンボルは、全ての文字が使えるわけでは無い。
>> :foo-bar
NameError: undefined local variable or method `bar' for main:Object
>> :2foo
SyntaxError
- ハッシュのキーとしてシンボルを採用する場合、userのハッシュは、↓のように定義できる。
>> user = { :name => "Michael Hartl", :email => "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} >> user[:name] # :name に対応する値にアクセスする => "Michael Hartl" >> user[:password] # 未定義のキーに対応する値にアクセスする => nil
- 最後の例で未定義のハッシュはnilになることがわかる。
- ハッシュではシンボルをキーとして使う。
>> h1 = { :name => "Michael Hartl", :email => "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} >> h2 = { name: "Michael Hartl", email: "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} >> h1 == h2 => true
- キーの名前の後にコロンを置き、その後に値が続くように置き換える。
{ name: "Michael Hartl", email: "michael@example.com" }
- jsなどの他の言語のハッシュ記法に近い。
{ :name => "Michael Hartl" }
- ↑のコードと
{ name: "Michael Hartl" }
- ↑のコードは同じ。
リスト4.13: ハッシュの中のハッシュ
>> params = {} # 'params' というハッシュを定義する ('parameters' の略)。 => {} >> 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"
- 配列や範囲オブジェクトと同様、ハッシュもeachメソッドに対応する。
- 配列のeachメソッドはブロックの変数は一つだけだが、ハッシュのeachメソッドでは、ブロックの変数はキーと値の二つになっている。( flash.each do |key, value| )
- ハッシュに対してeachメソッドを実行すると、ハッシュの一つの「キー、値」のペアの処理を繰り返す。
- inspectメソッド
- 要求されたオブジェクトを表現する文字列を返す。
>> puts (1..5).to_a # 配列を文字列として出力 1 2 3 4 5 >> puts (1..5).to_a.inspect # 配列のリテラルを出力 [1, 2, 3, 4, 5] >> puts :name, :name.inspect name :name >> puts "It worked!", "It worked!".inspect It worked! "It worked!"
- オブジェクトを表示するためにinspectを使うことがよくあるためpメソッド( 'puts :name.inspect' )というショートカットが使える。
>> p :name # 'puts :name.inspect' と同じ :name
@ 4.3.4 CSS、再び
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
- ↑のコードでは↓のメソッドを呼んでいる。
stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
- 「 ( ) 」がない。
- Rubyは「 ( ) 」を使用しなくても良い。つまり↓の二行は同じ。
# メソッド呼び出しの丸カッコは省略可能。 stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track': 'reload') stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
- media引数はハッシュだが、「 { } 」が無い。
- ハッシュがメソッド呼び出しの最後の引数である場合は省略できる。 ↓
# 最後の引数がハッシュの場合、波カッコは省略可能。 stylesheet_link_tag 'application', { media: 'all', 'data-turbolinks-track': 'reload' } stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload
- ↓のようなコードでも正常に実行できる。
stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload'
- 途中で改行が含まれているにも関わらず、正常に実行できるのは、Rubyは改行と空行を区別していないため。
- 行を分割したのはコードを読みやすくするため。
stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
- ↑のコードではstylesheet_link_tagメソッドを二つの引数で呼んでいる。
- 最初の引数の文字列( 'application','data-turbolinks-track' )はスタイルシートへのパスを示している。
- 次の引数であるハッシュは要素が二つある。
- 最初の要素がメディアタイプ(media:)
- 次の要素がturbolinksという機能をオンにしている。
- <%= %>で囲まれたコードを実行した結果がERbのテンプレートに挿入される。ブラウザ上でこのページのソースを表示すると、必要なスタイルシートが含まれていることを確認できる。
リスト 4.14: 読み込まれたCSSによって生成されたHTMLソース
<link data-turbolinks-track="true" href="/assets/application.css" media="all" rel="stylesheet" />
@ 4.4 Rubyにおけるクラス
- Rubyではあらゆるものがオブジェクトである。
- 実際にオブジェクトをいくつか定義してみる。
- Rubyはメソッドをまとめるのにクラスを使っている。
- これらのクラスからインスタンスが生成されオブジェクトが作成される。
- オブジェクト思考の具体例を示す。
@ 4.4.1 コンストラクタ
>> s = "foobar" # ダブルクォートは実は文字列のコンストラクタ => "foobar" >> s.class => String
- ↑では文字列がclassメソッドに応答している。その文字列が所属するクラスを返している。
- 明示的に名前付きコンストラクタを使うことができる。
- 名前付きコンストラクタはクラスに対してnewメソッドを呼び出している。
>> s = String.new("foobar") # 文字列の名前付きコンストラクタ => "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] # 存在しないキー (:foo) の値にアクセスしてみる => nil >> h = Hash.new(0) # 存在しないキーのデフォルト値をnilから0にする => {} >> h[:foo] => 0
- メソッドがクラス自身(new)の場合はこのメソッドをクラスメソッドと呼ぶ。
- クラスのnewメソッドを呼び出した結果はそのクラスのオブジェクトであり、クラスのインスタンスとも呼ばれる。
- lengthのようにインスタンス(array.length)に対して呼び出すメソッドはインスタンスメソッドと呼ぶ。
@ 4.4.2 クラス継承
- superclassメソッドを使うとクラス階層がわかり、クラスについて分かりやすくなる。
>> s = String.new("foobar") => "foobar" >> s.class # 変数sのクラスを調べる => String >> s.class.superclass # Stringクラスの親クラスを調べる => Object >> s.class.superclass.superclass # Ruby 1.9からBasicObjectが導入 => BasicObject >> s.class.superclass.superclass.superclass => nil
- 図4.1のようにStringクラスのスーパークラスはobjectクラスで、objectクラスのスーパークラスはBasicobjectだが、このクラスはスーパークラスを持っていない。
- Rubyのクラスは最終的にスーパークラスを持たないBasicobjectクラスを継承している。
- クラス継承の仕組みがあることから、Rubyはあらゆるものがオブジェクトである。
- クラスについての理解を深めるために、自分でクラスを作成してみる。
- Wordクラスを作成する。
- 単語を前後ろどちらから読んでも同じならばtrueを返すpalindrome?(回文)メソッド を作成してみる。
>> class Word >> def palindrome?(string) >> string == string.reverse >> end >> end => :palindrome?
- このクラスとメソッド は ↓のように使うことができる。
>> w = Word.new # Wordオブジェクトを作成する => #<Word:0x22d0b20> >> w.palindrome?("foobar") => false >> w.palindrome?("level") => true
- 文字列「w.palindrome?("文字列")」を引数にとるメソッド「palindrome」を作るために新しいクラスを使っている。(本来ならば ↓ のようにWordクラスはStringクラスを継承する)
リスト4.15:コンソールでWordクラスを定義する
>> class Word < String # WordクラスはStringクラスを継承する >> # 文字列が回文であればtrueを返す >> def palindrome? >> self == self.reverse # selfは文字列自身を表します >> end >> end => :palindrome?
- ↑のコードは継承のためのRubyのword < String 記法。
- 新しいpalindrome?メソッドだけではなく、Stringクラスが扱える全てのメソッドがWordクラスで使えるようになる。
>> s = Word.new("level") # 新しいWordを作成し、"level" で初期化する => "level" >> s.palindrome? # Wordが回文かどうかを調べるメソッド => true >> s.length # WordはStringで扱える全てのメソッドを継承している => 5
- wordクラスはStringクラウを継承しているためクラス階層を確認できる。
>> s.class => Word >> s.class.superclass => String >> s.class.superclass.superclass => Object
- Rubyではselfキーワードを使ってクラスの中から自分自身が持つ単語にアクセスすることができる。
- Wordクラスの中では、selfはオブジェクト自身を指す。
self == self.reverse
- ↑のコードを使い、単語が回文であるかを確認できる。
- Stringクラス内部ではメソッドや属性を呼び出すときのself.も省略可能。
self == reverse
@ 4.4.3 組み込みクラスの変更
- 仮に継承を使わずpalindrome?メソッドをStringクラス自身に追加して(Stringクラスを拡張して)使う方法があればWordクラスを作らなくてもよい。
>> "level".palindrome? NoMethodError: undefined method `palindrome?' for "level":String
- Rubyでは組み込みの基本クラスの拡張が可能。
- Rubyのクラスはオープンで変更可能(誰でも自由に変更可能)
- つまり、クラス設計者でない開発者でもこれらのクラスにメソッドを自由に追加することができる。
>> class String >> # 文字列が回文であればtrueを返す >> def palindrome? >> self == self.reverse >> end >> end => :String >> "deified".palindrome? => true
>> "".blank? => true >> " ".empty? => false >> " ".blank? => true >> nil.blank? => true
@ 4.4.4 コントローラクラス
- StaticPagesコントローラで継承やクラスについて触れていた。
class StaticPagesController < ApplicationController def home end def help end def about end end
- StaticPagesControllerはApplicationControllerを継承していて、homeやhelp,aboutメソッドを定義している部分などについて説明できるようになった。。
- Railsコンソールは、セッションごとにローカルのRails環境を読み込む。
- コンソール内で明示的にコントローラを作成したり、そのクラス階層を調べたりすることができる。
>> controller = StaticPagesController.new => #<StaticPagesController:0x22855d0> >> 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
- Railsコンソールでは、その中からコントローラのアクション(メソッド)を呼ぶこともできる。
>> controller.home => nil
- Railsのアクションには戻り値がない。
- homeアクションはWebページを表示するためのもの。値を返すものではない。
- 第3章で一度もStaticPagesControlelr.newを実行していなかった。
- RailsはRubyで書かれているがRubyとは別物。
- Railsクラスは普通のRubyオブジェクトと同様に振舞うが、多くのクラスにはRails独自の仕様(魔法?🙄)担っているため分けて学習する必要がある。
@ 4.4.5 ユーザークラス
- 最後に、Userクラスを最初から作成してみる。
- アプリケーションのルートディレクトににexample_user.rbファイルを作成し、そこにリスト4.17のように書く。
リスト4.17: example_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
- ユーザ名とメールアドレス(属性attribute)に対応するaccessorをそれぞれ作成する。
- accessorを作成すると↓二つが定義される。
- データを取り出すメソッド(getter)
- データを代入するメソッド(setter)
- この行を実行し、インスタンス変数@nameと@email にアクセスするためのメソッドが用意される。
- Railsでは、インスタンス変数をコントローラ内で宣言するだけでビューで使えるようになる。
- 一般的にはそのクラス内であればどこからでもアクセスできる変数として使われる。
- インスタンス変数は常に@記号で始まり、未定義ならnilになる。
- 次の行のinitializeは、Rubyのメソッド
- User.newを実行すると自動的に呼び出される。
- この場合はattributesという引数を一つ取る。
def initialize(attributes = {}) @name = attributes[:name] @email = attributes[:email] end
- ↑のコードではattributes変数は空のハッシュデフォルトの値として持つ。
- 名前やメールアドレスのないユーザをinitializeメソッドにより最初に作ることができる。
- 最後にformatted_emailメソッドは、文字列の式展開を利用し@nameと@emailに割り当てられた値をユーザーのメールアドレスとして構成する。
def formatted_email "#{@name} <#{@email}>" end
>> require './example_user' # example_userのコードを読み込む方法 => true >> example = User.new => #<User:0x224ceec @email=nil, @name=nil> >> example.name # attributes[:name]は存在しないのでnil => nil >> example.name = "Example User" # 名前を代入する => "Example User" >> example.email = "user@example.com" # メールアドレスを代入する => "user@example.com" >> example.formatted_email => "Example User <user@example.com>"
- requireのパスの'./example_user'の'.'は現在作業しているディレクトリ(カレントディレクトリ) という意味を示す。
- 次のコードで空のexmaple_userを作成する。(example = User.new)
- 次に対応する属性にそれぞれ手動で値を代入すると名前とメールアドレスを与えることができる。(attr_accessorを使っているため =>attr_accessor :name, :email )
example.name = "Example User"
- @name変数に"Example User"とemail属性にも値を設定している。値はformatted_emailメソッドで使われる。
- 最後のハッシュ引数の{}を省略すると同様にinitializeメソッドにハッシュを渡すことで属性が定義済みの他のユーザを作成することができる。
> user = User.new(name: "Michael Hartl", email: "mhartl@example.com") => #<User:0x225167c @email="mhartl@example.com", @name="Michael Hartl"> >> user.formatted_email => "Michael Hartl <mhartl@example.com>"
@ 4.5 最後に
- 不要ファイルの削除..
$ rm example_user.rb
- 「deified」という単語は回文である🧐
- かなり長文でかつ文章の統一感がなく、申し訳ないです。数日間に分けて実施しました。
- 結構自分自身も文章の理解に苦しみました。
- この章はRubyの基本構文の話になるので、新しい発見も多く、内容が濃い印象でした。
- 次からやっとコーディングです!!!!🤗
Ruby on Rails tutorialを通してのメモ (第3章その3)
前回まで
- 前回はテストコードを書きながらAboutページを作成しました。
- 今回から動的なページを作成していきます。
作業開始
@ 3.4 少しだけ動的なページ
- ページのタイトルを自ら書き換えて表示するようにする。
- 本格的な動的ページは7章で開始する。
- Homeページ、Helpページ、Aboutページをそれぞれ編集し、最終的にページごとに異なるタイトルを表示する。
- ここではviewの<title>タグの内容を変更する。
- 多くのブラウザではtitleタグの内容をブラウザウィンドウの上部にタイトルタグを表示している。
- 「RED,GREEN,REFACTOR」のサイクルを全て行う。
- ページのタイトルの簡単なテストを書く。(RED)
- 3つのページにタイトルを追加する。(GREEN)
- レイアウトファイルを活用してコードの重複を解決する。(REFACOTR)
- 3つの静的ページのタイトルを「<ページ名> | Ruby on Rails Tutorial Sample App」 という形式に変更する。<ページ名>が表示しているページに応じて動的に変わる。
- レイアウトファイルは$ rails new コマンドでデフォルトで作成されている。レイアウトファイルの役割を知るために、一時的にファイル名を変更する。コマンドやエディタでファイル名を変更する。
$ mv app/views/layouts/application.html.erb layout_file
@ 3.4.1 タイトルをテストする (Red)
- HTMLについてのおさらいをまず行う。
リスト3.23:Webページの典型的なHTML構造
<!DOCTYPE html> <html> <head> <title>Greeting</title> </head> <body> <p>Hello, world!</p> </body> </html>
- リスト3.23の構造には3つの要素が含まれている。
- "<!DOCTYPE html>" → document type → 使用するHTMLのバージョンをブラウザに宣言している。
- "<head>" → headセクション,<head>タグに囲まれたコード → <title>タグに囲まれた"Getting"という文字
- bodyセクション → 「Hello, wold!」という文字列がpタグ内にある。
- HTMLはスペースやタブが無視される。インデント(字下げ)は揃っていなくても問題ない。が、揃えた方がみやすい。😀
- Home,Help,Aboutページのタイトルについてテストをコードを書く。
- assert_selectメソッドを使用する。このメソッドは、特定のHTMLタグがソンンザイするかどうかをテストする。(別名セレクタと呼ばれる。)
assert_select "title", "Home | Ruby on Rails Tutorial Sample App"
- このセレクタは<title>タグ内に「Home | Ruby on Rails Tutorial Sample App」という文字列があるかをチェックする。
リスト3.24: StaticPagesコントローラのタイトルをテストする(RED)
test/controllers/static_pages_controller_test.rb
assert_select "title", "Home | Ruby on Rails Tutorial Sample App"
assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
assert_select "title", "About | Ruby on Rails Tutorial Sample App"
@ 3.4.2 タイトルを追加する (Green)
- 各ページにタイトルタグ、タイトルを追加して先ほどのテストがパスするようにする。↓のコードをtutolialに習い、修正する。
リスト3.26: 完全なHTML構造を備えたHomeページのview(RED)
app/views/static_pages/home.html.erb
リスト3.27: 完全なHTML構造を備えたHelpページのview(RED)
app/views/static_pages/help.html.erb
リスト3.28: 完全なHTML構造を備えたAboutページのview(RED)
app/views/static_pages/about.html.erb
- GREENになっているか、確認してみる。
リスト3.29: GREEN
$ rails test 3 runs, 6 assertions, 0 failures, 0 errors, 0 skips
- 私の場合は、tutolialでは テスト結果が3tests,となっているところが3runsとなっていましたが、調べた結果フラグの有無で違うようです。
- titleタグを使用することにより、ブラウザのタブにタイトルがついたことが確認できたでしょうか。
@ 3.4.3 レイアウトと埋め込みRuby (Refactor)
- Home,Help,Aboutページはほとんど同じコードで作成してきた。
- DRYに反するため繰り返しコードを使用しないようにコードを作成する。
- viewで「埋め込みRuby」を使う。Railsのprovideメソッドを使ってタイトルをページごとに変更する。
リスト3.31: タイトルにERBを使ったHomeページのビューGREEN
app/views/static_pages/home.html.erb
<% provide(:title, "Home") %>
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
- ↑は、ERBと呼ばれるWebページに動的な要素を加える時に使うテンプレートシステムのことをいう。
- 拡張子がhome.html.erbとなっているerbファイルのため、HTMLのコード内に、Rubyのコードを書くことができる。
- リスト3.31の解説↓
<% provide(:title, "Home") %>
- <% ~ %>で囲まれている中から、provideメソッドを呼び出している。引数は"Home"という文字列と:titleというラベルを関連付けている。
- このメソッドにより、テンプレートの対応する部分に実際のタイトルが挿入される。
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
- <%= ~ %> のように<% ~ %>内に、= を追加するとyieldメソッドの実行結果がテンプレートの中に挿入される。今回ならyield(:title)の実行結果はprovide(:title,"Home")のHomeになる。
リスト3.32:GREEN
$ rails test 3 tests, 6 assertions, 0 failures, 0 errors, 0 skips
<% provide(:title, "Help") %>
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
<% provide(:title, "About") %>
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
- HTMLの構造はHome,Help,Aboutがほぼ全てのページが一緒なので、ファイル名を書き換えていたapplication.html.erbを使用してDRYする。
- 名称変更:layout_file → application.html.erb
- デフォルトのタイトル(<title>SampleApp</title>)を書き換える。
リスト3.35: サンプルアプリケーションのレイアウト(GREEN)
app/views/layouts/application.html.erb
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
<body> <%= yield %> </body>
- <%= yield %> は各ページのレイアウトを挿入するもで、/static_pages/homeにアクセスするとhome.html.erbの内容がHTMLに変換され、<% yield %>の位置に挿入される。(という理解であれば問題ないです。)
- Railsのデフォルトのレイアウトでは、下記の行が存在する。
<%= csrf_meta_tags %> <%= stylesheet_link_tag ... %> <%= javascript_include_tag "application", ... %>
- このERBはcsrf_meta_tags,stylesheet,JavaScriptメソッドをページ内で展開するためのもの。
- <%= yield %>により、Home,Help,Aboutページはapplication.html.erbに呼び出されるため、重複する箇所があり余分な部分を削除する必要がある。
リスト3.36: HTML構造を削除したHomeページ(GREEN)
app/views/static_pages/home.html.erb
リスト3.37: HTML構造を削除したHelpページ(GREEN)
app/views/static_pages/help.html.erb
リスト3.36: HTML構造を削除したAboutページ(GREEN)
app/views/static_pages/about.html.erb
- 表示結果は重複部分がある前と変わらないが、コードが大きく削減され、リファクタリングすることができた。
- 再度、テストを実行してみる。
- 私はテストをしてみて"failures"が出ることがありました。コードの空行が抜けていた時に出たもので、コードとして動かないわけではないが、期待通りの結果出ない時に出るようです。テストコードがなければ気づけないケアレスミスを、気づくことができました。
@ 3.4.4 ルーティングの設定
- 現在の最初のページ(ルート"/"ページ)をapplication.html.erbにする。
- application_controller.rbにhelloアクションがあるので削除する。同様にルーティングにもルートがあるので削除する。(config/route.rb)
リスト3.41: HomeページをルートURLに設定する
config/routes.rb
root 'static_pages#home'
- このように、ルートパス("/")のルーティングを↓のような書き方にする。
root 'static_pages#home'
NCSも結構好きです。
Ruby on Rails tutorialを通してのメモ (第3章その2)
前回まで
- 静的なページのセットアップ、コントローラを生成し、homeページ、helpページにアクセスできるようになりました。
- 今回はエラーコードを書きながらAboutページを作成していきます。
作業開始
@ 3.2.2 静的なページの調整
- 最初の段階で静的なHTMLが存在していることを前回確認し、修正できることもわかりました。
- リスト3.11,リスト3.12をtutolialに合わせて修正しましょう。(こちらでは省略します。)
リスト3.11: HomeページのHTMLを修正する
app/views/static_pages/home.html.erb
リスト3.12: HelpページのHTMLを修正する
app/views/static_pages/help.html.erb
- Homeページ、Helpページ共に修正されたでしょうか。ブラウザで確認してみましょう。
@ 3.3 テストから始める
- Homeページ、Helpページを作成した後、Aboutページを作成します。
- Aboutページを作成する際に自動化テストを作成し、機能が正しいかを確認します。
- テストコードはバグを追う時間が減るため開発速度アップにつながる。
$ ls 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 end test "should get help" do get static_pages_help_url assert_response :success end end
- test do ~ end で囲まれたテストが二つ描かれている。
- この二つのテストは、HomeとHelpのアクションに対応として生成されている。
- テストの内容はまず、"get ~ _url" と書いてあり、それぞれアクションをGETした後正常化を確認する。この"get"とは、HomeページやHelpページが「getリクエストを受け付ける」Webページであることを示す。
- この確認は「アサーション」と呼ばれる手法で行う。
- テスト内容の二つ目に、"assert_responce:success"と書いてある。リクエストはsuccessだ。と書いてある。
- テスト内容は「Homeページのテスト。GETリクエストをhomeアクションに対して発行せよ。その後リクエストに対するレスポンスはsuccessのはず。」という内容。(tutolialそのままだが、、)
- 現在のテストスイートを確認してみる。リンクを張ったがテストスイートとは複数のテストケースをまとめたものだそうだ。
リスト3.14:GREEN
$ rails test
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
- どうやらfailures,errorsあたりが0なので正常みたいです。
- $ rails test を実行してみましたが、実行にはある程度の時間がかかるようです。その理由が↓の二つのようです。
@ 3.3.2 Red
- テスト駆動開発のサイクルは、
- 失敗するテストを最初に書く
- アプリケーションコードを書いて成功させいる。
- 必要ならリファクタリング(修正)する。
- テストの成功はGREEN,失敗をRED,リファクタリングはREFACTORとする。またこの三つをサイクルと呼ぶことがある。
- ここで、サイクルの一つ目としてAboutページ用の失敗するテストを書く。
- サイクルの最初としてAboutページ用の失敗するテストを書く。
- HomeやHelpのテストコードに習ってAboutページのテストコードを書いてみる。
リスト3.15: Aboutページのテスト RED
test/controllers/static_pages_controller_test.rb
test "should get about" do get static_pages_about_url assert_response :success end
- このまま実行すると、期待としては、Aboutに対応するアクションが存在しないためエラーが出るはずです。つまり↓のように失敗したら期待通りです。
リスト3.16:RED
$ rails test
3 tests, 2 assertions, 0 failures, 1 errors, 0 skips
- テストが失敗したので、次の段階としては、テストのエラーメッセージを頼りにテストをGREENにさせるようなコードを書き、Aboutページを実装します。
- エラーメッセージの確認をします。
リスト3.17:RED
$ rails test
NameError: undefined local variable or method `static_pages_about_url'
- 同じ内容のエラーメッセージが見つかったでしょうか?
- エラーメッセージを読んでみると「undefinded ,'static_pages_about_url'」なので 「AboutページのURLが見つからない」と言われているようです。
- まずはHomeやHelpページを作成した際に行ったように、ルーティングを修正します。
リスト3.18: about用のルートの追加をする。
config/routes.rb
get 'static_pages/about'
- homeやhelpのルーティングを真似てaboutのルートを追加すればできるはず。
- GETリクエストが来た時、StaticPageコントローラのaboutアクションに渡す処理をRailsが指示する。結果static_pages_about_urlというヘルパーが使えるようになる。 ヘルパーとは、今回のようにstatic_pages_about_urlをメソッドとして使えるようにすることでわざわざURLを指定しなくても良くなるといいたRailsの機能のことをいう。
- ルーティングを編集しただけなので、コントローラを修正しなければまだREDのままのはずです。そのためもう一度テストスイートを実行してみる。
リスト3.19:RED
$ rails test AbstractController::ActionNotFound: The action 'about' could not be found for StaticPagesController
- 同じようなエラーメッセージが出たでしょうか。前回はURLについてのエラーでしたが、今回はControllerについてエラーが出ていることが確認できるはずです。
- そのためコントローラにaboutアクションを追加しましょう。
def about end
- home,helpアクションに習ってaboutアクションを追加できたでしょうか。
- それではテストをしてみましょう。
$ rails test ActionController::UnknownFormat: StaticPagesController#about is missing a template for this request format and variant.
- 今更ですが、$ rails test は $ rails t と省略して実行できます。何回も打っていて楽に実行したいと思った方はすでにそうしていたでしょうか。
- エラー内容は、"missing template"と書いてあります。このエラーは、viewファイルがファイル名が間違っている時や存在しない時によく見かけるエラーです。今回はviewファイルが未作成なので作成しましょう。
- app/views/static_pagesディレクトリにabout.html.erbファイルを作りましょう。テキストエディタやFinder,tutolialではコマンドで作っています。私はテキストエディタなのでコマンドでは作成しませんが。😆
- テキストファイルabout.erbを作成したら、内容をリスト3.21の内容に修正します。ここでは省略します。
リスト3.21: Aboutページのコード
app/views_static_pages/about.html.erb
- 次こそはエラーが出なくなっているはずです。
リスト3.22:GREEN
$ rails test 3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
- 私もエラーが出なかったです。おお!と少し驚きました。エラーが解消されると嬉しいですね。🤗
- ブラウザでも確認してみましょう。URLは/static_pages_aboutです。 $ rails s でサーバを起動させて確認してみましょう。
@ 3.3.4 Refactor
- Refactorに関しては3.4.3から始めるそうです。
ZeddのRemixがかなりうまくハマっている。革命や。
Ruby on Rails tutorialを通してのメモ (第3章)
前回まで
- 主に投稿機能を実装しました。
作業開始
point
- 今回から3章です。静的なページを作成するようです。
- 静的なページ例としてはWikipedia
- 動的なページ例としてはTwitter,Facebookでしょうか。
- こちらは静的なページ?動的なページ?の参考になれば。
@ 3.1 セットアップ
リスト3.1 サンプルアプリケーションの生成
$ cd ~/environment $ rails _5.1.6_ new sample_app $ cd sample_app/
- Gemfileをリスト3.2に習いながら編集します。
- 編集したら、$ bundle install を実行してGemfileで指定したgemをインストールします。 ↓のオプションはproduction環境(開発環境)でしか使わないgemはインストールしないようにする設定のようです。
$ bundle install --without production
You have requested:
minitest = 5.10.3
The bundle currently has minitest locked at 5.11.3.
Try running `bundle update minitest`
If you are updating multiple gems in your Gemfile at once,
try passing them all to `bundle update`
//
インストールしようとしたminitestのバージョンがGemfileに書いてあるgemより古いようです。(currently has minitest locked at 5.11.3)
なのでbundle updateを指示されていますので、 $ bundle update を実行します。
render html: "hello, world!"
root 'application#hello'
- リスト3.4とリスト3.5は過去に行ったhello world!をデフォルトページで表示させるプログラムです。
- 確認の意味で、$ rails s ($ rails serverの省略形)を実行してもいいかもしれません。hello, world!が表示されたでしょうか。
@ 3.2 静的ページ
- 3.1でセットアップが完了しました。今後の手順としては、
- まずRailsのアクションやビューを使用して静的なHTMLのみのページを作成
- 静的なページを動的なページに作り変える。
リスト3.7: StaticPagesコントローラ内のhomeアクションとhelpアクションで使うルーティング
config/routes.rb
get 'static_pages/home' get 'static_pages/help'
- ルーティングにこちら二つが追加されていることが確認できたでしょうか。
- /static_pages/homeのURLにリクエスト(リクエストとはHTTPリクエストのgetのこと)をするとStaticPagesコントローラのhomeアクションと結びつけている。
- 実際にhttp://localhost:3000/static_pages/home にアクセスして確認してみましょう。私はローカルなのでlocalhostにアクセスしています。
リスト3.8: リスト3.6のrails gで生成されるStaticPagesコントローラ
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
- classのStaticPagesControllerはメソッド(アクションにあたるdefに囲まれたhomeやhelpのこと)をまとめている。ApplicationControllerを継承しています。
- 純粋なRubyはメソッドは実行しない。今回のようにRailsでApplicationControllerクラスを継承しているためStaticPagesControllerのメソッド(home,help)はRails特有の振る舞いをする。↓
- /static_pages/homeのURLにアクセス
- StaticPagesControllerを参照
- homeアクションのコードを実行
- homeアクションに対応するviewファイルを出力する。(見た目の部分,HTMLファイルの出力)今回はhomeアクションが空なので↓のようなページが表示されているはず。
StaticPages#home
Find me in app/views/static_pages/home.html.erb
- そこで、viewはどのように出力されるか。どのviewが表示されるか。
- viewファイルはアクション名に対応します。
- 今確認したいのは、MVCあたるVの部分で、app/のviewsに対応するファイルがあります。ファイル名は、アクション名と同じで、home,helpがあるはずです。
リスト 3.9: Homeページのview
app/views/static_pages/home.html.erb
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
リスト3.10: Helpページ用に生成されたview
app/views/static_pages_help.html.erb
<h1>StaticPages#help</h1> <p>Find me in app/views/static_pages/help.html.erb</p>
- つまり、これらのファイルを編集すれば見た目にあたるviewを修正できそうです。
Ruby on Rails tutorialを通してのメモ (第2章後半)
前回まで
- 前回まではscaffoldを使用して簡単なユーザ作成画面を表示させることができました。
作業開始
@ 2.2.2 MVCの挙動
point
- ここでは、MVCのモデルについて詳しく説明しています。
- ポイントとしては、URLを見ながら今の画面がどこか、対応する画面になぜ遷移できるかを気にすることだと思います。私も考えるようになったのはアプリケーションを数回作成した時です。🤔今は図2.11の説明を読んで見て「こういうものなんだな」と概要を把握してもらえばokだと思います。
@ 2.2.3 Usersリソースの欠点
- scaffoldについての問題点を提示しています。以下の通りです。
- データの検証が行われない。( ユーザ名が空欄,メールアドレスが"@"がないなどの場合でも登録できてしまう。)
- ユーザー認証が行われない。(ログイン、ログアウト機能がない)
- 必要なテストコード が書かれていない。(テストコードはこれを機会に覚えておきたい。実は私もまだ習得していません。🙏)
- レイアウトが整っていない。
- コードの内容が複雑。
@ 2.3 Micropostsリソース
point
- MicropostsもUserの時と同様、scaffoldでモデルを生成します。(ここで一度Userモデルの生成方法を見直すといいかもしれません。)
- この章ではUserリソースとMicropostsリソースの違いについて理解することが目的のようです。
point
- rails generate scaffoldコマンドをオプションをつけて実装しています。
- 「2.2Userリソース」と見比べながら進めていきます。
$ rails generate scaffold Micropost content:text user_id:integer
- contentはtext型に、user_idはinteger(int)型に指定しています。確かidは自動で追加されたはずでしたね。
- $ rails generate + $ rails db:migrate rails generate した後はマイグレートをします。Userの時にも行いました。
$ rails db:migrate
- routes.rbにMicropostsのルーティングが追加されました。
config/routes.rb
resources :microposts
確認できましたでしょうか?自動で追加、更新されるのですね。
- resource は自動でコントローラにアクションを生成してくれます。microposts_controller.rbを確認するとわかります。これは、users_controller.rbも同様です。(コントローラに生成されたファイルは全部で7種類であることも確認しましょう。→ index,show,new,create,edit,update,destroy)
- 実際にURLの/micropostsにアクセスして見ましょう。私の場合は「localhost:3000/microposts」にアクセスしました。
- new micropostsをクリックし、 content にはテキストが入力できるテキストボックスが、Userには数字が選択できるようになっていることが確認できたでしょうか。前回のUserリソースの時はメールアドレスを作成できましたが、今回は簡単にテキストを投稿することができました。実際にはscaffoldコマンドの引数のオプションを少し変更しただけで、ほとんど違いがありません。
point
- テキスト入力欄(content)は現在、文字数制限がありません。ツイッターも文字数が限られていると同様、また、「マイクロポスト」にも文字数制限をかけます。
- 制限を加える時には、バリデーションを使用します。
リスト2.13
app/models/micropost.rb
validates :content, length: { maximum: 140 }
- validates , contentに対して、length: {maximum: 140}なので文字数を140文字に制限しているように読み取れます。🤔
- 実際にcontentの欄に140文字以上文字を入力するとtutolialのようなエラーが出ました。何事も確認が大切です。逆にすんなりと投稿できてしまった場合はvalidationを記載したファイルに誤字脱字がないか確認、または本当に140文字なのかを確認する必要があります。
@ 2.3.3 ユーザーはたくさん
マイクロポストを持っている
point
- 一人のユーザは、複数のマイクロポスト、つまり1ユーザは、複数投稿することができます。ツイッターも作成したアカウントは複数呟けるのでそれと同じことを行います。
- UserモデルとMicropostモデルをある設定(関連付け,別名アソシエーション)することにより1ユーザが複数投稿できるように表現できます。
リスト2.14 - 1ユーザは複数のマイクロポストを持つ。
app/models/user.rb
has_many :microposts
- このように、複数モデルを持つ場合は、持ち主は「has_many」を設定します。
リスト2.15 - 1マイクロポストは1ユーザに属する。
app/models/micropost.rb
belongs_to :user
- 逆に所属する側は「belongs_to」を設定します。
@ 2.3.4 継承の階層
point
- Toyアプリケーションで使用しているRailsコントローラとモデルのクラス階層...正直概念の説明は、「そういうもだ」と覚えるので納得いかないことがある場合時は先に進めてあとで見返してみるがいいと思います。私も概念の説明は完璧ではありません。
リスト2.18 - Userクラスの継承
app/models/user.rb
class User < ApplicationRecord
リスト2.19 - Micropostクラスに置ける継承
app/models/micropost.rb
class Micropost < ApplicationRecord
- モデルはどちらもApplicationRecordというクラスを継承しています。なぜか?<が継承と呼ばれるものなのです。
- ApplicationRecordはさらに、ActiveRecord: :Base というクラスを継承しています。ややこしいです。。
- このようにクラスを継承することでモデルはデータベースにアクセスできたり、Rubyの属性のような書き方ができるようになります!
- コントローラも同様にクラスを継承しています。Railsはクラスを継承して機能を実装していることがわかりました。
@ 2.3.5 アプリケーションをデプロイする
- デプロイ?省略させてください、、。
@ 2.4 最後に
point
- 2章のまとめです。
- Railsのアプリケーションを完成させました。機能としては、ユーザの登録機能、投稿機能の二つです。よってこれからはこの二つの機能はどのようなアプリケーションにおいても実装できることを自信持ってください!
to be continued...
- 真っ白のページですが、機能はほとんどどのアプリケーションも同じ仕組みであると考えると、あとは画面のレイアウトの問題です。レイアウトが綺麗だと、不思議といいアプリケーションに見えてしまいます。実際アプリケーションを使う側(顧客)は中の機能性よりも見た目を気にすると思います。まあ5章以降の話なのですが、、。
- アルバムTRUEの中でも一番好きな曲。前向きな歌詞が気に入っています。
- 楽しい音楽を聴きながら開発することが続けることの秘訣🎵
Ruby on Rails tutorialを通してのメモ (第2章)
前回まで
- MVCについての説明、デフォルトページに「hello, world!」と表示させる作業の説明をしています。
作業開始
point
- 今回から2章に入ります。
- 2章では、Toyアプリケーションと呼ばれるRailsのアプリケーションをscaffoldを使用して簡単に作ります。
point
- Toyアプリケーションをどうやって作るかの計画を立てる。
- まずはrails new コマンドを実行する。バージョン指定を忘れずに行いたいところ。😕
私は今回のバージョンのrailsがなかったため($ gem list rails コマンドで確認したところありませんでした...)改めて該当のrails gemをインストールしました。↓ ある人は不要な作業です!
$ gem install rails -v 5.1.6
gemに限らずですが、インストールしたら確認をして見ましょう!
$ gem list rails
railsのgemのバージョン に 「5.1.6」が追加されていました!
改めてrails newをしました!
$ cd ~/environment
$ rails _5.1.6_ new toy_app
$ cd toy_app/
コピペですが、environmentディレクトリ内にに移動し、「rails (version) new アプリ名」という形でコマンドを実行しています!
- リスト2.1に従い、Gemfileを編集する。コピペ推奨です。
- $ bundle install --without production を実行する。
- gitコマンドのところをを飛ばします!🙏(説明が長くなるので、ローカルでやりたいです!できる人はやってもらったほうがいいかも!)
- どうやら前回の「Hello, world!」を表示させる手順をもう一度行うようなので、コントローラ(application_controller.rb)、ルーティング(routes.rb)をリスト2.2,2.3に従い編集します。
point
- アプリケーションを始めるにあたり、まずは設計が必要になります。主観ですが、業務では最初は設計に関わることはなかなかできない部分で、チーム開発においてはとても楽しい部分ではあります。
- どうやらこのアプリケーションはユーザーが存在するようです。なのでユーザー情報を登録します。各ユーザーには番号(id),名前(name),メールアドレス(email)を型をつけて持たせます。型とは、こちら参照して見てください。😭個人的には数字や文字にはデータを入れる専用の箱が必要なんだな、と解釈しております。
- マイクロポストですが、"ポスト" というくらいなので投稿する機能のことを指しています。いわゆるTwitterのツイート機能と考えていいと思います😄詰まる所、投稿機能にはどのような情報が必要かをここで設計(考える)するようですね。
- 必要な情報は番号(id),投稿したテキスト(content),誰が投稿したかを持つ情報(user_id) を使います。
point
$ rails generate scaffold User name:string email:string
- name:string email:string の部分がオプションにあたる所です。 先ほど(2.1.1)のtutolialでは図の2.2の通りにモデルを実装しました。 idは自動でデータベースに追加されるようです😟。オプションにはidはありませんでしたね。
- 続いて、マイグレーションを実行する必要があるようです。
$ rails db:migrate
- マイグレーションとは先ほどモデルを実装したものを実際にSQLを発行しデータベースを作成することを言います。$ rails generate と $ rails db:migrate はセットで覚えておきたい所です。
- ブラウザで動作を確認して見ましょう。「hello, world!」が見えていますか?
私の場合はHerokuにデプロイしてないので、localhost:3000が最初のトップページです。ローカルでの身作成した方は、Chromeなどのブラウザでlocalhost:3000と入力して確認をして見ましょう。
$ rails server
point
- 学習というよりかは、ブログ投稿が先行しています。手段と目的が逆的な。🤔結果的には身になることだから一手段として文章を考えることが好きな方にはオススメの勉強方法です。。
- もし、難しいと感じた場合はprogateなど環境構築のいらない学習サイトでサクサク進めることをオススメします。