日本語版Rails Tutorialhttps://railstutorial.jp/
を運営しているYassLabさんが講師!
たった5日間であの長いRails Tutorialを完走する集中講座に参加しています。
https://coedo-dev.doorkeeper.jp/events/72968
講義でやったことと、その後ぼくが気になってぐぐったことが混ざって書かれてますがご愛嬌。
第4章 Rails風味のRuby〜全てはオブジェクト〜
昨日のAWSのご機嫌斜めだったエラーの話
詳細は特定できてないが、
複数のCloud9を開いていると起こりやすいエラーだったとか。
Rubyに詳しいと何が嬉しいか。
下のような処理をちょちょいと書けちゃう。
ちょっと動的なタイトル。
Home | をとっちゃう。
で、先にテスト書く。
GREEN→テスト書いてRED→fixしてGREEN
で、いい感じにラップする helperってやつを作る
app/helper/
irbの設定(リスト4.8)
Rubistはpryを使う。なんか色つけがいい感じ。
Rails consoleをpry風にするやつもある。
gem 'pry-rails' を入れよう。
詳しくはhttps://qiita.com/silmisilon/items/8e08435204d8d08d09ff
+演算子の正体
ただのエイリアス。String#+ってメソッドがあるのだ!
https://docs.ruby-lang.org/ja/search/query:%2B/
"文字列".+("文字列") #stringに定義されているプラスメソッド。
"文字列" +("文字列") #ドットは省略できる!
"文字列" + "文字列" #かっこすら省略できる!!
おほー。
「bashではif
でも?
でも[
でもコマンドなんだよ!」って言われた時のような
不思議な感覚になった。
調べてみた
==もメソッド
(いろんなクラスについてる 1==1.0はtrue)
https://docs.ruby-lang.org/ja/search/query:integer/query:%3D%3D/#entry-0
if,forとかは制御構造の予約語。コレはオブジェクトではないらしい
https://docs.ruby-lang.org/ja/search/query:keyword/query:end/type:document/
式展開
"#{hogehoge} + #{fugafuga}"
シングルクォーテーション
'#{hogehoge} + #{fugafuga}'
式展開しない! ¥n
とかも改行にしない。
(個人開発なら式展開をしたいとき以外は'を使う癖をつけたほうがいいかな。)
純粋なオブジェクト指向言語って意味
"foo"
=> "foo"
"foo"って書くと、文字列"foo"ってオブジェクトを渡す。
文字列のプラスメソッドを使って連結すると、連結された文字列が返ってくる。
"foo".+("bar")
=> "foobar"
さらにメソッドチェーンしていくと。
"foo".+("bar").length
=> 6
"foo".+("bar").length.to_s
=> "6"
じつはendもオブジェクト。なんじゃそりゃ
推測できることの大事さ。
empty?なメソッド名なら、
絶対booleanが来るだろ?
空だったらtrueになるんだろ?って類推できることが大事。
returnは書いても書かなくてもいいよ
最後に評価されたものが返る。
なぜ後置if文が作られたか?
なるべく、人間が読みやすく設計した。
ぼくらの思考の順番的に。より自然言語に近い。
unlessとか。
(Rubyは異常って言っていいほど自然言語(英語)に近づこうとする執念がある、と個人的に思ってる。
2.years.ago
みたいなのが衝撃だった。)
範囲・範囲演算子
splitで配列になるよ
"foo bar buz".split
=>["foo","bar","buz"]
配列の最後をとりたいなら
a[-1]
a.last
a.lastって書き方の方が一般的。
a.sort
a.sort!
の違い
メソッド末の!(bang)は破壊的メソッド。不可逆な変更を加えていく。
配列に数字と文字列をまぜる
a = [1, 2, 5, 18, "hoge", "fuga"]
a.sort #error
例外投げてくれる。
範囲演算子
range = (1..10)
ary = range.to_a #これはOK
range = (10..1) #ここで例外でるわけじゃないけど
=>10..1
range.to_a #これはできない。
=>[] #からっぽの配列
(1..10).to_a.reverse #これならできる
=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
順番は小さい数から大きい数へ一方通行。
-1を配列の範囲で使うと、配列の終わりまでいく。
('a'..'z')もできるよ。
文字列だと並び替えが数値と違うので注意。
ary = ["7","8","9","10","11","12"]
ary.sort
=> ["10", "11", "12", "7", "8", "9"]
ary.sort_by{|s| s.to_i } #これならできる
=> ["7", "8", "9", "10", "11", "12"]
範囲演算子は()で囲った方がいい理由
1..9.to_a #error
Rubyでは
1..(9.to_a)を実行しようとしてエラーになる。
(1..9).to_a なら勿論問題なく動作する。
ブロック付きメソッド
よくある例
(1..10).each {|i| puts i**2}
for文を過去のものにするメソッド
(Javaでも、もう素のforを回すことは少なくなったよね)
eachの可能性
map
select
reject
(Javaもパクったやつですね)
ブロック
Rubyのソースコードを渡すのがブロック。
制御文とかの進化版?ってイメージ?
二行以上なら do endで
一行で書くなら { }
なんでブロックとか作ったのか
rubyの設計思想。
人間が想像できることは簡単に書きたい。
自分たちでも定義したりオーバーライドしたりしたい。
3.times do {...}
じつはあんま使わないけど、単純に回数指定したいとき。
ぼっち演算子
map&.(:downcase)
みたいなの。&. がぼっちに見える。
mapがnilで無いならmap.downcaseをtryするって意味らしい。
http://sakurawi.hateblo.jp/entry/2017/09/09/%E3%80%90RubyonRails%E3%80%91try%E3%81%A8try%21%E3%81%AE%E9%81%95%E3%81%84%E3%80%90%E3%81%BC%E3%81%A3%E3%81%A1%E6%BC%94%E7%AE%97%E5%AD%90%26_%E3%81%A8%E3%81%AF%E3%80%91#%E3%81%BC%E3%81%A3%E3%81%A1%E6%BC%94%E7%AE%97%E5%AD%90
知ってると早く書けるよ!ってネタがRubyはめちゃくちゃ多い。
生産性の差がそういうことの積み重ねでついてくる。
シンボルのお話
縦長なタンスのイメージ。引き出しの中にvalueがある。
引き出しは普段閉じててkeyが見える位置に貼ってある。
key | value |
---|---|
name | kugyu10 |
kugyu10@example.com |
Rubyのシンボルはマジでなんでもいい
数字、文字列はもちろん、trueとかnilでもいい!?
人間的には
user['name']
user['email']
がすげー分かりやすい。
なぜなら、タンスあけなくてもかなりの部分を 推測 できるから。
user[1]
user[2]
のがコンピューターには楽。
文字列は作るたんびにobject_idがふられるため
まずその文字列を見るのに一手間増える。
数字はいつでも同じ。
keyは文字列で書くべきか、数値で書くべきか。
この戦争(笑)に終止符を打ったのがシンボル
"name".object_id
を連打してみると毎回変わる。
そこを両者をいい感じに橋渡しするのがシンボルというオブジェクト。
:name.object_id
これはいつでもおなじ結果になる。
ハッシュの方が早いし、読みやすいし、みんなハッシュ使おうねって話。
but, 今までの話は一般論。
エンジニアとしては、実証してみることが大事。
Rubyもどんどん進化しててあんまり差が無い。
Ruby2.4ではStringは1.27倍遅い?
Ruby2.1のころは2倍くらい差があった?
benchmark-ips ってgemで比較できるらしい(あとで触る)
ModuleとClassの違い
クラス
ActionContollerとか
インスタンスを作ることができる
モジュール
メソッドの塊。ヘルパー。
(つまり、使うのにインスタンスを用意する必要がない)
クラスにモジュールをincludeすることができる。(mix-inって考え方)
Rubyは多重継承はしない。
ので、代わりにモジュールを用意して、
それをincludeすることで、それっぽいことできるよ、ってなって嬉しい。
Rails風味
- blank?メソッドはRubyには無くてRailsにはあるよ。
- .first .lastはあるけど、.second .thirdがあるよ。
組み込みクラス破壊とかは、すごいけど、リスクも伴う。
DHHがRubyでRails作ったのは、Rubyのその自由さが必要だったから。
Rubyはスーパー自由だけど、Railsは、ルールが細かい。
(みんなでRails乗って楽しようぜ!って発想?)
Ruby参考文献
- るりま
- るりまサーチ
- メタプログラミングRuby
第5章 レイアウトを作成する〜フロントエンドって変化速すぎだろjk〜
モックアップ
あると話するとき楽
- header
- container
- footer
の部分。
まずはブランチ
IE対応のマジックコメント
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
今の時代、IEは対応しない!方が逆に親切なんじゃね?ってレベルらしい。
よく使うやつ
- yeild
- link_toタグ
- media: 'all' #4章でやったやつ
- class: 'btn btn-lg' #=> class='btn btn-lg'って属性になる
- image_tag("image.png", alt:"logo") alt属性='logo'で画像
- link_to image_tag(...) って書くこともできる
Railsは画像はここに置く!ってのが決まってる。
assets
assetsにいれておけば、相対パスとかいらないので、楽しよう。
gem でbootstrapいれよう
「多くの人がやりたいって思うことはだいたいgemある」法則が発動する。
railsのメリットの1つ。
PHPとかと違ってFW戦争がないので
やりたいことはだいたいgemにある。
新しくgemをいれてbundle installしたときは、
rails sを立ち上げ直した方がいい。(必要ないこともある)
Q.外部bootstrapテンプレを組み込む時は?
assetsディレクトリはassetsパイプライン(後述)のためにある。
一応それでも、動くと思うけど、venderに入れたほうがいいかも。
大きな理由として、venderが書いたテスト済みのものと、
ぼくらがテスト中・開発中のものを混ぜない方がいい。
何かおかしくなった時、99%はぼくらの書いた部分がおかしいので。
Railsのレイアウトとデザイン あたりで調べるといいかも!
デザインのコツ
- 空白を効果的に使う
- 上下の余白の対称性
- 色とかフォントとか、メリハリつけたい情報を意識する。
- ノンデザイナーズ・デザインブック
- スタンフォード大学「かっこいいデザインのサイトは信用できるサイト」
http://credibility.stanford.edu/guidelines/index.html
http://mono-stock.com/?p=5449(和訳&解説)
『人は見た目で判断できない』と言われるがサイトはその反対で『アクセスしたページの見た目で決まる』
partial。入れ子構造。便利。
CSSは機能ちょっと弱い
ミックスインしたいなー
変数名使いたいなー
ネストしたいなー
それ全部sassでできるよ!
sassとかをコンパイルして生CSSを作る、って形。
で、順番は?
マニフェストファイルに書いて制御する
またはファイルは拡張子を重ねる
hoge.js.erb.coffee
後ろから順に評価していく。
空白を消すmin化とかもassetがやってくれる。
モバイルとかだとこういうの重要。
Q.今流行りのフロントエンドフレームワークは?
A.知らんがな
フロント詳しい人に聞こう。
フロントエンドは変化が速すぎて
Railsでもどんどん変化・仕様変更・依存の切り捨てとかやってるよ。
HTTP/2?
ストリームっていって、1つのコネクションで並列してリク送れたりできるとか。
名前つきルート
こういうやつ
get '/help', to:'static_pages#help'
help_path
help_url
って形でいろんなところに書けるようになる。
統合テスト
rails generate integration_test site_layout
railsガイド
専門用語バンバンだけど、読んでみるといいよ!
- assets
- レンダリング
第6章 ユーザーのモデルを作成する〜ここらへんから1章あたりの重さがハンパない件〜
rails generate controller Users new
Modelでやりたいこと
- ユーザー登録
- DBに永続的に保存したい(通常の変数じゃダメ)
- DBを扱うためにはSQLを学ぶ必要がある・・・orz
- RailsならActionRecordで(ある程度)DBが扱えるよ!やった!
Railsでは型とか書かない(Railsが推測してくれるもの)けど、
DBの世界ではなんでも明示的にやる(とにかく高速が正義の世界だから)
なので、DBと仲良しなModelをgenerateするときも、型を指定する必要がある
(桁数とかはいい感じにやってくれるのだろうか)
rails g model User name:string email:string
上記のコマンドでmigrateが作られるので、 rails db:migrate
を実行すると、
テーブルが作られる。
開発環境はsqliteなので、ファイルダウンロードして
ソフトで開くことができる。
マジックカラム
id, created_at, updated_atはRailsが勝手に追加される。
integerのidが必ず入っている。
(saveしたときにRailsがユニークに自動採番してくれる)
ほかの情報
シーケンスとか、どこまでmigrateしたかとか。
Rails Consoleしてみよう
u = User.new
u.name = "Yohei Yasukawa"
u.email = "yohei@example.com"
すごい!rubyっぽく書ける!SQL臭くない!
ここまでは只の変数。保存しないと消えちゃう。
DBに保存するなら
u.save
と実行すると
(0.1ms) SAVEPOINT active_record_1
SQL (2.7ms) INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "Yohei"], ["created_at", "2018-04-29 07:58:39.400010"], ["updated_at", "2018-04-29 07:58:39.400010"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
とか表示される。
INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "Yohei"], ["created_at", "2018-04-29 07:58:39.400010"], ["updated_at", "2018-04-29 07:58:39.400010"]]
いい感じにSQLを作ってくれてる。
class User <- ApplicationRecord <- ActiveRecord
UserモデルはApplicationRecordを継承してて、
それはActiveRecordをさらに継承している。
ApplicationRecordはrails5.0からできたやつ。
アプリ特有のバリデーションとかはここに書きましょうねってやつ。
u = User.new(name:"hoge",email:"hoge@example.com")
u.save
User.create(name:"2nd", email:"2@example.com")
User.last.destroy
u.update_attributes(:name,"hoge")
# sが無い方はバリデーション飛ばすこともできる
u.update_attribute(:name, "hoge")
とかできる。
destroy
これはDBからDELETEしているだけで、
ApplicationRecord変数自体はのこってる
find(num)
idで検索する。見つかることが期待されてる。
見つからないと エラー がraiseされる。
find_by(name: "hoge")
見つからないと nilを返す。
この違い結構大事。
検証
- 名前が空じゃないか?
- emailは重複していないか?
- emailはフォーマットに従っているか?
- 短すぎない、長すぎない
バリデーションはうっかりが致命傷になることが多いので気をつける。
ここらへんが雑だとosushiになっちゃう。
テスト駆動が有効な好例。
presense, lengthの検証
もうRailsで用意されてて、一行ですむのでガンガン使おう。
しっぱいした時のメッセージ
失敗した時すぐわかるようにしておくの大事。(多分CIとか)
ブラックボックステストの話とか
ソフトウェア工学の話とか
正規表現
ほんとに真面目にやると、500ページ超える。
Rubularhttp://www.rubular.com/で遊ぼう。
[\w+\-.]+@[a-z\d\-.]+\.[a-z]+
# OK
user@example.com
USER@foo.COM
A_US-ER@foo.bar.org
first.last@foo.jp
alice+bob@baz.cn
# NG
user@example,com
user_at_foo.org
user.name@example.
foo@bar_baz.com
foo@bar+baz.com
# NGだけど通っちゃう例
foo@bar..com
Rubyの場合、定数は全部大文字で書く、
正規表現は""で囲わない。
Q.フロントエンドのバリデーションとの住み分けは?
フロントのバリデーションはUXデザイン。
間違ってたら即教えてあげるとユーザー体験の質があがる。(って鉄則がある)
バックエンドのバリデーションはデータ壊れないようにとか、セキュリティとか。
最後の砦はDBのテーブル制約だけど
あれはRailsのバリデーションほど楽に書けないので
Railsで頑張るところが多くなる。
でもDBでやる方がいいものもある↓
DBでやるべき検証(一意性)
まったく同時のタイミングで同じメアドでユーザー登録を試みた時、
Railsでは限界があるのでうまくDBと連携する必要があるよ。
Railsでもuniquness とか書くけど。
DBにindexを貼る
rails generate migration add_index_to_users_email
雛形しか作ってくれないので自分でmigrationを書き足す。
indexは検索を早くするためのものだけど、
一意性が分かるようになるという作用もある。
fixture
MyStringのままなのでバリデーションにひっかかる。全部消すことで対応
case-insensitive
validates :email,
...
uniqueness: { case_sensitive: false }
DBに保存する直前、モデルがdowncaseにしてくれる
before_save { email.downcase! }
これで必ず小文字で保存されるようになる。
セキュアなパスワードを実装する
Railsだと一行で実装が終わる。
has_secure_password
で、このレールに乗るために準備しないといけない条件があるので
それをクリアしよう。
その条件とは、
password_digest
ってカラムを持つこと。
なければgenerateしよう
rails g migration add_password_digest_to_users password_digest:string
rails db:migrate
あと、パスワード最低長の設定は必要。1文字パスワードは流石に、ね。
ハッシュ化って?
同じ文字列なら必ず同じダイジェストになるんだけど、
これから元に戻すことはできない。
DBに入るのはハッシュ値。
万が一DBがクラッキングされても、ここからパスワードに復元できなければ
二次災害は防げる。
ハッシュ化するためにbcryptをいれる
最低長
これはユーザー名のlengthバリデーションと同じ方法でできる。
herokuのmigrate
開発環境でrails db:migrateやったなら
herokuでもやる必要がある。
開発環境とheroku本番環境では接続しているDBが違うので。
heroku run rails db:migrate
エラーでなければこれでOK
今日の感想
速い。めっちゃ進行が速い。
5日で700P攻略するから当然のペースなんだけど。
2週目だし、一周目より大分理解できたかも。
6章だけでもだいぶRailsの凄さが分かる。
現職がJavaの古いオレオレFWの現場なので、DB周りは面倒くさいのよ。
TODO
- gem benchmark あとで試す