Rspec初心者が使って便利だと思ったRspecオプション

始めまして。 システム事業部の鈴木と申します。

1年間 Ruby on Rails の案件に参画してきましたが、Rails のテストフレームワークであるRspecに触れる機会が多々ありました。
その際に私が初めて使って、とても便利に感じたオプションについて、事例とそれを解消できるオプションについて書いて行きたいと思います。

そもそもオプションとは?

 Rspec を実行する時に指定する便利機能のことです。
$ bundle exec rspec "オプション" "ファイル名等"
 で指定することができます。
 また、.rspecファイルにオプションを書くことで、実行時には
 $ bundle exec rspec
 だけで、.rspecファイルの中のオプションを書いたものとして、実行してくれます。
 .rspecファイルの保存先と 記述例を書いておきます。 ファイル構造
 Railstest
├ Gemfile
├ app
└ .rspec
(要するにGemfileと同じ階層に作成します)

.rspecファイル 記述例

-f documentation  
-o rspec.txt  

では次から実際に起きた事例とそれに応じたオプションの使い方を説明します

事例 1. 今すぐに失敗しているテストを調査したい!!

業務で超大量のテストコードを実行し、それのテストが失敗している部分の調査を行いました。1回全て通して実行してみると、何個かテストが失敗している部分がありました。実行結果を見て修正をしましたが、それでも何個か落ちてしまっていました。 超大量のテストコードなので、実行時間もかなり時間がかかってしまいます。1回1回テストコードの終了を待っていたら何日あってもたりないので、テストコード実行中に失敗したテストの調査をし始める必要がありました。 しかし出力は .....FFFFF.... となんかのテストの成功と失敗しか分かりません。 そこで使用するのが次のオプションになります。

-f [出力形式]

出力形式については 1. progress 2. documentation 3. html 4. json

があります。 では出力形式によってどういった違いがあるのか、例を使って見てみます。

例:

context '検索が成功した場合' do  
  it 'レスポンスが成功している事' do  
 end  
  it 'レスポンスが200である事' do  
  end  
end  

というテストを
$ bundle exec rspec -f [出力形式] コマンドラインで実行
または
.rspec-f [出力形式] を追記した後、実行したとき

1.のprogress は 事例1 のように

$ bundle exec rspec  
Randomized with seed 00000  
....  
Finished in 0.70694 seconds (files took 7.7 seconds to load)  
4 examples, 0 failures  
Randomized with seed 00000  

と表示されます。 これは -f を省略したときにも表示されます 

2.のdocumentation は

$ 検索が成功した場合  
$ レスポンスが成功している事  
$ レスポンスが200である事  

のように progress より、分かりやすく、読みやすい形で出力してくれます

3.のhtmlについては以下のようにhtml形式で出力されます。

<div id=“div_group_4” class=“example_group passed”>
 <dl style=“margin-left: 30px;“>
 <dt id=“example_group_4” class=“passed”>検索が成功した場合</dt>
  <script type=“text/javascript”>moveProgressBar(75.0);</script>
  <dd class=“example passed”><span class=“passed_spec_name”>レスポンスが成功している事</span><span class=‘duration’>0.01757s</span></dd>
  <script type=“text/javascript”>moveProgressBar(100.0);</script>
  <dd class=“example passed”><span class=“passed_spec_name”>レスポンスが200である事</span><span class=‘duration’>0.01371s</span></dd>
 </dl>
</div>

ブラウザで開くとこうなります

f:id:zenet-tech:20201012192230p:plain
Rsepc_htmlde

最後に4.のjson もhtml形式と同様にjsonという形式で出力されます。これについては初心者の方は考えなくてもいいと思います。

{version”:“3.9.2",“seed”:29794,“examples”:[{id”:“./spec/controllers/*********_spec.rb[1:1:1:1]“,”description”:“レスポンスが成功している事“,
   ”full_description”:“TargetListsController GET #index 検索が成功した場合 レスポンスが成功している事“,
   ”status”:“passed”,“file_path”:“./spec/controllers/**************_spec.rb”,“line_number”:6,“run_time”:0.214949,“pending_message”:null},
   {id”:“./spec/controllers/*******_spec.rb[1:1:1:2]“,”description”:“レスポンスが200である事“
 ~~~~~中略~~~~~
 ,“summary”:{duration”:0.52153,“example_count”:4,“failure_count”:0,“pending_count”:0,“errors_outside_of_examples_count”:0},
 “summary_line”:“4 examples, 0 failures}

今回のように、途中でテストコードの調査をしたい場合は、2 の documentation を 選択すると、初心者でも分かりやすく表示してくれます。

またオプションにはテストコード実行時にコマンドラインで書く方法($ bundle exec rspec -f [出力形式])と.rspecに記述する方法の2通りありますが、このオプションについては、ずっと変更していてほしいなら.rspecに、場合によって出力を切り替え対場合はコマンドラインで書いたほうが良いです。 ちなみに私はテスト実行時に書いています。

事例 2. テストコードがたまにしか失敗しなくて、原因がわからない。

事例1では、テスト中から調査をし始めて修正を行って、全部成功にしたと思いましたが、念のため超大量のテストコードもう一度実行すると、別のところのテストが失敗していました。   しかし1回前の実行ではそれは成功していたのです。 ファイル単体でテストを回してみると、今度は成功してしまいました。
その後も何度かテストコード全体で実行しても、失敗したり成功したりまちまちでした。 私はテストコードが失敗している部分が見たいのに、ファイル単体では成功してしまい、全体でテストコードを実行しても、たまにしか失敗しない。 そんなときに使用下のが次のオプションになります

 --seed [シード値]

シード値とは?

乱数を生成するときの最初の設定値のことです。 シード値が同じであると生成する乱数は全く同じになります。
Rspecのテスト実行順序はランダムであるため、乱数と同様に、同じシード値を指定すると同じ実行順序になります。
例えば、以下はテスト実行時のログになります。最後の行のRandomized with seed 0000 の 00000 部分がシード値になります。

$ bundle exec rspec  
Randomized with seed 00000  
....  
Finished in 0.70694 seconds (files took 7.7 seconds to load)  
4 examples, 0 failures  
Randomized with seed 00000  

例:最後に [ Randomized with seed 12345 ] と表示されたテストと同じ順序でテストを行いたい場合は
$ bundle exec rspec --seed 12345コマンドラインで実行する。
または
.rspec--seed 12345 を追記した後、Rspecを実行します。

しかし、.rspec に書いて置くと別のテストコードを実行するとき等に、順序が固定されてしまい、
実行順序で失敗するコードに気づかない危険性があるため、 めんどくさいですが、コマンドラインで実行するときに書きましょう。

事例 3. テストの実行結果を保存したい。

こんどは超大量のテストコードの実行結果を見せてほしいといわれました。
しかしまだまだ大量にテストが失敗している状況で、実行結果をターミナルからコピーしようとしたとき、最初の部分が消えてしまい、うまくログが取れなかったことがあります。 でも、どうしてもすべてのログを取得したかったので、その時使用したのが、次のオプションになります。

-o [ファイル名]

これを使うと[ファイル名]に記載したファイルに実行結果を出力してくれます。
例えば
$ bundle exec rspec -o rspec.txt コマンドラインで実行
または
.rspec-o rspec.txt を追記した後、実行したとき
.rspecと同じ階層にrspec.txtが生成され、そのファイルに実行結果を出力してくれます。

注意点として、ターミナルには実行結果が表示されなくなってしまうため
別のターミナルで $ tail -f [ファイル名] を使うと、今まで通りにリアルタイムに実行結果を見れます。

事例1,事例2のオプションと違い、実行結果は常に取っておいてもいいと思いますので、 .rspecに記述したほうが良いと思います。

最後に

 Rspecを最初触った時は何をしたらいいのかよくわからずにテストコードを書いていました。実行しても、....FFFFFのように何をやっているかよくわかりませんでした。オプションなどの便利機能を使い始めるとわからないなりにもわかるように出力してくれたり、面倒くさいこともやってくれたりするので、初心者にこそ使ってほしいです。

AWS Solution Architect professionalに一発合格しました!!!!!!

始めまして3-4Gの増田と申します。

いきなりですが、先日、弊社で初めてAWS professional資格に合格できましたので、勉強方法や入手できる教材のメリット・デメリットなどをまとめて共有できればと思います。

前提

2年目で、情報処理はITパスポートを持っています。 開発系の部署に所属しており、大学も情報系ではないため、知識は少ないです。 AWSの勉強をしながら足りないインフラ知識を埋めていきました。 資格取得の前に少しだけAWSを触ったことがあります(Lambda、SNS、SQS、S3、Rekognition)。 勉強時間は、およそ150h(期間は2か月半)くらいだったと思います。

AWS professional資格の基本情報

受験料は30000円です。非常に高い!!!!2年目にはつらいです。 ただ以前AWSの資格試験に合格したことがあると、半額バウチャーがAWSから付与されているので15000円で受験することができます。知識の土台をつくる意味でも、SAAからの受験を強くお勧めします! 受験時間は、180分になります。これもまたつらいです。落ちると、精神的にも懐てきにもつらいので、入念に勉強を重ねて一発合格を狙うべきだと、振り返って思います。。

教材まとめ

Webで受験可能な試験対策の問題を以下に羅列します。個人的に、資格取得に役立った!というものは◎にしています。

AWS traing公式サイト -- Exam Readiness: AWS Certified Solutions Architect – Professional (日本語) ◎

一番最初に取り組むべき、良サイトです!! AWS資格試験を受験する前段階として、登録する「AWS training and certification」なのですが動画講義やハンズオンがとても充実しています。 演習問題を軸に、試験範囲や出題されるサービスなどが、すごくコンパクトにまとめられていて、4時間ほどで解説してくれるので、とても分かりやすいです。

AWS認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説 ◎

日本語で出版されている、唯一のプロフェッショナル対策本です! Udemyに比べ格段に文章が読みやすいですし、正解に導くための根拠が明確に問題文の中にあるためとても解きやすいです。自力がつくと思います。 模擬問題で意味不明な日本語にやる気をそがれる前に、取り組んでおくべき良本です。 https://honto.jp/netstore/pd-book_30341766.html

Udemy -- AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集(全5回分375問)

https://www.udemy.com/course/aws-53225/ Web学習サイトのUdemyで発売されている教材の中では、おそらく日本語のAWS professional資格試験に取り組むことのできる、唯一の問題集です。 僕は、この問題演習に一番時間をかけました。試験範囲の把握には良かったと思います。 ただ、試験を解いた後振り返ってみますと、それほど点数に直結したという感覚はありませんでした。 またUdemyには英語話者向けの一番売れている教材があるのですが、その問題と「すごく似ている問題だな…?」という部分が多くあります。英語が得意な方はそちらを買われた方が良いかもしれません。

Udemy -- Ultimate AWS Certified Solutions Architect Professional 2020 (英語)

https://www.udemy.com/course/aws-solutions-architect-professional これもUdemyですが動画メインの講義になります。英語教材ですが、良質な教材です!! 問題演習はないのですが、AWS pro試験で出題される細かな範囲まで、丁寧にカバーしてくれています。 本教材では字幕をスクリプトとして画面外に表示できるので、それをGoogle翻訳するというやりかたで勉強していました。

Whizlabs -- AWS Certified Solutions Architect Professional(英語)

https://www.whizlabs.com/aws-solutions-architect-professional/ Whizlabsという、これまたWeb系のオンライン講座を運営しているページの講座になります。 Udemyは誰でも講師になることができるというシステムのため当たり外れが大きいのですが、Whizlabsは運営が1つの教材のみを管理しているため、問題が安定して良問であるような印象でした。 講義編、ハンズオン編、問題演習編がばら売りになっているので、クーポンを使用して問題演習編のみを1500円程度で購入するのが一番効率の良い利用方法かと思います。 これも、Google翻訳を駆使して解いていきました。 ただ、問題の難易度は実際の試験と比較して少し優しいのかなと思います。

AWS公式サイト -- 各サービスの「よくある質問」

これも侮れません!! 単なるサポートページのように見えて、市販されているAWS対策本には書いてないけど試験にはばんばん出てくる情報が凝縮されているイメージです。 ただ、proに関しましては、もちろん出題されうるサービス数が多いため、以下のサービスを抑えておくのが良いと感じています。 Direct Connect,Activ Directory,Organziation,CloudFront,

以下はDirectory Serviceの「よくある質問」になります。 https://aws.amazon.com/jp/directoryservice/faqs/

AWS公式サイト -- AWS サービス別資料 ◎

https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/ サービスごとのスライド説明です。 基本的な説明を図で説明してくれるので、「このサービスは一体何なんだ。。。」「この概念が良く分からない。。」「公式リファレンスが分かりづらい。。」というときに使うと便利です。

試験場の注意など

日本語がとにかくひどいです!! AWS資格試験は、申込時に言語を「日本語」に選択しても、当日受けている途中に英語に変えることができるため、意味が取りにくい文章があったら強くおススメします! (僕の場合は、この方法で1問 正解にすることができました。点数が761点だったので、気づかなかったら多分落ちていました。。)

また、試験時間が180分と長いので、見直しも見込んで1問平均1.5分程度で解いていくのが良いかと思います。

感想

つらいです。 資格勉強をしている間は、趣味にも手がつかないくらいプレッシャーがかかるので、超短期間で勉強して一気に受かりたいなと思いました。 今度はDevopsを取れるように勉強しようかと思います。

最後に、、

取得した資格だけは、いっちょ前な名前なのですが、業務ではSSHのポートを全開にしていたりと、ミスが絶えません。。 やはり試験と実際の業務には乖離があるといいますか、実践が一番重要なのだと強く思っています。

ほんとの最後に、、、

現在弊社ではAWS研修を行っております!!! AWS資格取得はもちろん(professionalにも対応しています)、実務に向けたハンズオン研修も充実しておりますので、ぜひぜひお申込み頂ければと思います! (わたくしが講師をしております。がっつり宣伝です!) https://www.zenet-web.co.jp/PDF/info_aws_training.pdf

お久しぶりです。 システム事業部マネージャ阿部です。

ここ半年忙しくてブログを更新できていなかったので、 私から再開します。

ここ3,4年Railsを中心としてWebアプリの開発をやっていく中で、 「なんでこんなとこで躓いてしまったんだ」 という無駄な時間を過ごすことがあったので、備忘録として残しておこうと思います。

私はマネージャということもあり、社内の事務処理や提案資料を作ることも多く、 Windowsをメインに仕事をしていることが多いです。

Railsの開発を行う場合は,WindowsVirtualBoxを乗せて、そのうえでLinuxをインストールして起動しています。 ファイルはSAMBAやSSH接続することで、Windows上のVScode/sublime textなんかでコーディングしています。

f:id:zenet-tech:20200831133214p:plain

そこで、1年に一度くらいはまって1日を無駄にすることがあるのが

VM環境で実行した場合に、ゲストOSからはアクセスできるが、ホストOSからアクセスできない

です

実際に起こることは以下の3つです。

  • 起動コマンドを実行結果を見ると、起動は成功している
  • Chromeで表示すると【このサイトにアクセスできません】と表示される
  • Linux上のFireFoxからは画面が表示される

結論から説明しますと、起動時に以下のオプションを指定していなことが原因でした。

Rails s -b 0.0.0.0 

qiita.com にすごくわかりやすい記事がありました。

2,3度無駄を繰り返しているので、環境を構築した場合にまずエイリアスで独自コマンドを作って実行するようにしています。

rs='bundle exec rails s -b 0.0.0.0'

これで

rs

と打つようにしておけば、もう繰り返すことはないでしょう。

もし同じような悩みを抱えている方がいたら、エイリアスを有効活用することをお勧めします!

preztoで快適ターミナル生活

システム事業部の五十島です。

現在お使いのシェル環境はどんな感じでしょうか?
以下のようにデフォルトをそのまま使用していませんか?

f:id:zenet-tech:20191209114755p:plain

シェル環境を快適にしたいけど、設定がよくわからない・めんどくさい人に朗報です。
必要な設定をほぼ自動的に行なってくれるツールがあります。
GitHub - sorin-ionescu/prezto: The configuration framework for Zsh こちらを使えばお手軽に、素敵zsh環境を構築することができます。

f:id:zenet-tech:20191209115143p:plain

上記画像は一例ですが、git管理をしているディレクトリだとブランチ名が出たり、lsでファイルの種類ごとに色をつけてくれたり・・・様々な設定を含んだ設定ツールになります。

1. 準備

zsh のバージョンが4.3.11以上かを確認しましょう。 以下のコマンドで確認できます。

$zsh --version
zsh 5.7.1 (x86_64-apple-darwin17.7.0)

4.3.11未満の人はzshのバージョンをあげてください。 そもそもzshが入っていない人はインストールをしましょう。(apt-get、yam、brewなどのパッケージ管理ツールで)

2. Preztoの設定

Preztoはgithubからクローンしてきます。 以下のコマンドを実行すると、ホームディレクトリーに .zprzeto ディレクトリが作成されます。

$ git clone --recursive https://github.com/sorin-ionescu/prezto.git “${ZDOTDIR:-$HOME}/.zprezto”

以下を実行して、設定ファイルを作成ます。

$ setopt EXTENDED_GLOB
for rcfile in “${ZDOTDIR:-$HOME}“/.zprezto/runcoms/^README.md(.N); do
 ln -s “$rcfile” “${ZDOTDIR:-$HOME}/.${rcfile:t}”
done

初期のシェルをzshに変更して、新しくターミナルを立ち上げると、いい感じになっています。

$ chsh -s /bin/zsh

3. カスタマイズ

表示のカスタマイズ

表示タイプはデフォルトで色々用意されています。 以下のコマンドを実行すると、一覧で表示されます。

$ prompt -l
Currently available prompt themes:
agnoster cloud damoekri giddie kylewest minimal nicoulaj paradox peepcode powerline pure skwp smiley sorin steeef adam1 adam2 bart bigfade clint default elite2 elite fade fire off oliver pws redhat restore suse walters zefram

以下のコマンドで表示を変更できます。

$ prompt -s cloud

f:id:zenet-tech:20191209120329p:plain

今回は「cloud」に変更してみました。 ただし、新規のターミナルを立ち上げたり、ターミナルを終了するともとに戻ってしまいます。

永続的に使用したい場合は、 ~/.zpreztorc に変更を加えましょう。 100行目あたりの以下に好きな表示タイプ名を入れて保存してください。 次回起動時から表示設定が変更されています。

# Set the prompt theme to load.
# Setting it to 'random' loads a random theme.
# Auto set to 'off' on dumb terminals.
zstyle ':prezto:module:prompt' theme '表示タイプ名'

便利な設定をしよう

preztoはよく使われるコマンドの保管やエイリアス設定なども準備されています。 ~/.zpreztorc にどんどん追加して、好きにカスタマイズしていきましょう。 一覧は以下を参照にしてください。 prezto/modules at master · sorin-ionescu/prezto · GitHub

私は以下のように設定を入れており、git、dockerなどは個人的に入れておくことをおすすめします。
rubyrailsなどは開発で使用しているので入れているという感じです。お使いの開発言語に合わせて、カスタマイズしてみましょう。

 # Set the Prezto modules to load (browse modules).
 # The order matters.
 zstyle ':prezto:load' pmodule \
   'environment' \
   'terminal' \
   'editor' \
   'history' \
   'docker' \
   'directory' \
   'spectrum' \
   'utility' \
   'completion' \
   'git' \
   'osx' \
   'rails' \
   'ruby' \
   'ssh' \
   'prompt'

preztoで快適ターミナル生活はじめてみませんか?

HTML5のdatalistを使って、IE11で部分一致させる。

システム事業部の三浦です。 HTML5で追加された、datalistのちょっとしたクセについて紹介したいと思います。

TL;DR

IEでdatalistを部分一致で引っ掛けたい場合は、
datalist-polyfillを利用すると簡単

本題

HTML5より導入された、inputのlist属性とdatalistタグを利用すると、簡易的にサジェスト機能を実装できます。

datalistのリファレンス

とっても便利な機能なのですが、困ったことにブラウザ毎で仕様が微妙に違うのというクセがあります・・・

何が違うのかというと、前方一致タイプと部分一致タイプに分かれます。

前方一致

部分一致

確認用に以下のhtmlを用意しました。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Datalist</title>
  <style>
    html { font-family: meiryo; }
  </style>
</head>
<body>
  <h2>Datalist確認</h2>
  <input type="text" list="test">
  <datalist id="test">
    <option value="ラーメン">
    <option value="とんかつ">
    <option value="かつ丼">
    <option value="うどん">
    <option value="ステーキ">
  </datalist>
</body>
</html>

リストが表示されている状態(IE11で確認)
f:id:zenet-tech:20191008195310j:plain

また、この状態でと入力すると以下の様な結果となります。 f:id:zenet-tech:20191008195424p:plain

IEは前方一致、chromefirefoxは部分一致となっていますね。

これを解決するためにサジェスト系のライブラリを利用するといったやり方もありますが、
リッチなUI・機能はいらなかったり、手っ取り早くやりたいという時に便利なのがこれです。

datalist-polyfill

※色々な導入方法がありそうですが、簡易的に利用したい場合は、datalist-polyfill.js または datalist-polyfill.min.jsのファイルだけをダウンロードしてください。今回はファイルダウンロードで試しています。

これはもともとPolyfill(ポリフィル)と言われる類のもので、

ポリフィルとは、最近の機能をサポートしていない古いブラウザーで、その機能を使えるようにするためのコードです。大抵はウェブ上の JavaScript です。

https://developer.mozilla.org/ja/docs/Glossary/Polyfill より引用

基本的な使い方としては、未対応のブラウザで同等の動作をさせる(今回はdatalist) ためのスクリプトですが、すでに対応されているのIEの動作を変更することができます!

先ほどダウンロードしたdatalist-polyfillのjsファイルを対象HTMLに読み込みます。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Datalist</title>
  <style>
    html { font-family: meiryo; }
  </style>
  <script src="js/datalist-polyfill.min.js"></script> -----追加
</head>
<body>
  <h2>Datalist確認</h2>
  <input type="text" list="test">
  <datalist id="test">
    <option value="ラーメン">
    <option value="とんかつ">
    <option value="かつ丼">
    <option value="うどん">
    <option value="ステーキ">
  </datalist>

</body>
</html>

例では今回は以下の様なディレクトリ構成を取っています。

index.html
- js
  - datalist-polyfill.min.js

これで以下の様な感じになります。(IE11で確認)
f:id:zenet-tech:20191008195748j:plain

これで、簡単に部分一致に統一することができました!!

以上です。

Railsを3.2系から5.0系にマイグレーションした時の経験談等

初めまして、システム事業部の坂本です。

以前、Railsマイグレーション(バージョンアップ)業務を担当したことがありました。 その際Railsのバージョンアップに伴い、「バージョンを上げると使えなくなる記述」が非常に多く骨が折れた記憶があります。 自身の備忘録も兼ねて、主にこの記事では以下3点にフォーカスを当ててRailsマイグレーションに関して書いて行きたいと思います。

  • ステップ1:そもそもマイグレーションってどうやったの?
  • ステップ2:修正が必要な個所を洗い出してみる
  • ステップ3:実際に修正してみる(具体例有)

マイグレーション業務に関わる予定がある方でも無い方でも、最後まで見て頂ければ幸いです。 「そんな記述が昔は出来たんだ」「あのバージョンでこの機能はまだ実装されてなかったんだ」という発見があって、ちょっと面白いと思います。


ステップ1:そもそもマイグレーションってどうやったの?

根本的な話からです。大まかに説明すると、私が担当した際はRailsマイグレーション作業を以下の流れで行いました。

  1. Gemfileを修正し、bundle install等でRailsのマイナーバージョンを1段階上げる
  2. ソースを修正する
  3. アプリを動かして、一通りの機能を動かしてみる
  4. 修正が不十分であればアプリが落ちるので、必要に応じて更に適宜修正
  5. 全ての修正が完了したら1.へ戻り、目的のRailsバージョンまで繰り返す

上記は飽くまでも一例ですが、基本的には「1段階上げて修正、完了したらまた1段階上げて修正、完了したらまた1段階……」という風に、1ステップずつ作業を行うのが適切です。*1 いきなりRails3.2系からRails5.0系まで上げる、みたいなことをすると多分詰みます。(経験談) 慌てず1段階ずつ行きましょう。

Gemfileの修正について

Gemfileを開いて、railsに対応するバージョンを上書きします。 ここで、例えばrailsを「4.0」と指定すれば「actionmailer」「activemodel」「activesupport」等、Railsのコアライブラリも「4.0」まで上がります。

Gemによっては「actionmailer4.0に対応しているバージョンはX.X.Xから」「rails4.0に対応しているバージョンはX.X.Xから」という風に指定があるため、 bundle installのエラーやRubyGems*2を参考にしながら、適切なバージョンまで必要なGemのバージョンを上げていきます。

ステップ2:修正が必要な個所を洗い出してみる

さてソースコード修正開始の前に、下準備から行きましょう。いざとやろうとしても、闇雲にやると後で良く分からなくなってしまいます。 まず全体を通して、以下の記述3点は後程修正が必要になる可能性が非常に高いです。

  • モデルに対して検索・更新・削除等が行われる記述(特にwhereメソッドを利用していない箇所)
  • Gemファイルに依存する記述(バージョンアップで記述が変わるGemもある)
  • コントローラー、モデルに対するオプション全般

そしてRails3.2系から5.0系への大幅なマイグレーションを行った中で、 ソース修正時のメインとなったのは大きく分けて以下の3通りでした。

  • find(3.2→4.0へアップグレード)
  • updated_all、Strong Parametersへの対応(4.0→4.1へアップグレード)
  • validate全般(4.2→5.0へアップグレード)

間違いなく3.2から4.0に挙げた際の「find」の修正が一番の壁でした。 マイグレーション作業の4割近くはこのメソッドに対する対応だった記憶があります。

勿論上記以外にも修正すべき場所はまだありますが、少なくともここまで私が言及した内容に関してはマイグレーション作業の中で修正が必要になると思われます。 修正が必要なファイル・対応行を一通り書き留めて、後で修正が完了したか確認出来る簡易的なチェックリストを用意しておきましょう。

ステップ3:実際に修正してみる(具体例有)

さて、ここからが本題です。実際にソースコードを修正するとどうなるのか?をコメントと共に記載します。 特に説明が無い限り、以下の通りに記述していきます。

修正前

↓

修正後

修正した個所は沢山ありましたが、今回はその中でも特に印象に残った以下4点をご紹介します。

  • find
  • update_all
  • validate全般
  • Strong Parameter (Rails3系からRails4系)

「find」を修正してみる

基本的な書き換え

User.find(:all, :conditions=> "postal_code=1234567 and gender=0", :order => "name")

↓

User.where(postal_code: 1234567, gender: 0).order(:name)

マイグレーション作業でまず一番最初に驚いた記述がこれでした。Rails3.2系では、findメソッドの中に検索条件・Order条件等を一通り入れることが出来たのですね……

しかし今のRailsではそんなことは出来ませんので、シンプルにwhereメソッドやorderメソッドを利用した記述に変更しましょう。

条件に対する1件目のみ取得

User.find(:first, :conditions=> "name='ゼネット太郎'")

↓

User.find_by(name: 'ゼネット太郎')

先程との差異は「find(:all, ......)」だったのが「find(:first, ......)」になっているところですね。 検索結果の1件目のみ取得したいのであれば、「find_by」が利用できるのでそちらを使用します。

「update_all」を修正してみる

User.update_all("first_name= '田中'", "first_name= '山田'")

↓

User.where(first_name: '山田').update_all(first_name: '田中')

やりたいことはどちらも「苗字が'山田'のユーザ全員の苗字を、'田中'に変更する」です。 以前までは「update_all(更新内容, 条件式)」を利用して、条件式に該当するデータ全てを更新することが出来ましたが現在はupdated_allに引数を2つ以上持たせることは出来ません。 そのため、「where(条件式).update_all(更新内容)」に書き換えます。

余談ですが、修正前をよくよく見てみるとSQLっぽいですね。 「修正前はUPDATE users SET first_name='田中' WHERE first_name='山田';を取り合えずRailsで実装してみて、修正後はよりRailsらしく分かりやすい実装にしてみた」という印象を受けます。

validate全般を修正してみる

だいたい修正の方法が同一なので、まとめて4パターンのみ記載します。

ユーザの名前の長さを最大10文字までにする

validates_length_of :name, :maximum => 10

↓

validates :name, length: { maximum: 10 }

ユーザの年齢は整数のみ許可する

validates_numericality_of :age, :only_integer => true

↓

validates :age, numericality: { only_integer: true }

ユーザの名前は必須とする

validates_presence_of :name

↓

validates :name, presence: true

ユーザの月収は数字のみ許可する

validates_numericality_of  :salary

↓

validates :salary, numericality: true

ここまで、修正方法4パターンを紹介しました。何となく法則性があるのが見て取れると思います。 他にもフォーマットの修正・ユニークの設定等もありますが、基本的には以下の2パターンで修正することが出来ます。

validates_XXXXXXXX_of :カラム名, :オプションキー => オプション値

↓

validates :カラム名, XXXXXXXX: {オプションキー: オプション値}
validates_XXXXXXXX_of :カラム名

↓

validates :カラム名, XXXXXXXX: true

Strong Parametersへの対応(Rails3系からRails4系)

Strong Parametersを大まかに説明すると、ユーザからは特定の項目のみ更新可能にしてセキュリティを強化する仕組みです。ですが、Strong ParameterはRails4系から実装されたものでありRails3系では無かった機能となります。 そのため、Rails3系からRails4系にアップグレードした際、必要であれば対応を行って下さい。

長くなるためここではStrong Parametersに関する言及は行いませんが、詳しくはRuby on Railsガイドのこちらの記事をご確認下さい。

Action Controllerの概要 4.5 Strong Parameters | Railsガイド


所感など

さて、ここまでRailsマイグレーション作業に関して色々書きましたが、もっと書こうと思うと長くなりすぎてしまうので今回はこの程度に収めておきます。

この記事に記載したソースコードのBefore→Afterを改めて見ると、全体的にスッキリして読みやすくなっている印象を受けました。 特にバリデーションはただ単純にスッキリしているだけではなく、実装のしやすさも変わっていると思います。 例えば、実際に「ユーザの名前は必須かつユニークで、最大10文字まで可能」というバリデーションを実装しようとするとRails3系までの記述・Rails5系からの記述ではこのように変わります。

validate_presence_of :name
validate_uniqueness_of :name
validate_length_of :name, :maximum => 10

↓

validates :name, presence: true, uniqueness: true, length: {maximum: 10}

上記のBefore→Afterを見ていると、Rails5の方が文字数も少なくスッキリまとまっていて、パッと見た時に意味が分かりやすい印象を受けるのではないでしょうか。

Railsに限らず、様々な言語でバージョンアップに伴う細かい記述方法の変更があると思われますが、「何故この記述に変更になったのだろうか?」「変更されたことで何かメリットはあるのだろうか?」と考えてみると、ちゃんとした意味があることに気づけて面白いと思いました。


マイグレーションの作業は想像以上に大変だと思いますので、慌てず計画的にやっていきましょう!

最後まで見て頂き、ありがとうございました。

SECCON Beginners ctf 2019 writeup

初めましてシステム事業部の石黒です。

SECCON Beginners2019に参加しました。
解くことができた問題について、どのように解いたかを備忘録がてら残したいと思います。 今回が初参加であり、筆者の業界歴も浅いため、ビギナー目線の記事になることをご承知おきください。

SECCON Beginnersとは

SECCON Beginnersというのはその名の通り、初心者向けのSECCONになります。
(そもそもSECCON is 何?という人はこちら)

今回のSECCON Beginnersは、CTF(Capture The Flag) 形式で行われました。
CTFでは、参加者が様々な攻撃を仕掛け、問題のどこかにあるflagを探し出すことが目的となります。
flagは ctf4b{XXXX}の形式で、暗号化されたりして隠されています。

問題

問題は[Crypto, Pwn, Reversing, Web, Misc]の5種類に分けられており、それぞれ4問ずつあります。
私が解くことができたのは、この内Web系の問題2問になります。

なお、残念ながら全問題についてはすでにサイトが閉じてしまっているため見ることができません。

[warmup] Ramen

warmupということで、一番簡単なものになります。
しかし、初参加の私にはハードでした。

まず、戸惑ったのは問題文です。
問題文は以下のようなものでした。

ラーメン
(url省略)



お わ か り い た だ け た だ ろ う か



他の問題もそうですが、問題文なんてものはありません。SECCONの洗礼を受けました。
なにがなにやらわからないので、とりあえずリンクを踏んでみました。

すると、リンク先はどうやら簡易的なWebサイトのようでした。
サイト内に検索フォームがあるので、sqlインジェクションにあたりをつけてflagを探すことに。

sqlインジェクションについてgoogle先生に聞きながら試すうちに、
どうにか以下のUNION句でテーブル一覧を取得できるところまでたどり着くことができました。

 'UNION SELECT table_name, GROUP_CONCAT(column_name) FROM information_schema.columns GROUP BY table_name -- 

テーブル一覧を取得してみると、flagテーブルがあったので、
今度は以下のUNION句でflagテーブルのデータを取得し、無事flagを見つけました。

 'UNION SELECT flag, flag FROM flag --  
 => ctf4b{a_simple_sql_injection_with_union_select}

ここまで一時間半程度掛かりました。。

katsudon

問題文を見てみると、何やら怪しい文が

Rails 5.2.1で作られたサイトです。  
(url省略)
クーポンコードを復号するコードは以下の通りですが、まだ実装されてないようです。
フラグは以下にあります。 
(url省略)

Rails 5.2.1とわざわざバージョンが書いてあるため、 脆弱性のバグをつくものかと思いましたが、結局わからなかったので、断念。

別の方法を探すため、サイト上に示されている、以下の暗号化されたflagの文字列の複合を試みる方針に。

BAhJIiVjdGY0YntLMzNQX1kwVVJfNTNDUjM3X0szWV9CNDUzfQY6BkVU--0def7fcd357f759fe8da819edd081a3a73b6052a

サイトのRailsコードが公開されていたので、MessageVerifierによって文字が作成されていることはわかりました。 しかし、secret_key_baseがわからないため、複合できそうにない。。。

どうしようかとコードを追っていくうちに、文字列が以下のようにして生成されていることがわかりました。

 "#{data}--#{generate_digest(data)}"

後ろはただのハッシュなので、--以前に対して複合してあげれば行けそう?と思い、 rails consoleで以下を叩くと、

Marshal.load(::Base64.strict_decode64("BAhJIiVjdGY0YntLMzNQX1kwVVJfNTNDUjM3X0szWV9CNDUzfQY6BkVU"))
=> "ctf4b{K33P_Y0UR_53CR37_K3Y_B453}"

flagを取得できました。

この問題も一時間半程度掛かりました。

気づいた方もいるかもしれませんが、上でやっているのはbase64で複合しているということなので、 rails consoleでこんなコードを叩く必要もなく、もっと簡単に解けます。。。 base64の文字列に慣れている方は一瞬だったかと思います。

(補足) 実はこれらの解き方は運営側としては意図していないものだったらしく、
改めてkatudon-okawariとして修正版の問題が出題されました。

そしてこのkatudon-okawariの解き方は、
Rails脆弱性のバグを利用し、secret_key_baseを盗るというもののようです。。。
当初このアプローチをしていただけに、非常に悔しい。。。

まとめ

というわけで、初めてSECCON Beginnersに参加したわけですが、
自身の知識・技術不足を痛感でき、非常に良い刺激になりました!

次はweb以外の問題も解けるように力を付けたいです。