見出し画像

railsチュートリアル挑戦記 第4章 Rails風味のRuby

railsチュートリアルをやりながらメモしたことをそのまま記述しています。

第4章Rails風味のRuby
3章のrailsアプリケーションを元にruby扱うよ

・4 1 動機

まずはトピックブランチを作成して作業を進める
git checkout -b rails-flavored-ruby

・4 1 1 組み込みヘルパー

app/views/layouts/application.html.erb
の以下の行に注目
<%= stylesheet_link_tag 'application', media: 'all','data-turbolinks-track': 'reload' %>

application.cssをすべてのメディアタイプで使えるようにしている
混乱を生じるrubyの4つの概念がある
組み込み関数
カッコを使わないメソッド呼び出し
シンボル
ハッシュ

・4 1 2 カスタムヘルパー

app/views/layouts/application.html.erb
の以下の行
<%= yield(:title) %> | Ruby on Rails Tutorial Sample App
は、各ビューでprovideで:titleに値をセットしてる

しかし、各ビューで設定されていない場合、変な表示になっちゃう

そういうときはヘルパーを使おう!

full_titleヘルパーを定義する
app/helpers/application_helper.rb
----------------------------
module ApplicationHelper
 # ページごとの完全なタイトルを返します。
 def full_title(page_title = '')
   #基本のタイトルです
   base_title = "Ruby on Rails Tutorial Sample App"
   #provideで;titleが設定されなかったら縦棒をつけずにそのまま出力します
   if page_title.empty?
     base_title
	#provideで:titleが設定されていたら縦棒をつけて表示します
   else
     page_title + " | " + base_title
   end
 end
end
----------------------------

そして、application.html.erbを以下のように修正することで、|がついたりつかなかったりになります

full_titleヘルパーを使ったWebサイトのレイアウトgreen
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ページのタイトル確認用にテストを更新する red
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
----------------------------

rails test

ログ
----------------------------
vored-ruby) $ rails test
Running via Spring preloader in process 19093
/home/ec2-user/environment/sample_app/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /home/ec2-user/environment/sample_app/config/application.rb to limit the frameworks that will be loaded.
Started with run options --seed 18917
                                           
ERROR["test_should_get_root", StaticPagesControllerTest, 0.3632605649981997]
test_should_get_root#StaticPagesControllerTest (0.36s)
NameError:         NameError: undefined local variable or method `root_url' for #<StaticPagesControllerTest:0x0000000006b3e2b8>
           test/controllers/static_pages_controller_test.rb:10:in `block in <class:StaticPagesControllerTest>'
FAIL["test_should_get_home", StaticPagesControllerTest, 0.4051615860007587]
test_should_get_home#StaticPagesControllerTest (0.41s)
       <Ruby on Rails Tutorial Sample App> expected but was
       <Home | Ruby on Rails Tutorial Sample App>..
       Expected 0 to be >= 1.
       test/controllers/static_pages_controller_test.rb:17:in `block in <class:StaticPagesControllerTest>'
 5/5: [] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.40997s
5 tests, 8 assertions, 1 failures, 1 errors, 0 skips
ec2-user:~/environment/sample_app (rails-flavored-ruby) $ 
----------------------------

Homeページのprovideを削除する必要がある

ページタイトルをカスタマイズせずに表示するHomeページ green
app/views/static_pages/home.html.erb
----------------------------
<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>
----------------------------

再度rails test

ログ
----------------------------
vored-ruby) $ rails test
Running via Spring preloader in process 19533
/home/ec2-user/environment/sample_app/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /home/ec2-user/environment/sample_app/config/application.rb to limit the frameworks that will be loaded.
Started with run options --seed 30571
                                           
ERROR["test_should_get_root", StaticPagesControllerTest, 0.3567180069985625]
test_should_get_root#StaticPagesControllerTest (0.36s)
NameError:         NameError: undefined local variable or method `root_url' for #<StaticPagesControllerTest:0x0000000005f0e628>
           test/controllers/static_pages_controller_test.rb:10:in `block in <class:StaticPagesControllerTest>'
 5/5: [] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.39086s
5 tests, 8 assertions, 0 failures, 1 errors, 0 skips
ec2-user:~/environment/sample_app (rails-flavored-ruby) $ 
----------------------------

あ、config/routesのrootをコメントアウトにしたままだった

それ直してrails test

ログ
----------------------------
vored-ruby) $ rails test
Running via Spring preloader in process 19624
/home/ec2-user/environment/sample_app/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /home/ec2-user/environment/sample_app/config/application.rb to limit the frameworks that will be loaded.
Started with run options --seed 52404
                                           
 5/5: [] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.38189s
5 tests, 9 assertions, 0 failures, 0 errors, 0 skips
ec2-user:~/environment/sample_app (rails-flavored-ruby) $ 
----------------------------

もう一度hobe.html.erbでprovideを復活させてエラーになって消してエラーにならないことを確認

・4 2 文字列とメソッド

Railsコンソールはirb (IRB: Interactive RuBy) を拡張して作られている。

ホームディレクトリに.irbrcファイルを作ってみる
nano ~/.irbrc

irbの邪魔な自動インデント機能をOFFにできる
irbの設定ファイルを追加する
nano ~/.irbrc

・・・てコンソールになんか立ち上がったぞ?!
あ、ここに以下の2行を打ち込むのか

----------------------------
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:AUTO_INDENT_MODE] = false
----------------------------

んで、Ctrl+Xで離脱できるんだね~
ほんで、y押して保存で終わりか。

・・・ん?固まった?
あぁ、Enter押したら元の画面に戻ったわ
いや、時間経過で戻ったのか?分からんけどまあいいや

rails consoleを起動してみる

ログ
----------------------------
ec2-user:~/environment/sample_app (rails-flavored-ruby) $ rails console
Running via Spring preloader in process 22159
Loading development environment (Rails 5.1.6)
>> 
----------------------------

実はコンソールはデフォルトで開発環境で起動する
他の2つはテスト環境と本番環境。とりあえずデフォルトのまま。

railsコンソールで何かを壊すことはまずありえないので安心。
railsコンソールでおかしくなったらCtrl+cで強制的に抜け出す。
Ctrl+Dで正常に抜け出す
↑で過去のコマンドを呼び出せる

・4 2 1 コメント


#

・4 2 2 文字列

rubyの備忘録に書いてあるからほぼ読み飛ばした

putsは文字列を出力するが戻り値はnilを返す
putsは改行する
printは改行しない
printで改行するときは\nを使う

・4 2 3 オブジェクトとメッセージ受け渡し

全てオブジェクト
"".length=>6
"foobar".empty?=>false
"".empty?=>true

rubyでは後続ifを記述できる

#xが空でないとき
puts "x is not empty" if !x.empty?

#stringが空でないとき
puts "The string '#{string}' is nonempty." unless string.empty?

強制的に論理値に変更する方法
!!nil
!!はバンバンと読む

rubyは0ですらtrue

reverseメソッドを使うと
puts "reverse".reverse
esreverと表示される
ちな戻り値はnil

.nil?とするとnilのときにtrueになる

・4 2 4 メソッドの定義

defでやる

rubyでは戻り値がなくても暗黙の戻り値がある

・4 2 5 titleヘルパー、再び

module ApplicationHelperについて

関連したメソッドをまとめる方法の1つで、includeメソッドを使ってモジュールを読み込むことができる
ミックスイン (mixed in) とも呼ぶ

full_titleメソッドは自動的にすべてのビューで利用できるようになっている

・4 3 他のデータ構造


webアプリケーションはただの文字列

・4 3 1 配列と範囲演算子


配列を理解することは、ハッシュやデータモデルを理解するための重要な基盤

空白で切り分ける
>> "foo bar baz".split # 文字列を3つの要素を持つ配列に分割する
=> ["foo", "bar", "baz"]

xで切り分ける
>> "fooxbarxbaz".split('x')
=> ["foo", "bar", "baz"]

添え字で数字を指定する以外にもなんか色々指定方法ある
>> a # 配列「a」の内容を確認する
=> [42, 8, 17]
>> a.first
=> 42
>> a.second
=> 8
>> a.last
=> 17
>> a.last == a[-1] # == を使って比較する
=> true

含まれてるかどうか
>> a.include?(42)
=> true

昇順
>> a.sort
=> [8, 17, 42]

逆転
>> a.reverse
=> [17, 8, 42]

混ぜる
>> a.shuffle
=> [17, 42, 8]

全て表示
>> 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"]

配列の添え字にマイナスを指定すると末尾に行って先頭に行く形になる

splitの逆でjoinがある
>> a
=> [42, 8, 17, 6, 7, "foo", "bar"]
>> a.join # 単純に連結する
=> "4281767foobar"
>> a.join(', ') # カンマ+スペースを使って連結する
=> "42, 8, 17, 6, 7, foo, bar"

toArrayの略で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]

>> a = %w[foo bar baz quux] # %wを使って文字列の配列に変換
=> ["foo", "bar", "baz", "quux"]
>> a[0..2]
=> ["foo", "bar", "baz"]

a[-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]

文字列も配列化できる
>> ('a'..'e').to_a
=> ["a", "b", "c", "d", "e"]

downcaseは文字列中の大文字を小文字に変えた新しい文字列を返

・4 3 2 ブロック

>> (1..5).each { |i| puts 2 * i }
2
4
6
8
10
=> 1..5

>> (1..5).each do |i|
?> puts 2 * i
>> end
2
4
6
8
10
=> 1..5

は同じ結果

ちな{ |i| puts 2 * i }がブロック
そうじゃない形ならputsのところがブロック

>> 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"]

小文字にして返す
>> %w[A B C].map { |char| char.downcase }
=> ["a", "b", "c"]

小文字にして返す
>> %w[A B C].map(&:downcase)
=> ["a", "b", "c"]

('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 ハッシュとシンボル

前コロンは=>が必要
>> 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"}

でも使うときは前コロン

ハッシュにeach使うとき
>> flash.each do |key, value|
?> puts "Key #{key.inspect} has value #{value.inspect}"
>> end
Key :success has value "It worked!"
Key :danger has value "It failed."

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!"

インスペクトはよく使われるため、
p :name
が使えるようになった

{ "a" => 100, "b" => 200 }.merge({ "b" => 300 })は
{ "a" => 100, "b" => 300 }になる

・4 3 4 CSS、再び

実は関数使うときに丸カッコなくても大丈夫
ハッシュは関数の引数の末尾なら波カッコなくても大丈夫

rubyは1行を80字以内に収めてコードを読みやすくしている

stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload'

は、
<link data-turbolinks-track="true" href="/assets/application.css"
media="all" rel="stylesheet" />

になる

クラスから呼び出すメソッドをクラスメソッド
インスタンスから呼び出すメソッドをインスタンスメソッド

・4 4 Rubyにおけるクラス

クラス階層を調べる
>> 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

rubyはBasicObjectを継承しているからあらゆるものがオブジェクトになる

・4 4 1 コンストラクタ

特に学ぶことなし

・4 4 2 クラス継承

特に学ぶことなし


・4 4 3 組み込みクラスの変更

元々あるクラスですら書き換えられるヤバそう


・4 4 4 コントローラクラス

>> 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

User=>
ApplicationRecord(abstract)=>
ActiveRecord::Base=>
Object

・4 4 5 ユーザークラス

6章で使う用のUserクラスを最初から作成してみる
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
----------------------------

マスアサインメント (mass assignment) という技法
initializeメソッドにハッシュを渡すことで
属性が定義済みの他のユーザーを作成することができる

・4 5 最後に

マージする

・4 5 1 本章のまとめ

rubyは文字列を扱うためのメソッドを多数持っている
rubyの世界ではすべてがオブジェクトである
rubyではdefを使ってメソッドを定義する
rubyではclassというキーワードを使ってクラスを定義する
railsビューでは静的HTMLのほかにERBも使える
Rubyの組み込みクラスには配列、範囲、ハッシュなどがある
Rubyのブロックは柔軟な機能で、添え字を使ったデータ構造よりも自然にイテレーションができる
シンボルとはラベルである。追加的な構造を持たない文字列みたいなもの
Rubyではクラスを継承できる
Rubyでは組み込みクラスですら内部を見たり修正したりできる

この記事が気に入ったらサポートをしてみませんか?