Ruby on Rails チュートリアルで30歳までに人生を変える(第5章)
こんにちは。opiyoです。
今回は、第5章をやっていきます。
第5章はレイアウト。つまり見た目の部分をメインにやっていきます。
では、早速始めてみたいと思います。
railsチュートリアル5章の学び
クラスとidの違い クラス:ページの中で何度でも使用ができる id:一度しか使用できない
画像は
app/assets/images
に置きimage_tag("ファイル名", alt: "属性名")
で呼び出す.(ドット)
はクラスを表しますアセットディレクトリ
- app/assets: 現在のアプリケーション固有のアセット
- lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット
vendor/assets: サードパーティのアセット
アセットをまとめる処理を行うのはSprocketsというgem
リダイレクトの場合のみ_url書式を使用
pathとurlの違い
- help_path -> '/help'
- help_url -> 'http://www.example.com/help'
統合テスト (Integration Test)の実行方法
- $ rails test:integration
railsチュートリアル5章の演習解説
5.1.1 演習 ナビゲーション
5.1.1.1
<問題> Webページと言ったらネコ画像、というぐらいにはWebにはネコ画像が溢れていますよね。リスト 5.4のコマンドを使って、図 5.3のネコ画像をダウンロードしてきましょう。
<回答>
$ curl -OL cdn.learnenough.com/kitten.jpg
5.1.1.2
<問題> mvコマンドを使って、ダウンロードしたkitten.jpgファイルを適切なアセットディレクトリに移動してください (参考: 5.2.1)。
<回答>
$ mv kitten.jpg app/assets/images/kitten.jpg
5.1.1.3
<問題> image_tagを使って、kitten.jpg画像を表示してみてください (図 5.4)。
<回答>
# app/views/static_pages/home.html.erb <div class="center jumbotron"> <h1>Welcome to the Sample App</h1> <h2> This is the home page for the <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a> sample application. </h2> <%= link_to "Sign up now!", "#", class: "btn btn-lg btn-primary" %> </div> <%= link_to image_tag("rails.png", alt: "Rails logo"), "https://rubyonrails.org/" %> <%= image_tag("kitten.jpg", alt: "cat logo") %>
5.1.2 演習 BootstrapとカスタムCSS
5.1.2.1
<問題>リスト 5.10を参考にして、5.1.1.1で使ったネコ画像をコメントアウトしてみてください。また、ブラウザのHTMLインスペクタ機能を使って、コメントアウトするとHTMLのソースからも消えていることを確認してみてください。
<回答>
<!-- <%= image_tag("kitten.jpg", alt: "cat logo") %> -->
5.1.2.2
<問題>リスト 5.11のコードをcustom.scssに追加し、すべての画像を非表示にしてみてください。うまくいけば、Railsのロゴ画像がHomeページから消えるはずです。先ほどと同様にインスペクタ機能を使って、今度はHTMLのソースコードは残ったままで、画像だけが表示されなくなっていることを確認してみてください。
<回答>
img { display: none; }
5.1.3 演習 パーシャル(partial)
5.1.3.1
<問題>Railsがデフォルトで生成するheadタグの部分を、リスト 5.18のようにrenderに置き換えてみてください。ヒント: 単純に削除してしまうと後でパーシャルを1から書き直す必要が出てくるので、削除する前にどこかに退避しておきましょう。
<回答>
# app/views/layouts/_rails_default.html.erb <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
5.1.3.2
<問題>リスト 5.18のようなパーシャルはまだ作っていないので、現時点ではテストは redになっているはずです。実際にテストを実行して確認してみましょう。
<回答> redになる!
5.1.3.3
<問題>layoutsディレクトリにheadタグ用のパーシャルを作成し、先ほど退避しておいたコードを書き込み、最後にテストが green に戻ることを確認しましょう。
<回答> greenになる!
5.2.2 演習 アセットパイプライン
5.2.2.1
<問題> 5.2.2で提案したように、footerのCSSを手作業で変換してみましょう。具体的には、リスト 5.17の内容を1つずつ変換していき、リスト 5.20のようにしてみてください。
<回答>
/* footer */ footer { margin-top: 45px; padding-top: 5px; border-top: 1px solid $gray-medium-light; color: $gray-light; a { color: $gray; &:hover { color: $gray-darker; } } small { float: left; } ul { float: right; list-style: none; li { float: left; margin-left: 15px; } } }
5.3.2 演習 RailsのルートURL
5.3.2.1
<問題>実は名前付きルートは、as:オプションを使って変更することができます。有名なFar Sideの漫画に倣って、Helpページの名前付きルートをhelfに変更してみてください。
<回答>
rails routes Prefix Verb URI Pattern Controller#Action root GET / static_pages#home help GET /help(.:format) static_pages#help about GET /about(.:format) static_pages#about contact GET /contact(.:format) static_pages#contact rh0257:railstutorial_5 taku$ rails routes Prefix Verb URI Pattern Controller#Action root GET / static_pages#home helf GET /help(.:format) static_pages#help # 「helf」になっていることを確認! about GET /about(.:format) static_pages#about contact GET /contact(.:format) static_pages#contact
5.3.2.2
<問題>先ほどの変更により、テストが redになっていることを確認してください。リスト 5.28を参考にルーティングを更新して、テストを greenにして見てください。
<回答> できた
5.3.2.3
<問題>エディタのUndo機能を使って、今回の演習で行った変更を元に戻して見てください。
<回答> Command + z
5.3.3 演習 名前付きルート
5.3.3.1
<問題>リスト 5.29のようにhelfルーティングを作成し、レイアウトのリンクを更新してみてください。
<回答>
<%= link_to "Help", helf_path %>
にしても/help
にジャンプすることを確認した
5.3.3.2
<問題>前回の演習と同様に、エディタのUndo機能を使ってこの演習で行った変更を元に戻してみてください。
<回答> Command + z
演習 5.3.4 リンクのテスト
5.3.4.1
<問題> footerパーシャルのabout_pathをcontact_pathに変更してみて、テストが正しくエラーを捕まえてくれるかどうか確認してみてください。
<回答>
$ rails test Running via Spring preloader in process 49273 Started with run options --seed 21667 FAIL["test_layout_links", SiteLayoutTest, 0.8195362979986385] test_layout_links#SiteLayoutTest (0.82s) Expected at least 1 element matching "a[href="/about"]", found 0.. Expected 0 to be >= 1. test/integration/site_layout_test.rb:9:in `block in <class:SiteLayoutTest>' 5/5: [============================================================================================================================================================] 100% Time: 00:00:00, Time: 00:00:00 Finished in 0.95899s 5 tests, 12 assertions, 1 failures, 0 errors, 0 skips
5.3.4.2
<問題> リスト 5.35で示すように、Applicationヘルパーで使っているfull_titleヘルパーを、test環境でも使えるようにすると便利です。こうしておくと、リスト 5.36のようなコードを使って、正しいタイトルをテストすることができます。ただし、これは完璧なテストではありません。たとえばベースタイトルに「Ruby on Rails Tutoial」といった誤字があったとしても、このテストでは発見することができないでしょう。この問題を解決するためには、full_titleヘルパーに対するテストを書く必要があります。そこで、Applicationヘルパーをテストするファイルを作成し、リスト 5.37のFILL_INの部分を適切なコードに置き換えてみてください。ヒント: リスト 5.37ではassert_equal <期待される値>, <実際の値>といった形で使っていましたが、内部では==演算子で期待される値と実際の値を比較し、正しいかどうかのテストをしています。
<回答>
# test/helpers/application_helper_test.rb require 'test_helper' class ApplicationHelperTest < ActionView::TestCase test "full title helper" do assert_equal full_title, 'Ruby on Rails Tutorial Sample App' assert_equal full_title("Help"), 'Help | Ruby on Rails Tutorial Sample App' end end
5.4.1 演習
5.4.1.1
<問題>表 5.1を参考にしながらリスト 5.41を変更し、users_new_urlではなくsignup_pathを使えるようにしてみてください。
<回答>
# routes.rb get '/signup', to: 'users#new'
# rails routesコマンド $ rails routes Prefix Verb URI Pattern Controller#Action root GET / static_pages#home help GET /help(.:format) static_pages#help about GET /about(.:format) static_pages#about contact GET /contact(.:format) static_pages#contact signup GET /signup(.:format) users#new ← `signup`が追加されていることを確認!
5.4.1.2
<問題>先ほどの変更を加えたことにより、テストが redになったことを確認してください。なお、この演習はテスト駆動開発 (コラム 3.3) で説明した red/green のリズムを作ることを目的としています。このテストは次の5.4.2で greenになるよう修正します。
<回答> OK
5.4.2 演習
5.4.2.1
<問題>もしまだ5.4.1.1の演習に取り掛かっていなければ、まずはリスト 5.41のように変更し、名前付きルートsignup_pathを使えるようにしてください。また、リスト 5.43で名前付きルートが使えるようになったので、現時点でテストが greenになっていることを確認してください。
<回答>
# rails testコマンド $ rails test Running via Spring preloader in process 2676 Started with run options --seed 22738 7/7: [============================================================================================================================================================] 100% Time: 00:00:00, Time: 00:00:00 Finished in 0.89370s 7 tests, 17 assertions, 0 failures, 0 errors, 0 skips
5.4.2.2
<問題>先ほどのテストが正しく動いていることを確認するため、signupルールの部分をコメントアウトし、テスト redになることを確認してください。確認できたら、コメントアウトを解除して greenの状態に戻してください。
<回答>
OK
コメントアウトは#
で、元に戻すときはCommand + z
5.4.2.3
<問題>リスト 5.32の統合テストにsignupページにアクセスするコードを追加してください (getメソッドを使います)。コードを追加したら実際にテストを実行し、結果が正しいことを確認してください。 ヒント: リスト 5.36で紹介したfull_titleヘルパーを使ってみてください。
<回答>
# test/integration/site_layout_test.rb require 'test_helper' class SiteLayoutTest < ActionDispatch::IntegrationTest test "layout links" do get root_path assert_template 'static_pages/home' assert_select "a[href=?]", root_path, count: 2 assert_select "a[href=?]", help_path assert_select "a[href=?]", about_path assert_select "a[href=?]", contact_path get contact_path assert_select "title", full_title("Contact") get signup_path ← 追加! assert_template 'users/new' ← 追加! end end
好きなことで生きていくって難しいよ
会社では新卒を除いて僕が一番若い
20代は僕以外に多分一人しかいない
先輩達のほとんどが中途組だから人生の参考にはならない
さっきTwitter見てたら2020年には年収400万以下の人が6割になるってニュースを見た。
まー当たり前だろうし、そんな事は分かっているのだけど改めて言われると夢がないなーって思う。
ある程度大きな会社に入ればだいたいこのくらいで年収いくら、あーなったら出世コースでとか分かるっていう。実際にあーあいつは出世コースだなみたいな話もするらしいので本当だろう。
先ずこのレースに参加できるのは学生時代必死に勉強して良い大学に入った人達だけだ。
大学を卒業してなければ就職活動に参加することすら出来ない
いやいや今の時代40年間続く会社は4社くらいしかない
あれだけ大きな会社だった今の時代どうなるか分からない
だからこそ好きなことをやらないと生きていけない
そんな言葉がネットの世界では溢れているが、好きなことだと思って専門学校に行くという人生を歩んで来た人間から言わせると本当にそれ好きか?
それが好きな人達の中に飛び込むと圧倒される。そこでなんて最高な世界なんだって思えればそれは本当に好きなんだろうけど大体の人は場違いの場所に来たってなると思うよ。だって熱量が違い過ぎる。
専門的な事をするって簡単に言うけど間違いなく上には上がいるしそもそも普通のサラリーマンをするより門はめちゃくちゃ狭いぞ。
ただ、その中でもがき苦しみ突き抜けた人ってのは間違いなく成功する。
僕の知り合いは最初全然冴えない感じだったけど今では業界でも知名度のある凄い奴になっている。(まー元々馬鹿みたいにカッコ良かったから殻を破れてなかっただけかもしれないが)
最後に
とまー色々最近考えることがあって人生について悩み苦しんでいるのだけど好きなことで生きていくってのは大変ですよって話です。
だけど普通に生きていたら400万の人生しか生きれない。
じゃーどうするか。
藤原先生の「レアカード」になるって考え方がきっと確実に生きていく方法、正解なんだと思います。
たとえ好きな事じゃなくても100分の1を積み重ねていくことで自分の価値を上げる。
今周りにある環境で100分の1を先ずは目指す。何かに挑戦して100分の1を目指す。その繰り返し繰り返しが結果的に自分の価値を高める=レアカードになれる。
好きな事だから頑張れるってのは勿論あると思うけど、そればっかりに頭を使うんじゃなくて色々な要素を掛け算して考えるってのがすごい大事。
うーん何か言いたいことと違った結論になってしまったような。まー今日はこんな感じ。
しっかり握っておかないと心はすぐに離れてしまうから
最近いろいろとバタバタとしていて、子供たちと接する時間が取れてなかった。
昨日やっと色々落ち着いて子供たちと遊ぼうとするのですが何するにも壁があるような。
娘は絶対朝送ってくれるのにそれがない。帰った時の「パパだいずき」がない。「しょうぎしょうぎ」っていわない。
物理的な距離は確実に心の距離も遠ざける
これらは昨日一日で感じた事だから今日帰ったらな~んて事はないのかもしれない。
相手は子供だ。 子供は環境に適応するのが本当に早いとよく言う。子供たちも幼稚園に行きだして集団生活になりきっと楽しいことばかりじゃないだろうけど、朝早く起きて支度をして幼稚園に行って弁当食べて帰ってくる。そんな日常が当たり前になっていく。
海外に転勤になった時、一番大変なのはママって聞く。子供たちは気づいたら当たり前の生活になってしまう。
全部いいことだけ取り上げればそうだが、逆だって当然だ。
居なくて当たり前になってしまったら、そのように振舞うしどう接すればよいかも分からない。
大人は色々な事情や想いを知っているし我慢が出来るから頑張れるけど子供は今見えている世界が全てである。
父との思い出はキャッチボールだけ
僕は父が嫌いだ。
僕は父と話した記憶がほとんど無い。
学生の頃、友達が父と一緒にエロ本見て遊んでたとか言ってたけど考えられなかった。だけどそんな父って良いなって思う。
どんな時も真面目で笑わず本を読んでいる。唯一の思い出は庭の水やりを終わった後の夕方のキャッチボールとチケットが当たったと言って連れてってもらった東京ドームオープン戦だ。
ずっとサッカーをやっていたのだけど何となく野球がしたくて小学校高学年から野球を始めた。自分中でも分からないきっと父と遊んだ唯一の野球という存在が忘れられなくて野球をやってのだと思う。
どんな仕事をしていたかは今となってやっと何となく分かるけど聞いたことなかったし、何が好きで何を思って生きてきたのか。あなたは人生楽しかったのだろうか。
僕は父から学んだことは正直ほとんど無い。目の前にはいるが僕の心にはいなかった。
最後に
まー色々と書いてきたが、子供の心はしっかりと握っておかなければすぐに何処かへ行ってしまうなと思った。って話です。
物理的に近くにいることは勿論だけど、それだけじゃなくしっかりと会話して伝えていく必要がある。
僕は子供にとって父でいたいし、大人になった時に一番の親友でいたい。
その為にも、今から自分がどう生きてきたのか、何か思っているのか、何を学んだのか。
今、目の前に見えている「あたりまえ」の世界は全然当たり前ではない
ドコモとミスチルの25周年記念動画を見たことがあるだろうか。
もし見たことが無ければ是非見てほしい。
私は重なる部分が多く、泣いてしまった。
今こうして思い出すだけでも少し目が重たくなってる気がする。
https://www.nttdocomo.co.jp/special_contents/25th/mrchildren/
私は今人生の大きな岐路に立っていると思っている。
まだ決まった訳では無いから多くの事は言えないのだが、こんなんも悩んだことは人生で思いつかない。
言いたいことは一つで、
人間何処かで頑張らないと本当の幸せを掴むことは出来ない。
動画の中でも高橋一生は単身赴任で遠くに出かけていってしまう。
一人娘がいるのだが、それまで娘はパパが大好きだったのに会えない。
誕生日には娘がダンスする動画をパパに送ったり本当に幸せそうにしている。
だが単身赴任が終わり家に帰ると娘と離れてしまった気持ちは取り戻すことが出来ず喧嘩ばかり。
当たり前だ。娘はずっと寂しかったのだ。
一度閉じてしまった心は中々開かない。
じゃーこの時パパは単身赴任なんてせずに家にいればよかったんじゃないか。家族と一緒に引っ越せば良かったんじゃないか。離れてしまうくらいなら仕
事を変えればよかったんじゃないか。
そんな風に考える人もいるかもしれないが、「生きる」ってそんな簡単な話じゃない。相当な覚悟を持ってきっと決断したのだと思う。
きっと「今」ではなく「未来」が幸せであれと願い、想い、出した答えだったのだろう。
何が正解かなんて、僕たちは今を歩いているのだから未来のことは分からない。
「忙しい」という言葉を言い訳に未来に対する危機感が全くない人達。
危機感いっぱいにもかかわらず行動できなきない人。
どんな答えを出したって想いを持っての行動ならば、それはきっと間違ってないのだと思う。
ただその決断をしたことで悲しんでいる人がいるかもしれない。迷惑をかけているかもしれない。
その想いをしっかり胸に刻み一歩ずつ前に進みだそう。きっと良い未来が待っている。
Ruby on Rails チュートリアル4章の後半まとめてみた
こんちには、opiyoです。
人生の生き残りをかけて始めた「Railsブートキャンプ」ですが、今日はRailsチュートリアル第4章をやっていこうと思います。
第4章は「Ruby」のお勉強です。早速やってみましょう!
この記事は後半戦になります。
前半戦はこちらからどうぞ。
railsチュートリアル4章の解説
クラス
> s = "opiyo" => "opiyo" > s.class => String
- 名前付きコンストラクタとは、クラス名に対して
new
メソッドを呼び出す - Hashの場合は引数がデフォルト値になる
# 文字列 > d = String.new("Opiyo") => "Opiyo" > d.class => String > d == "Opiyo" => true # 配列 > a = Array.new([1, 3, 2]) => [1, 3, 2] # Hash > h = Hash.new => {} > h[:foo] # 存在しないキー (:foo) の値にアクセスしてみる => nil > h = Hash.new(0) # 存在しないキーのデフォルト値をnilから0にする => {} > h[:foo] => 0
- クラスの継承
> s = String.new("foobar") => "foobar" > s.class => String > s.class.superclass => Object > s.class.superclass.superclass => BasicObject > s.class.superclass.superclass.superclass => nil
- 組み込みの基本クラスの拡張が可能
> class String > # 文字列が回文であればtrueを返す > def palindrome? > self == self.reverse > end > end => nil > "deified".palindrome? => true
- コントローラークラスの継承
> controller = StaticPagesController.new => #<StaticPagesController:0x007fec80a64130 @_action_has_layout=true, @_routes=nil, @_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.class.superclass.superclass.superclass.superclass.superclass.superclass => BasicObject > controller.class.superclass.superclass.superclass.superclass.superclass.superclass.superclass => nil
railsチュートリアル4章の演習問題
演習4.4.1 コンストラクタ
4.4.1.1
<問題>1から10の範囲オブジェクトを生成するリテラルコンストラクタは何でしたか? (復習です)
<回答>
> r = 1..10 => 1..10 > r.class => Range
4.4.1.2
<問題>今度はRangeクラスとnewメソッドを使って、1から10の範囲オブジェクトを作ってみてください。ヒント: newメソッドに2つの引数を渡す必要があります
<回答>
> r = Range.new(1,10) => 1..10 > r.class => Range
4.4.1.3
<問題>比較演算子==を使って、上記2つの課題で作ったそれぞれのオブジェクトが同じであることを確認してみてください。
<回答>
> r = 1..10 => 1..10 > rn = Range.new(1,10) => 1..10 > r == rn => true
演習4.4.2 クラス継承
4.4.2.1
<問題>Rangeクラスの継承階層を調べてみてください。同様にして、HashとSymbolクラスの継承階層も調べてみてください。
<回答>
# Range > r = Range.new(1,10) => 1..10 > r.class => Range > r.class.superclass => Object > r.class.superclass.superclass => BasicObject > r.class.superclass.superclass.superclass => nil # Hash h = Hash.new(0) => {} > h.class => Hash > h.class.superclass => Object > h.class.superclass.superclass => BasicObject > h.class.superclass.superclass.superclass => nil # Symbol :symbol => :symbol > :symbol.class => Symbol > :symbol.class.superclass => Object > :symbol.class.superclass.superclass => BasicObject > :symbol.class.superclass.superclass.superclass => nil
4.4.2.2
<問題>リスト 4.15にあるself.reverseのselfを省略し、reverseと書いてもうまく動くことを確認してみてください。
<回答>
> class Word < String > def palindrome? > self == self.reverse > end > end => :palindrome? > s = Word.new("level") => "level" > s.palindrome? => true > s.length => 5 > class Word < String > def palindrome? > self == reverse > end > end => :palindrome? > Word.new("level") > s.palindrome? => true > s.length => 5
演習 4.4.3 組み込みクラスの変更
4.4.3.1
<問題>palindrome?メソッドを使って、“racecar”が回文であり、“onomatopoeia”が回文でないことを確認してみてください。南インドの言葉「Malayalam」は回文でしょうか? ヒント: downcaseメソッドで小文字にすることを忘れないで。
<回答>
> "racecar".palindrome? => true > "onomatopoeia".palindrome? => false > "Malayalam".downcase.palindrome? => true
4.4.3.2
<問題>リスト 4.16を参考に、Stringクラスにshuffleメソッドを追加してみてください。 ヒント: リスト 4.12も参考になります。
<回答>
> class String > def shuffle > self.split("").shuffle.join > end > end => :shuffle > "foobar".shuffle => "ofbaro"
4.4.3.3
<問題>リスト 4.16のコードにおいて、self.を削除してもうまく動くことを確認してください。
<回答>
> class String > def shuffle > split("").shuffle.join > end > end => :shuffle > "foobar".shuffle => "rafobo"
演習 4.4.4 コントローラークラス
4.4.4.1
<問題>第2章で作ったToyアプリケーションのディレクトリでRailsコンソールを開き、User.newと実行することでuserオブジェクトが生成できることを確認してみましょう。
<回答>
> u = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
4.4.4.2
<問題>生成したuserオブジェクトのクラスの継承階層を調べてみてください。
<回答>
> u.class => User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime) > u.class.superclass => ApplicationRecord(abstract) > u.class.superclass.superclass => ActiveRecord::Base > u.class.superclass.superclass.superclass => Object > u.class.superclass.superclass.superclass.superclass => BasicObject > u.class.superclass.superclass.superclass.superclass.superclass => nil
演習 4.4.5 ユーザークラス
4.4.5.1
<問題>Userクラスで定義されているname属性を修正して、first_name属性とlast_name属性に分割してみましょう。また、それらの属性を使って "Michael Hartl" といった文字列を返すfull_nameメソッドを定義してみてください。最後に、formatted_emailメソッドのnameの部分を、full_nameに置き換えてみましょう (元々の結果と同じになっていれば成功です)
<回答>
# example_user.rb class User attr_accessor :first_name, :last_name, :email def initialize(attributes = {}) @name = attributes[:first_name] @name = attributes[:last_name] @email = attributes[:email] end def full_name @full_name = @first_name + @last_name end def formatted_email "#{full_name} <#{@email}>" end end
# rails c > require './example_user' => true > u = User.new(first_name: "Haku", last_name: "Nagano", email: "haku@co.jp") => #<User:0x007f8d718ab8c0 @first_name="Haku", @last_name="Nagano", @email="haku@co.jp"> > u.full_name => "HakuNagano" > u.email = "Haku@co.jp" => "Haku@co.jp" > u.formatted_email => "HakuNagano <Haku@co.jp>"
4.4.5.2
<問題>"Hartl, Michael" といったフォーマット (苗字と名前がカンマ+半角スペースで区切られている文字列) で返すalphabetical_nameメソッドを定義してみましょう。
<回答>
def alphabetical_name "#{first_name}, #{last_name}" end
# rails c > require './example_user' => true > u = User.new(first_name: "Haku", last_name: "Nagano", email: "haku@co.jp") => #<User:0x007f8d6b3d2048 @first_name="Haku", @last_name="Nagano", @email="haku@co.jp"> > u.alphabetical_name => "Haku, Nagano"
4.4.5.3
<問題>full_name.splitとalphabetical_name.split(’, ’).reverseの結果を比較し、同じ結果になるかどうか確認してみましょう。
<回答> ?再度確認する
新しいRubyのバージョンがrbenvに表示されない時はgit pullする
Rubyのバージョン調べてみると2.2.3
だったので、2.2.4以上をインストールすべく
$ brew update $ brew upgrade rbenv ruby-build
をやってインストールできるバージョン一覧を表示
$ rbenv install --list (略) 2.2.1 2.2.2 2.2.3 (略)
しかし、2.2.3以上のバージョンが表示されない。。。
で、調べてみるとruby-build
をgit pull
すれば良いそうだ
$ cd ~/.rbenv/plugins/ruby-build $ git pull
再度表示すると2.2.4、2.2.5が出現!!
$ rbenv install --list (略) 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 (略)
めでたし。めでたし。
Ruby on Rails チュートリアル4章の前半まとめてみた
こんちには、opiyoです。
人生の生き残りをかけて始めた「Railsブートキャンプ」ですが、今日はRailsチュートリアル第4章をやっていこうと思います。
第4章は「Ruby」のお勉強です。早速やってみましょう!
あまりにもボリューミーなので、2回に分けます。この記事では「4.3 他のデータ構造までを」。
前回までのをまとめたのはこちらからどうぞ。
この章から始められる場合も、3章の「セットアップ」を参考に準備してください。
railsチュートリアル4章の解説
カスタムヘルパー
Railsのビューからは色々な関数が定義れています。
これは、自分で定義することもでき「カスタムヘルパー」と呼びます。
ここでは、3章で作成した各ビューで定義しているタイトルをヘルパーを使って定義します。
# app/helpers/application_helper.rb module ApplicationHelper # ページごとの完全なタイトルを返します。 def full_title(page_title = '') base_title = "Ruby on Rails Tutorial Sample App" if page_title.empty? # empty?は空っぽだったら「true」を返す base_title else page_title + " | " + base_title end end end
文字列とメソッド
$ rails console #ターミナルに潜り込みます
>>
このターミナルを使って簡単なRubyの勉強
コメントアウト
name = test * test # この「#」がコメントアウト
end
足し算
> 17 +42 => 59
文字列の連結
> "foo" + "bar" => "foobar"
式展開
> first_name = "Taku" > "#{first_name} Nakano" => "Taku Nakano"
出力
> puts "foo" # putsだと末尾に自動で改行コードが付与されるされる foo => nil > print "foo" # 文字が続いているのがわかる foo=> nil
シングルクォート内の文字列
> first_name = 'Taku' > '#{first_name} Nakano' => "\#{first_name} Nakno" # シングルクォートの場合は式展開されないので注意!
オブジェクトとメッセージ
Rubyでは文字列も、nilも何でもかんでもオブジェクトです。
例えば、文字列の数を知りたい場合はkength
メソッドを使います。
> "foobar".length # 文字列に "length" というメッセージを送る => 6
条件分岐
if
を使って処理を分岐することができる- 2つ以上にしたい時は
elsif
を使う - and(&&) や or(||) を使える
> 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'" > 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
メソッドの定義
メソッドは先ほど作ったカスタムヘルパーや、homeアクションやhelpアクションなどもそうですね。
def hogehoge(メソッド名) end
で定義できる- 引数にデフォルト値を含めることが可能
def string_message(str = '')
- この場合は引数を指定しないと
str = ''
がセットされる
- この場合は引数を指定しないと
配列と範囲演算子
文字列の分割
> "foo bar baz".split # デフォルトは「空白」で分割する => ["foo", "bar", "baz"] > "fooxbarxbazx".split('x') # 引数を指定すればそれで分割できる => ["foo", "bar", "baz"]
配列の中身を取り出す
a = [42, 8, 17] => [42, 8, 17] > a[0] # 0が一番目の要素になるので要注意! => 42 > a[1] => 8 > a[2] => 17 > a[-1] # マイナスの場合は後ろから数える! => 17 > a.first => 42 > a.second => 8 > a.last => 17 > a.last == a[-1] => true
いろいろなメソッド
a => [42, 8, 17] > a.empty? # 配列が空であればtrue、1つ以上何か値があればfalseを返します。 => false > a.include?(42) => true > a.sort => [8, 17, 42] > a.reverse => [17, 8, 42] > a.shuffle => [8, 42, 17] > a => [42, 8, 17] # いろいろやっても値は「変わらない!」ことに気をつけましょう。 > a.sort! # 「!」などの破壊的メソッドと呼ばれるメソッドを使うと強制的に値を書き換えます。 => [8, 17, 42] > a => [8, 17, 42]
値の追加
> a.push(6) => [42, 8, 17, 6] irb(main):044:0> a << 7 => [42, 8, 17, 6, 7] irb(main):045:0> a << "foo" << "bar" => [42, 8, 17, 6, 7, "foo", "bar"]
結合
> a => [42, 8, 17, 6, 7, "foo", "bar"] > a.join => "4281767foobar" > a.join(",") => "42,8,17,6,7,foo,bar"
範囲
> 0..9 => 0..9 irb(main):064:0> 0..9.to_a NoMethodError: undefined method `to_a' for 9:Integer # 9に対して`to_a`してるのでエラーになります Did you mean? to_s to_c to_f to_i to_d to_r . . from -e:1:in `<main>' irb(main):065:0> (0..9).to_a # ()を付けて範囲に対して`to_a`していることを伝えてあげます => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] > a = %w(foo bar baz quux) => ["foo", "bar", "baz", "quux"] > a[0..2] => ["foo", "bar", "baz"] > ('a'..'e').to_a # 文字でも使える!すごいねRuby! => ["a", "b", "c", "d", "e"]
ブロック
- ブロックは「{ }」のことで、「do end」で囲って表現する場合もあります。
- 短い1行のブロックには波かっこを使用し、長い1行や複数行のブロックにはdo..end記法を使うのが一般的
例えば、以下は1~5を順番に変数i
に渡してputs 2 * i
を実行するというような処理になります。
> (1..5).each { |i| puts 2 * i } 2 4 6 8 10 => 1..5 > (1..5).each do |i| * puts i * 2 > end 2 4 6 8 10 => 1..5
mapメソッド
> 3.times { puts "Betelgeuse!" } # 3.timesではブロックに変数を使用していない "Betelgeuse!" "Betelgeuse!" "Betelgeuse!" => 3 > (1..5).map { |i| i**2 } # 「**」記法は冪乗 (べき乗) => [1, 4, 9, 16, 25] # 配列で帰ってくる # 同じ結果をeachでやるには、こんな感じ? > array = [] => [] > (1..5).each do |i| * array << i ** 2 > end => 1..5 > array => [1, 4, 9, 16, 25] > %w[a b c] => ["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(&:downcase) # 省略できる => ["a", "b", "c"]
ハッシュとシンボル
- ハッシュとはインデックス([]の中身)に整数値以外のものも使用できる点が配列と違う
- ハッシュは「{}」を使って表記する
- ブロックの「{}」とは全く違う
- ハッシュでは要素の「並び順」が保証されない
user = {} => {} > user["first_name"] = "Michael" => "Michael" > user["last_name"] = "Hartl" => "Hartl" > user["first_name"] => "Michael" > user => {"first_name"=>"Michael", "last_name"=>"Hartl"} > user = { "first_name" => "Michael", "last_name" => "Hartl" } => {"last_name"=>"Hartl", "first_name"=>"Michael"}
- シンボルとはコロンが前に置かれている文字列
- 文字列と似ているが異なる
- Railsでは文字列よりもシンボルを使用する
- 文字列と違って全ての文字が使えるわけではない
- ハッシュもeachメソッド
> "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 = { :name => "Michael Hartl", :email => "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} > user[:name] => "Michael Hartl" > user[:password] => 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 > 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"
その他
app/views/layouts/application.html.erb
に書かれている以下の2行は色々な要素が省略されているのに注意!
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' } # htmlだとこうなります <link data-turbolinks-track="true" href="/assets/application.css" media="all" rel="stylesheet" />
railsチュートリアル4章の演習問題
演習
<問題1>
city変数に適当な市区町村を、prefecture変数に適当な都道府県を代入してください。
<回答1>
prefecture = "岡山県" => "岡山県" city = "倉敷市" => "倉敷市"
<問題2>
先ほど作った変数と式展開を使って、「東京都 新宿区」のような住所の文字列を作ってみましょう。出力にはputsを使ってください。
<回答2>
> puts prefecture + " " + city 岡山県 倉敷市 > puts "#{prefecture} #{city}" 岡山県 倉敷市
<問題3>
上記の文字列の間にある半角スペースをタブに置き換えてみてください。(ヒント: 改行文字と同じで、タブも特殊文字です)
<回答3>
> puts "#{prefecture} \t #{city}" 岡山県 倉敷市
<問題4>
タブに置き換えた文字列を、ダブルクォートからシングルクォートに置き換えてみるとどうなるでしょうか?
<回答4>
> puts '#{prefecture} \t #{city}' #{prefecture} \t #{city}
演習
<問題1>
"racecar" の文字列の長さはいくつですか? lengthメソッドを使って調べてみてください。
<回答1>
> "racecar".length => 7
<問題2>
reverseメソッドを使って、"racecar"の文字列を逆から読むとどうなるか調べてみてください。
<回答2>
> "racecar".reverse => "racecar"
<問題3>
変数sに "racecar" を代入してください。その後、比較演算子 (==) を使って変数sとs.reverseの値が同じであるかどうか、調べてみてください。
<回答3>
> s = "racecar" => "racecar" irb(main):013:0> s == s.reverse => true
<問題4>
リスト 4.9を実行すると、どんな結果になるでしょうか? 変数sに "onomatopoeia" という文字列を代入するとどうなるでしょうか? ヒント: 上矢印 (またはCtrl-Pコマンド) を使って以前に使ったコマンドを再利用すると一からコマンドを全部打ち込む必要がなくて便利ですよ。)
<回答4>
> puts "It's a palindrome!" if s == s.reverse It's a palindrome! => nil > s = "onomatopoeia" => "onomatopoeia" > puts "It's a palindrome!" if s == s.reverse => nil
演習
<問題1>
リスト 4.10のFILL_INの部分を適切なコードに置き換え、回文かどうかをチェックするメソッドを定義してみてください。ヒント: リスト 4.9の比較方法を参考にしてください。 ※回文・・・上から読んでも下から読んでも、同じ言葉になる文句
<回答1>
> def palindrome_tester(s) > if s == s.reverse > puts "It's a palindrome!" > else > puts "It's not a palindrome." > end > end
<問題2>
上で定義したメソッドを使って “racecar” と “onomatopoeia” が回文かどうかを確かめてみてください。1つ目は回文である、2つ目は回文でない、という結果になれば成功です。
<回答2>
> palindrome_tester("racecar") It's a palindrome! => nil > palindrome_tester("onomatopoeia") It's not a palindrome. => nil
<問題3>
palindrome_tester("racecar")に対してnil?メソッドを呼び出し、戻り値がnilであるかどうかを確認してみてください (つまりnil?を呼び出した結果がtrueであることを確認してください)。このメソッドチェーンは、nil?メソッドがリスト 4.10の戻り値を受け取り、その結果を返しているという意味になります。
<回答3>
> palindrome_tester("racecar").nil? It's a palindrome! => true > if palindrome_tester("racecar").nil? > puts "TRUE" > end It's a palindrome! TRUE
演習
<問題1>
文字列 “A man, a plan, a canal, Panama” を ", " で分割して配列にし、変数aに代入してみてください。
<回答1>
> a = "A man, a plan, a canal, Panama".split(",") => ["A man", " a plan", " a canal", " Panama"]
<問題2>
今度は、変数aの要素を連結した結果 (文字列) を、変数sに代入してみてください。
<回答2>
> s = a.join => "A man a plan a canal Panama"
<問題3>
変数sを半角スペースで分割した後、もう一度連結して文字列にしてください (ヒント: メソッドチェーンを使うと1行でもできます)。リスト 4.10で使った回文をチェックするメソッドを使って、(現状ではまだ) 変数sが回文ではないことを確認してください。downcaseメソッドを使って、s.downcaseは回文であることを確認してください。
<回答3>
> s.split(" ") => ["A", "man", "a", "plan", "a", "canal", "Panama"] > s.split(" ").join => "AmanaplanacanalPanama" > s_down = s.downcase => "amanaplanacanalpanama" > s_down == s_down.reverse => true
<問題4>
aからzまでの範囲オブジェクトを作成し、7番目の要素を取り出してみてください。同様にして、後ろから7番目の要素を取り出してみてください。(ヒント: 範囲オブジェクトを配列に変換するのを忘れないでください)
<回答4>
> az = ("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"] > az[7 - 1] => "g" > az[-7] => "t"
演習
<問題1>
範囲オブジェクト0..16を使って、各要素の2乗を出力してください。
<回答1>
> (0..16).map {|i| puts i ** 2} 0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256
<問題2>
yeller (大声で叫ぶ) というメソッドを定義してください。このメソッドは、文字列の要素で構成された配列を受け取り、各要素を連結した後、大文字にして結果を返します。例えばyeller([’o’, ’l’, ’d’])と実行したとき、"OLD"という結果が返ってくれば成功です。ヒント: mapとupcaseとjoinメソッドを使ってみましょう。
<回答2>
> def yeller(array) > puts array.join.upcase > end => :yeller > yeller(%w(o l d)) OLD
<問題3>
random_subdomainというメソッドを定義してください。このメソッドはランダムな8文字を生成し、文字列として返します。ヒント: サブドメインを作るときに使ったRubyコードをメソッド化したものです。
<回答3>
> def random_subdomain > ('a'..'z').to_a.shuffle[0..7].join > end => :random_subdomain > random_subdomain => "ikzbpahe"
<問題4>
リスト 4.12の「?」の部分を、それぞれ適切なメソッドに置き換えてみてください。ヒント:split、shuffle、joinメソッドを組み合わせると、メソッドに渡された文字列 (引数) をシャッフルさせることができます。
<回答4>
> def string_shuffle(s) > s.split("").shuffle.join # splitに「""」を渡すと1文字ずつ分割してしてくれる > end > string_shuffle("foobar") => "oobfra"
演習
<問題1>
キーが’one’、’two’、’three’となっていて、それぞれの値が’uno’、’dos’、’tres’となっているハッシュを作ってみてください。その後、ハッシュの各要素をみて、それぞれのキーと値を"’#{key}’のスペイン語は’#{value}’"といった形で出力してみてください。
<回答1>
> hash => {:one=>"uno", :two=>"dos", :three=>"tres"} * hash.each do |k,v| * puts "#{k}のスペイン語は#{v}です" > end oneのスペイン語はunoです twoのスペイン語はdosです threeのスペイン語はtresです => {:one=>"uno", :two=>"dos", :three=>"tres"}
<問題2>
person1、person2、person3という3つのハッシュを作成し、それぞれのハッシュに:firstと:lastキーを追加し、適当な値 (名前など) を入力してください。その後、次のようなparamsというハッシュのハッシュを作ってみてください。1.) キーparams[:father]の値にperson1を代入、2). キーparams[:mother]の値にperson2を代入、3). キーparams[:child]の値にperson3を代入。最後に、ハッシュのハッシュを調べていき、正しい値になっているか確かめてみてください。(例えばparams[:father][:first]がperson1[:first]と一致しているか確かめてみてください)
<回答2>
> params[:father] = person1 => {:first=>"nakano", :last=>"taku"} > params[:mother] = person2 => {:first=>"nakano", :last=>"haku"} > params[:child] = person3 => {:first=>"nakano", :last=>"toma"} > params[:father][:first] == person1[:first] => true > params[:mother][:first] == person2[:first] => true > params[:child][:first] == person3[:first] => true
<問題3>
userというハッシュを定義してみてください。このハッシュは3つのキー:name、:email、:password_digestを持っていて、それぞれの値にあなたの名前、あなたのメールアドレス、そして16文字からなるランダムな文字列が代入されています。
<回答3>
> user = {} => {} > user[:name] = "Taku" => "Taku" > user[:email] = "kosmo.waizu0804@gmail.com" => "kosmo.waizu0804@gmail.com" > > user[:password_digest] = ("a".."z").to_a.shuffle[0..15].join => "fpnewraocjbhustg" > user => {:name=>"Taku", :email=>"kosmo.waizu0804@gmail.com", :password_digest=>"fpnewraocjbhustg"}
<問題4>
Ruby API (訳注: もしくはるりまサーチ) を使って、Hashクラスのmergeメソッドについて調べてみてください。次のコードを実行せずに、どのような結果が返ってくるか推測できますか? 推測できたら、実際にコードを実行して推測があっていたか確認してみましょう。
<回答4>
> { "a" => 100, "b" => 200 }.merge({ "b" => 300 }) => {"a"=>100, "b"=>300}
railsチュートリアル4章の気になる!
その他メモ
- 新しいブランチの作り方
$ git checkout -b rails-flavored-ruby Switched to a new branch 'rails-flavored-ruby' $ git branch master * rails-flavored-ruby
第4章まだ途中ですが、ここで一度アップ!
1万文字超えてるではないか...
ユニクロではなく無印良品を選ぶ3つの理由
こんにちは。opiyoです。
岡山は今梅雨入り初めての雨が降っていますが、「晴れたらやりたいこと」は何でしょうか?
私は熱狂的なユニクロファンで赤色の靴下、パンツ、ジーパン、Tシャツ、パーカー全てがユニクロです。
先日痛くないハイヒールを作っている「瀧見サキ」さんの記事を書きましたが、この瀧見サキさんの格好が個人的にはドストライクで、めちゃくちゃ格好良いのですよ。
これ、無印っぽいので久しぶりに岡山イオンの無印良品に遊びに行ったのですが、そこには僕の知らないアイテム達が待ち構えていました
VネックTシャツ 2枚組(1490円)
無印良品って昔は多分Uネックしかなかったんじゃないかなぁ。
https://www.muji.net/store/cmdty/detail/4549738732082?searchno=11
タンクトップ 2枚組(1490円)
タンクトップも昔は無印良品なかったんじゃないかなぁと思うんだけど、自信ないな。
今はビックシルエットが流行ってるから旨味がないかもだけど、白のTシャツ着るときはグレーのタンクトップ着て1cmくらいTシャツから飛び出して見せると全体が引き閉まるからオススメです!
https://www.muji.net/store/cmdty/detail/4549738536451?searchno=1
ポケット付きTシャツ
通販サイトでは見つからなかった。こういうちょっとオシャレなものって全然なかったと思うんだど。どうだろうか。
これは普通にメンズだけじゃなくてレディースもいけると思う。
オシャレコーデ
WEAR
無印良品は間違いなく今後くる〜
昔から無印は好きだったのですが、2つ気にくわないところがありました
- 種類がが少なすぎる。
- 高い
例えばTシャツならUネックしかないとかだったけど、ご覧の通り。これだけ種類があれば満足する方結構いると思う。
あとは値段だけど、この前各アイテム値下げを発表みたいな記事読んだのでもう少し安くなるかも。
こーなってくると、高いから無印良品は買わないって人多かったと思うけど値段が同じならば無印良品で買うって人は出てくると思う。
何となく無印良品の方が高いブランドイメージ付いてるし。多分…
ということで今日はここまで。
22歳でパパになって良かったと思うこと/思わないこと
こんちには。opiyoです。
昨日ですかね、私が尊敬している元リクルートで副業家の西村さんがNEW PEACE代表の高木新平さんの記事を見て書いたというブログを見ました。
内容は簡単に言うと「若くして家族を持つことも悪くないよ!」って話だとぼくは解釈しました。
ぼくも22歳で結婚。次の年には長男が生まれ、その次の年には長女が生まれました。
全く同じでは無いですが、とても近い状況な僕にとっては改めて「家族」について考えるきっかけになりました。
みんな違って、みんないい。
こんな言葉があったような気がしますが、こんな感じになりそうです。
良かったと思うこと
仕事の第一次ピークに全力になれる
仕事の第一次ピークは、33〜38歳にやってくる
子育てがひと段落した状態で「仕事の第一次ピーク」を迎えられる
高木さんの記事では、仕事の第一次ピークは、33〜38歳と書かれています。
僕は今27歳。8月で28歳になる。
つまり、仕事の第一次ピークを迎えるのは5年後、2022年頃には
- 長男・・・10歳(小4)
- 長女・・・9歳(小3)
僕が30歳になる2年後であっても長男は小1、長女は年長になるので、この頃にはほとんど手はかからなくなりそうです。
これは、良い点ですね。いざという時に全力で走れます。
一番体力がある時に子育てができる
仕事の先輩、幼稚園パパを見るとやっぱり僕の優位は明らかです。
偉そうなこと言ってごめんなさい。でも、これだけは自信をもって子供たちに誇れるポイントです。
僕自身が3人目として生まれたので周りに比べると僕の両親はジジババでした。
なので公園行って走り回った記憶も無いです。唯一の楽しみはキャッチボールでした。
だから若い!ってのはそれだけで子どもと一緒に遊ぶ体力があるので良い事ばかりです。
コミュニティができる
子どもがいると幼稚園、習いごとなど絶対に繋がらないであろう人達と交流ができるってのは間違いなく良い所だと思います。
良くないなと思ったこと
20代という一番楽しい時間を自分だけに使う事ができない
もーこれです。 羨ましいに決まってるじゃないですか。何を強がっているのか。
僕が結婚した前後くらいから皆がiphone持つようになって今みたいな何処とでも繋がっている素晴らしい世界になってきました。そんな状況にも関わらず家と会社を往復する日々。自分に使う時間ってよりかはお金が無いので何も出来ない。そんな状況です。
旅したい。カメラ欲しい。遊びたい。
残念ながら今はできません。
周りの方が経済的に豊か
当たり前ですが皆さん僕より年上です。一回りも違う人だっています。ですから当たり前のように家があるから遊びに行って帰ってくると子どもは「なぜうちは階段が無いのか」聞いてくる。これは結構きついですよ。
待ってろよ。絶対どうにかしてやるからな。
みんな違って、みんな良い
よかったこと、よくないなと思ったこと自分なりに整理してきました。
結局ぼくは何が言いたいのだろうか。正直良く分かりません。
だけど、僕が歩んできた道に後悔はありません。家族には本当に感謝しています。
ありがとうね。
ということで「みんな違って、みんな良い」
あの人がこうだから…ではなくて、自分が良いと思える道をきちんと選んで生きていきましょう。
Ruby on Rails チュートリアルで30歳までに人生を変える(第3章)
こんちには、opiyoです。
人生の生き残りをかけて始めた「Railsブートキャンプ」ですが、今日はRailsチュートリアル第3章をやっていこうと思います。
railsチュートリアル 3章の流れ
静的なページのセットアップ
繰り返しの復習は大事です。人間はすぐに忘れてしまう動物なので。
改めてrails new
して最低限のところまでを作ります!
https://railstutorial.jp/chapters/static_pages?version=5.0#sec-sample_app_setup
$ rails _5.0.0.1_ new sample_app
- Gemfileをいじります
source 'https://rubygems.org' gem 'rails', '5.0.0.1' gem 'puma', '3.4.0' gem 'sass-rails', '5.0.6' gem 'uglifier', '3.0.0' gem 'coffee-rails', '4.2.1' gem 'jquery-rails', '4.1.1' gem 'turbolinks', '5.0.1' gem 'jbuilder', '2.4.1' group :development, :test do gem 'sqlite3', '1.3.11' gem 'byebug', '9.0.0', platform: :mri end group :development do gem 'web-console', '3.1.1' gem 'listen', '3.0.8' gem 'spring', '1.7.2' gem 'spring-watcher-listen', '2.0.0' end group :test do gem 'rails-controller-testing', '0.1.1' gem 'minitest-reporters', '1.1.9' gem 'guard', '2.13.0' gem 'guard-minitest', '2.4.4' end group :production do gem 'pg', '0.18.4' end # Windows環境ではtzinfo-dataというgemを含める必要があります gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
$ bundle install --without production
- エラーが出たら
$ bundle update
する
- エラーが出たら
git
を使ってsample_app
をバージョン管理下にする- トップページ(hogehoge.com/)に
hello world
を表示されるようにコードを修正する heroku
の設定を行いpush
しますheroku open
してhello world
が表示されればOK
git
とheroku
の設定はチュートリアルを見ずにやってみることで、覚えているかの復習になりますね!
コントローラーの作り方
- 表記はキャメルケース = 単語の先頭を大文字になる(StaticPages)
- アクション名は全て小文字にする
- 出来上がるコントローラーファイル名はスネークケース = 単語をアンダーバー
_
でつなぎ合わせた名前になる
$ rails g controller StaticPages home help # コントローラー名 アクション名ですね create app/controllers/static_pages_controller.rb # 出来上がったコントローラーのファイル route get 'static_pages/help' route get 'static_pages/home' invoke erb create app/views/static_pages create app/views/static_pages/home.html.erb create app/views/static_pages/help.html.erb invoke test_unit create test/controllers/static_pages_controller_test.rb invoke helper create app/helpers/static_pages_helper.rb invoke test_unit invoke assets invoke coffee create app/assets/javascripts/static_pages.coffee invoke scss create app/assets/stylesheets/static_pages.scss
- routes.rbが自動的に更新される
Rails.application.routes.draw do get 'static_pages/home' # 自動的に追加されたよ get 'static_pages/help' # 自動的に追加されたよ root 'application#hello' end
このgetは、/static_pages/home/
というURLでアクセスされたら、static_pages
コントローラーのhome
アクションと結びつく設定になります。
テスト駆動開発 (TDD)
考え方
テストの手法のひとつで、最初に「正しいコードがないと失敗するテスト」を書き、次に本編のコードを書いてそのテストがパスするようにする考え、やり方かな。
テストをするメリットはチュートリアルのコラムの中で書かれてますが、引用します。
さらに詳細までみたいな場合は、こちらからどうぞ(コラム3-3.です)
https://railstutorial.jp/chapters/static_pages?version=5.0#sec-custom_static_pages
当たり前ですが、何か問題があるとお客様に迷惑をかけます。それは本当に申し訳無いところなのですが、お客様以外のところで凄く面倒なことになります。
だからテストを書くのです。もーこれだけ。
テストコードの書き方
テストコードはrails g controller
を実行した時点で作成されます。
require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest test "should get home" do get static_pages_home_url assert_response :success end end
これを日本語で表すと、「Homeページのテスト。GETリクエストをhomeアクションに対して発行 (=送信) せよ。そうすれば、リクエストに対するレスポンスは[成功]になるはず。」となります。
テストの実行方法は
$ rails test # Running: .. Finished in 1.467940s, 1.3625 runs/s, 1.3625 assertions/s. 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
0 errorsとなっているので、成功(GREEN)したことが分かりますね。
もしエラーになる場合は、こちらに回避方法書いたので参考にしてください。 opiyotan.hatenablog.com
このように、テストと一緒にコードを書いていくことが最近は推奨されています。
3.3.1では、TDDの考えに基づき失敗するエラーを書いて成功させリファクタリングするという流れでテストする方法が乗っていますので是非チャレンジしてみてください。
動的にタイトルを変更する
先ずは各ページのタイトルをチェックするテストを書きます。
もちろん、view
のtitle
タグは何も変更していないのでエラー(RED)になります。
require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Home | Ruby on Rails Tutorial Sample App" # ここ追加しました。"title"タグに書かれた文字列をチェックするテストです end end
では、次にview
のtitle
タグを修正していきます。始めにapp/views/static_pages/home.html.erb
ファイルから。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Home | Ruby on Rails Tutorial Sample App</title> # この部分ですね </head> <body> <h1>Sample App</h1> <p> This is the home page for the <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a> </p> </body> </html>
この状態でテストを実行するとhome
アクションについては修正したのでエラーじゃなくなりますが他の2つのアクションがエラーになります
$ rails test # Running: Failure: StaticPagesControllerTest#test_should_get_about [/Users/taku/rails/railstutorial/sample_app/test/controllers/static_pages_controller_test.rb:19]: <About | Ruby on Rails Tutorial Sample App> expected but was <SampleApp>.. Expected 0 to be >= 1. bin/rails test test/controllers/static_pages_controller_test.rb:16 Failure: StaticPagesControllerTest#test_should_get_help [/Users/taku/rails/railstutorial/sample_app/test/controllers/static_pages_controller_test.rb:13]: <Help | Ruby on Rails Tutorial Sample App> expected but was <SampleApp>.. Expected 0 to be >= 1. bin/rails test test/controllers/static_pages_controller_test.rb:10 Finished in 0.649278s, 4.6205 runs/s, 9.2410 assertions/s. 3 runs, 6 assertions, 2 failures, 0 errors, 0 skips
なので、エラー(RED)にならないようhelp
とabout
も修正し成功(GREEN)させます。
リファクタリング
今までは全てのview
ファイルに直接title
タグを書き込んでいました。なので当然表示されるタイトルも変わってきます。
これらを今テストでやったように共通にできるところは共通化し、違う部分だけを設定するように修正していきます。
このように同じコードを繰り返し書かないようにする考え方を「DRY(Don’t Repeat Yourself: 繰り返すべからず) 」と言います。
では早速やってみます。先ずは各ページに動的に変更する部分を書いていきます。
app/views/static_pages/home.html.erb
<% provide(:title, "Home") %> # 各ビュー毎に文字列をセットする <!DOCTYPE html> <html> <head> <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title> # 設定した文字列をyield関数を使って反映させる </head> <body> <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> </body> </html>
次に共通のビューになるapplication.html.erb
のtitle
をyield
関数を使って表示されるようにします
<!DOCTYPE html> <html> <head> <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</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 %> # ここで各ページを読み込んでいるから、各ビューでは`head`タグとかがいらないんですね </body> </html>
それぞれのページでは違う処理だけ書く。共通部分はapplication.html.erb
で定義する!!
<% 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>
railsチュートリアル 3章の演習問題
3.1 演習
問題1
BitbucketがMarkdown記法のREADME (リスト 3.3) をHTMLとして正しく描画しているか、確認してみてください。
回答1
ぼくは、githubで作業しているのですが問題なく描画されていますね。
- h1は大きな文字
- h2は少し大きな文字
- リンクは青色で
- コード部分は灰色になる
https://github.com/nakanoTaku/railstutorial_3
問題2
本番環境 (Heroku) のルートURLにアクセスして、デプロイが成功したかどうか確かめてみてください。
回答2
hello worldが表示されているのでOKですね!
heroku logs
でログを見ることも出来ます。
3.2.1 演習
問題1
Fooというコントローラを生成し、その中にbarとbazアクションを追加してみてください。
回答1
$ rails g controller Foo bar baz class FooController < ApplicationController def bar end def baz end end
問題2
コラム 3.1で紹介したテクニックを駆使して、Fooコントローラとそれに関連するアクションを削除してみてください。
回答2
$ rails destroy controller Foo bar baz
3.4.2 演習
テストを一部リファクタリングします。
3つのアクションで同じように使われている文字列「Ruby on Rails Tutorial Sample App」を変数に代入し、使い回すようにします。
require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest def setup @base_title = "Ruby on Rails Tutorial Sample App" # setupというテストが実行される前に処理されるメソッド内で文字列を変数にセットしておきます。 end test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Home | #{@base_title}" # 変数を参照するように修正します。 end end
3.4.4 演習
問題1
リスト 3.41にrootルーティングを追加したことで、root_urlというRailsヘルパーが使えるようになりました (以前、static_pages_home_urlが使えるようになったときと同じです)。リスト 3.42のFILL_INと記された部分を置き換えて、rootルーティングのテストを書いてみてください。
回答1
test "should get root" do get root_url assert_response :success end
問題2
実はリスト 3.41のコードを書いていたので、先ほどの課題のテストは既に green になっているはずです。このような場合、テストを変更する前から成功していたのか、変更した後に成功するようになったのか、判断が難しいです。リスト 3.41のコードがテスト結果に影響を与えていることを確認するため、リスト 3.43のようにrootルーティングをコメントアウトして見て、 red になるかどうか確かめてみましょう (なおRubyのコメント機能については4.2.1で説明します)。最後に、コメントアウトした箇所を元に戻し (すなわちリスト 3.41に戻し)、テストが green になることを確認してみましょう。
回答2
ちゃんとREDになるし、GREEMにもなる
railsチュートリアル 3章で学んだこと
テストをパワーアップする
minitest reporters
テストの成功(RED)失敗(GREEN)の見栄えをよくしてくれます。
準備するのはこれだけ、是非試してみてください!
# ファイル名:test/test_helper.rb ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' require "minitest/reporters" Minitest::Reporters.use! class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all # Add more helper methods to be used by all tests here... end
Guard
ファイルの変更を検出して必要なテストだけを自動実行してくれるそうです。
例えば、「home.html.erbファイルが変更されたらstatic_pages_controller_test.rbを自動的に実行する」といったことをGuardで設定することができます。
これヤバいですね。今はまだ変更するファイルも少ないですし何をしたか全部記憶できるくらいしかないですが絶対面倒になって忘れますよね。
詳細な設定方法はRailsチュートリアルを参照してください。
https://railstutorial.jp/chapters/static_pages?version=5.0#sec-guard
手順だけ簡単にまとめておきます。
- 初期化
$ bundle exec guard init
初期化を実行すると、「/Guardfile」が作成されます。
- Guardfileを編集する
- .gitignoreにSpringを追加する
- Guardの実行
$ bundle exec guard
なんか実行すると「Ctrl + D」か「テストが成功」するまで終わらないのだけど、これは正しい動きなのか?
ずっとバックグラウンドで動かしておいて、常に監視させておくってことなのかな...
あーすごい便利かなーと思ったけど、これは使わないかもしれない。邪魔っちー
httpメソッド
HTTP (HyperText Transfer Protocol) には4つの基本的な操作があり、それぞれGET、POST、PATCH、DELETEという4つの動詞に対応づけられています。クライアント (例えばFirefoxやSafariなどのWebブラウザ) とサーバー (ApacheやNginxなどのWebサーバー) は、上で述べた4つの基本操作を互いに認識できるようになっています
- get
主にWeb上のデータを読み取る (get) ときに使われるリクエストです。
- post
ページ上のフォームに入力した値を、ブラウザから送信する時に送られるリクエストです。
gitでaddとcommitを一回でやる!
$ git commit -am "Improve the README"
herokuへpushした時に何かエラー
$ heroku logs
新しいブランチの作り方
$ git checkout -b hogehoge
今チェックアウトしているブランチは?
$ git branch master * static-pages
ブランチを指定してpushするには?
$ git push origin hogehoge
rails g をやり直したい!
$ rails destroy controller StaticPages home help $ rails destroy model User
Unixプロセスの確認
$ ps aux $ ps aux | grep spring $ ps aux | grep spring taku 7781 0.0 0.2 2518224 19900 ?? S 5:23PM 0:00.42 spring server | sample_app | started 31 mins ago taku 8561 0.0 0.0 2423376 216 s003 R+ 5:55PM 0:00.00 grep spring taku 7782 0.0 0.9 2577420 73224 ?? Ss 5:23PM 0:02.75 spring app | sample_app | started 31 mins ago | test mode $ spring stop $ ps aux | grep spring taku 8604 0.0 0.0 2434840 804 s003 S+ 5:57PM 0:00.00 grep spring # 「7781」「7782」が無くなった!
railsチュートリアル 3章のまとめ
3章ではテスト駆動開発 (TDD)に沿って、開発を進めてきました。 簡単にまとめるこんな感じでしょうか?
- 何事も繰り返し行うことで覚えることができる
rails new
git init
~git push
までの流れ
rails g controller ControllerName アクション名
でコントローラーが作れる- RailsのビューはRubyのコードが使える
- テスト駆動開発 (TDD)は、「RED」「GREEN」「REFACTOR」のサイクルを繰り返して開発をすることだ
では、最後にぼくが一番尊敬している先輩エンジニアからの名言でお別れしましょー
テストコードが仕様書だ