Rails controllerで早期return
アプリケーションの規模が大きくなるにつれてcontrollerもfatになってくることが多いと思いますが、 リファクタする際に早期returnを使われる方も多いと思います。 controllerで早期returnをするTipsをまとめました。
Guard Clause(早期return)とは
によると下記のような説明がありました。
ガード (Guard) とは、コンピュータ・プログラミング言語において、条件式ないし条件分岐のような意味を持つもので、ある分岐で処理を続けるために真 (true) と評価されなければならない[1]式である。
つまり、条件分岐や関数の途中、早期に脱出する手段の一つです。ソースコードの可読性が向上し、性能もアップすることが期待されています。「ガード節」、「早期復帰」、「早期リターン」なんて呼んだりすると思います。
controllerで早期リターンするパターン
例に使ってるコード自体に意味はありません。あくまで早期returnの方法を説明することに関心を置いています。
古典的な方法
まずは古典的な方法です。
class UsersController < ApplicationController def show unless @user.logged_in? redirect_to sign_in_path and return end if invalid_user? redirect_to users_path and return end # 何らかの処理 end end
これは古典的な方法だと思います。
ある条件が真だった場合に、redirectさせるために return
を使っています。
メソッド and 早期リターン(パターン2)
次はメソッドに切りだしたパターンです。
class UsersController < ApplicationController def show verify_user and return # 何らかの処理 end private def verify_user unless @user.logged_in? redirect_to sign_in_path and return true end if invalid_user? redirect_to users_path and return true end end end
メソッドに処理を切り出した場合、例えば concerns
などに切り出した処理を置いていろいろな controller で使いたい場合には注意が必要です。
このパターンはメソッド内で return true
しないと新たなバグを生み出す可能性があります。
メソッドに切り出して早期リターンする場合、 true
を返さないと呼び出し元の and
の左辺が偽あつかいになるので処理が途中で中断されません。その場合、 DoubleRenderError
が発生する場合があるので注意です。
verify_user and return
という書き方が直感に反する気がしました。
メソッド or 早期リターン(パターン3)
メソッドに切り出した場合に and
ではなく or
を使うパターンもあります。
class UsersController < ApplicationController def show verify_user or return # 何らかの処理 end private def verify_user unless @user.logged_in? redirect_to sign_in_path and return end if invalid_user? redirect_to users_path and return end return true end end
この場合は、メソッドに切り出したときにメソッドの最後に return true
を追加する必要があります。
しかし、切り出した部分に関しては修正する必要がないので良いですね。
メソッド { return }(パターン4)
次はブロックをとるパターンです。
class UsersController < ApplicationController def show verify_user { return } # 何らかの処理 end private def verify_user unless @user.logged_in? redirect_to sign_in_path and yield end if invalid_user? redirect_to users_path and yield end end end
メソッド内で return
ではなく yield
を使います。ブロックで return
を実行している部分が yield
で実行されます。
これは好みが分かれる書き方かもしれませんね。
メソッド; return if performed?(パターン5)
最後は ActionController::Metal#performed? メソッドを使用するパターンです。
このメソッドは render
あるいは redirect
が実行されているかどうかを判定するメソッドです。
個人的にはこの方法が1番Rails Wayっぽい感じもするけどどうなんでしょう。
class UsersController < ApplicationController def show verify_user; return if performed? # 何らかの処理 end private def verify_user unless @user.logged_in? redirect_to sign_in_path and return end if invalid_user? redirect_to users_path and return end end end
まとめ
controller内で早期returnをする方法を見てきました。 特にメソッドに切り出す必要がない場合は古典的な方法を使うのが1番シンプルですね。
curlオプション備忘録
よくDockerfileとかを書いているときに -sSfL
というオプションを使ったりするのだけれど、よく意味を忘れるのでまとめておこうと思いました。
curl -sSfL https://xxx.com
-s(--silent)
進捗の表示をしない
-S(--show-error)
エラーを表示
-s
オプションはURLが間違っていたり、エラーがあった場合、何も表示しません。
進捗の表示はしたくないけど、エラーがあったら表示したいときには、
-sS
のようにセットで使ってあげると良い。
-L(--location)
リダイレクトする
-f(--fail)
400、500等のエラーの場合、標準出力にエラー文字を出さない
rbenvでRubyを管理する
僕はRubyのバージョン管理に rbenv を使っています。 他のバージョン管理ツールには RVM なんかもありますね。 最近、自宅のPCを新しくして、環境を構築したのでメモがわりに残してます。
何のためにバージョンを管理するか
例えば、ポートフォリオなんかを作成しようと思って、Aというアプリを作ったとします。仮に、そのアプリではrubyのバージョンが 2.5.0
だったとします。
新しくBというアプリはrubyのバージョンを 2.6.5
に上げて作りたいなという状況があったとします。
そんなときに便利なのがrbenvです。
要は一つのrubyバージョンに縛られることがなくなるということですね。
rbenvの導入手順
rbenvのインストール
今回は vi
を使用してログインシェルのファイルに記述していく方法をとります。
~ ❯❯❯ vi ~/.zshrc # bashの方は .zshrc を .bash_profile に置き換えてください
下記のように PATH
と eval
を追記する。
省略 # rbenv path PATH="~/.rbenv/shims:/usr/local/bin:$PATH" eval "$(rbenv init -)" ~ ~ ~ ~ ~ "~/.zshrc" 19L, 452C
ちなみに vi
で編集するときはインサートモードにしなければならないのでファイルを開いた後に I(i)
を押して追記するなりコピペするなりしてください。
編集した後は、インサートモードを解除してあげないといけないので esc
キーを押して :
を押して、 wq
で保存してください。
esc
キーを押した後は、"~/.zshrc" 19L, 452C
の部分にコマンドを打てるようになります。
# rbenv path PATH="~/.rbenv/shims:/usr/local/bin:$PATH" eval "$(rbenv init -)" ~ ~ ~ ~ ~ :wq # 設定の変更を保存する
設定の変更を反映します。
~ ❯❯❯ source ~/.zshrc # bashの方は .zshrc を .bash_profile に置き換えてください
rbenvをインストールします
~ ❯❯❯ brew install rbenv ruby-build
ここまでくると rbenv
コマンドが実行できるようになります。
確認してみます。
~ ❯❯❯ rbenv rbenv 1.1.2 Usage: rbenv <command> [<args>] Some useful rbenv commands are: commands List all available rbenv commands local Set or show the local application-specific Ruby version global Set or show the global Ruby version shell Set or show the shell-specific Ruby version install Install a Ruby version using ruby-build uninstall Uninstall a specific Ruby version rehash Rehash rbenv shims (run this after installing executables) version Show the current Ruby version and its origin versions List installed Ruby versions which Display the full path to an executable whence List all Ruby versions that contain the given executable See `rbenv help <command>' for information on a specific command. For full documentation, see: https://github.com/rbenv/rbenv#readme ~ ❯❯❯
こんな感じになっていたら成功です。 次にインストールできるrubyのバージョン一覧を見てみます。
~ ❯❯❯ rbenv install -l # --list でも実行できます
たくさん数字が書かれたものが表示されたと思います。 後は、インストールしたいrubyのバージョンを指定してコマンドを実行します。
~ ❯❯❯ rbenv install 2.7.0-dev Downloading openssl-1.1.1d.tar.gz... -> https://dqw8nmjcqpjn7.cloudfront.net/1e3a91bc1f9dfce01af26026f856e064eab4c8ee0a8f457b5ae30b40b8b711f2 Installing openssl-1.1.1d... Installed openssl-1.1.1d to /Users/kuritakazuki/.rbenv/versions/2.7.0-dev Cloning https://github.com/ruby/ruby.git... Installing ruby-master... ruby-build: using readline from homebrew Installed ruby-master to /Users/kuritakazuki/.rbenv/versions/2.7.0-dev
インストールするのに若干時間がかかると思います。 最後に忘れずに下記のコマンドを実行すること!
~ ❯❯❯ rbenv rehash # 変更を反映させる
ここまでくるとrubyのバージョンを管理できるようになります。
Ruby技術者認定試験Silverに受かったのでやったことをまとめてみた
先日Ruby シルバーに合格した。
受験するきっかけは、受験しろという上司の半ばパワハラを1年間受けてきてさすがにウザくなってきた事と同僚が公式の一問一答が出てると教えてくれて、解いてみたら割といい点数を取れたことがきっかけ。
基本的に業務でやってることプラス試験用に覚えないとけないメソッドが少しあるといった印象。 Rubyを割とやっていたら受かるんじゃないかなと思った。
やったこと
- 試験本を購入して問題を解く(当たり前)
- 解答は理由を答えられるように
- 絶対出る分野があるのでおさえる
- 一応、合格記事をググって眺める
前提
試験前の僕のスペックは以下の通り。
- Ruby歴2年
- 社会人になってプログラミングを始めた
- 文系大学院卒
- Rubyが初めての学習言語
- IT系の知識はあまりない
- 一応基本情報は持ってる(試験に受かるための勉強しかしてないので身になってない)
学習期間
- 3日
学習期間3日とか書くと再現性低いじゃんと思われるかもしれないが、一応業務でも毎日Rubyを使ってるのでそこそこ知識はある状態。
基本的ことはわかってて普段業務で使う機会に恵まれなかったメソッドたち scan
とか shift
とかを必死に覚えた。
正直3日で受かると思ってなかった。
学習方法
1. 試験本を購入して問題を解く
Ruby技術者認定試験合格教本 という本を買って、巻末についている基礎問題とシルバー用の問題を2回解いた。なぜか僕には基礎問題の方が難しく感じられた。ちなみに1回目解いた際は、基礎問題は19/30問で、シルバー用の問題は37/50問くらい。 試験の概要も記載されているので買って損はないと思う。注意点がいくつかあって、Rubyのバージョンが2.1(試験もこのバージョン)とかなり古いのと誤植が多い。業務では2.5以上のRubyしか扱ったことなかったので、「なんでこの書き方」みたいなところが若干あった。
Ruby技術者認定試験合格教本 Silver/Gold対応 Ruby公式資格教科書
- 作者:増井 雄一郎,小川 伸一郎,株式会社 日立ソリューションズ 牧 俊男
- 発売日: 2015/08/21
- メディア: 単行本(ソフトカバー)
Ruby歴が浅い人はRubyの基本的なことを理解することも兼ねて基本書を一通りやることをオススメします。 僕が新人時代にRubyを勉強した書籍載っけときます。
プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plusシリーズ)
- 作者:伊藤 淳一
- 発売日: 2017/11/25
- メディア: 大型本
チェリー本です。この書籍を通読すればRubyに関してはかなり理解できるんじゃないかと思います。
五十嵐さんの書籍。勉強会でお見かけしたことありますが、物腰柔らかくてすごくいい人そうでした。 図を多く用いていて、視覚的に理解できるような構成になっています。 かなり初心者向けなのである程度知識がある人はチェリー本からやればいいと思います。
2. 解答は理由を答えられるように
上記の問題集をやって、正解した問でも必ずなぜ正解なのかを紙に書き出した。 言わずもがな間違った問題は実際にirbで動かしてみて挙動を確かめる。 これを繰り返していく。無心で筋トレするのと同じ感じで。
やっていくうちに自ずと自分の苦手な分野がわかってくるのでそこを潰していく。受験勉強と似た感じの進め方をやった。 ちなみに僕の場合はIOクラスと組み込み系のクラスのメソッドで細かい挙動を覚えられていないことが弱点だった。
3. 絶対出る分野があるのでおさえる
何回か問題集を解いていくとこういうとこ絶対出るなっていうのがわかってくる。 例えば、
- IOクラス
- String/Array/Hashクラスのインスタンスメソッド
- 演算子の優先順位に関して
- 破壊的or非破壊的か
!
がつかない破壊的なメソッド
- 同じ意味を持つメソッド(mapやcollect等)
- Timeクラス
etc...
4. 一応、合格記事を眺める
最後に勉強方法とか試験の情報を集める意味でも3~4記事くらい眺めてみるのがオススメ。 多分同じようなことが書かれているので自分の勉強方法ややってることが間違ってないと安心できる。心の栄養剤みたいなもんです。
最後に
だいたい問題集と同じような問題が7割くらいは出るんじゃないかという感じだったが、僕が受験した時は sort
に関する問題がやたら出た。業務で使ったことねーわ!!と心の中で憤怒しながらなんとか合格できたのでよかった(試験中は結構間違えた気がしてテンション下がった)。
試験を終えた瞬間にPCに合格か否かが出力されるので受かった時は気分いいけど落ちてたら失うものが大きい(受験料1.6万とその日のテンション)ので十分準備して受験されることをオススメします。3日しか勉強してない僕が言うのもなんですが。
次はGoldとります!