ホーム ブログ ページ 35

ゲームデータをExcelで書くときに役立つ4つのこと

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

 ゲームを作るとき、利用するソフトや制作形態によって、データをどう入力するかは 大きく異なってくる。この記事ではExcelで入力する場合を取り上げるが、考え方などは 他のツールでも役に立つかもしれないので、参考にしていただけたらと思う。

データの入力例

 戦闘があるゲームを例として考えてみよう。
 ↓の画像はスキル設定シートにおける入力だ。データ的に必要なものだけを入力している。なお、実際のゲームでは消費MPとか威力とかその他色々な内容を設定する必要があるが、今回は例なのでこの程度にしている。
enter image description here
 どの数字が何に対応しているか分からないこのシート、入力する人は大変な思いをするだろう。何百、何千とスキルがあったとしたら・・・想像するだけでゾッとする。入力ミスは当然起きるだろうし、時間もかかる。だが、Excelならそんな悩みは吹き飛ばせる。

データの入力規則とVLOOKUP

まずは新たに↓のようなシートを用意しよう。
enter image description here
そして
 B5~B8をドラッグ→数式タブの中にある「名前の管理」→「新規作成」
と操作し、「スキル種類」と名付ける。次にB5~C8をドラッグして、今度は「スキル種類リスト」と名付ける。他の項目も同様にやっておく。
(余談:このようなシートを「reference(参照)」と呼んだりする)

一方、入力用のシートは↓のようにする。
enter image description here
そして
 名称のセルを選択→データタブの中にある「データの入力規則」
と操作し、↑画像のように入力する。これで先ほど設定した「スキル種類」と名付けた
内容がプルダウン式で選択できるようになる。
 次に数字が入っているほうのセルには、「=IF(D4=””,””,VLOOKUP(D4,スキル種類リスト,2,0))」と入力する。このように入力することでD4の値に合ったcodeが出るようになる。こういった自動で入力されるセルには分かりやすく色付けしておくといいだろう。↓こんな感じだ。
enter image description here
(余談:このようなIF文にすると名称欄が空欄だと何も出ないが、単にVLOOKUPのみにすると#N/Aエラーが出る。自分や開発環境のスタイルに合わせて使い分けてほしい。)

 このような入力方法にすることで、作業効率をアップし、ミスを減らすことができる。さらに、この方法は後で「ターゲットのcode2番をランダム1体にしたい」となったときに、referenceシートの方で、2番にランダム1体、3番に全体、とすれば自動的に入力シートに反映される。ただし、名前の管理から3番目が外れていたら直しておく必要があるので注意。

文字列を書き換える置換

(置換なんて知ってるよ!って人は飛ばしていい。これは完全に初歩だ。)
 先ほどのシートで、「ターゲットの単体を1体に書き変えたい」となったとしよう。referenceと合わせても「単体」と書いているセルは6個なのでこの程度なら直接書き換えても大したことはない。しかし、既にスキルを100個作っていたとしたら1つ1つ変えることほど馬鹿らしくて間違えやすいことはない。
 ここは置換機能を使おう。ホームタブの「検索と選択」の中にある。検索する文字列には「単体」、置換後の文字列には「1体」と入力する。次に「すべて置換」を押したいところだが、先に「すべて検索」を押そう。これを押すことでこれから置換しようとしている対象のセルが全て見れる。押してみると、説明文の方に「単体」の文字が入っていることが分かる。(↓の画像のようになったはず)
enter image description here
もし説明文はこのままにしておきたければ、「セル内容が完全に同一であるものを検索する」にチェックを入れよう。あとは「すべて置換」を押せば完了だ。

エラー値チェック

 Excelを使ったことがあれば誰でも「#N/A」「#REF!」などでイラッときた経験はあるだろう。こういったエラー値表示はいくつかの方法でチェックすることができる。ここでは3つほど紹介する。

1. 検索で「#N/A」などのありがちなエラー値を検索する
 これはそのまんま。自分がよく見かけるものを検索しよう。ただ、エラー値表示は7種あるため、毎回全て検索するのは結構面倒くさい。
 参考:エラー値は「#DIV/0!」「#N/A」「#NAME?」「#NULL!」「#NUM!」「#REF!」「#VALUE!」の7種。

2. 数式タブの「エラーチェック」
 編集中のシートのあらゆるエラー値を調べてくれる便利なボタンだ。ボタンを押すだけで編集中のシートのエラーを調べられるのだが、検索のように一覧で見ることはできないし、ブック全体を調べることはできないので、シートがたくさんある場合はあまり有効ではないので注意。

3. 条件付き書式
 これはエラーを探すというより、あらかじめエラーを探しやすくする方法だ。まずはエラーが起こりそうなセルを選択し、ホームタブの「条件付き書式」内のその他のルールを選択。「数式を使用して、書式設定するセルを決定」を選択し、「=ISERROR(A1)」と入力(A1は設定するセルの場所)。書式は気づきやすいようにセルを赤色にしたりすると良い。(↓こんな感じだ。)
enter image description here
 こうすることで、設定したセルがエラー文を表示しているときだけ、設定した書式に変化する。検索と組み合わせれば、設定した書式を検索するだけで全て調べ上げることもできる。条件付き書式はエラーチェックだけでなく、様々なことに利用できるので色々試してみると良いだろう。ただし、条件付き書式はExcel全体が重くなる原因になりやすいので、多用は禁物。

表示順を設定する

 設定したゲームデータが表示される順番は、勿論設定した順番になる。しかし、例えば「ポーションとメガポーションを作ったが、後からハイポーションを間に入れたくなった」となったときどうすればいいだろうか。
 論理的には2つの間に行を挿入してハイポーションを作れば事足りるが、これはあまりよろしくない制作方法だ。新しく何かを追加するとき、一番下の行に追加しないと、どれが新しく追加したものか後から分からなくなってしまうからだ。
(1人で作っているならどうしようと勝手ではあるが)
 さて、話を戻すと各行毎に数値で表示優先度を振ることになる。このとき、ある程度の桁数と一定のルールで振るといい。例えば回復系アイテムは「10001000~10009999」とか、強化系アイテムは「20001000~20009999」とかそういう感じだ。どう振るのが適切かはゲームによりけりなので自分で考えよう。

まとめ

 いかがだっただろうか。他にも当たり前のようにやっていることや考えていることはあるだろうが、今回はこういうお題で思いついたものを書かせていただいた。
 Excelは調べれば使い方はたくさん出てくるが、それをどう活かすかは自分で考えなければならない。いや、Excelに限らずどのツールでもそうだろう。自分はまだまだ未熟なのでもっと精進しなければならない。

pyenv + pyenv-virtualenv + Serverless Framework で AWS Lambda 向け開発環境を作る

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

先日の記事のとおり、Serverless Frmework で Python3.6 の環境を作成するのにちょっとハマったということを書きましたが、やっぱり pyenv が便利なので pyenv の場合の環境構築手順をまとめてみました。

環境

  • OS: CentOS Linux release 7.3.1611 (Core)
  • Serverless Frameowrk 1.14.0

あらかじめ Serverless Framework はインストールされている前提です。
インストールされていない場合は、以下のページなどを参考にインストールして下さい。

pyenv と pyenv-virtualenv をインストール

Pythonの環境を複数用意する方法として、 pyenv + pyenv-virtualenv で行う方法と、virtualenv(venv) で行う方法があり、デファクトスタンダードは virtualenv(venv) のようですが、
コマンドのインターフェースが rbenv に似てて個人的に使いやすい点、python-build によって気軽に複数バージョンをインストールできる点から pyenv を使う方法を選択しました。

pyenv

以下のように pyenv をインストールします。

# Github から clone 
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv

# .bash_profile に環境変数等の設定を追加しておく
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

シェルを再起動した後、試しに現在利用中の Python のバージョンを確認してみると

$ pyenv versions
system (set by /home/vagrant/.pyenv/version)

$ python --version
Python 2.7.5

system にインストールされている Python 2.7.5 が利用中ということがわかります。

pyenv-virtualenv

続いて pyenv-virtualenv をインストールします。

# Githubから ~/.pyenv/plugins 配下に clone
$ git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv


# プロンプトへのバージョン表示を無効化(個人的にうざいので止める)
$ echo 'export PYENV_VIRTUALENV_DISABLE_PROMPT=1' >> ~/.bash_profile
# .python-version ファイルによる自動的な環境切り替えを有効化するために以下を実行
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile

シェルを再起動して、インストール結果を確認

$ pyenv virtualenv --version
pyenv-virtualenv 1.0.0 (virtualenv unknown)

上記のようにバージョンが表示されてたらインストール完了。

pyenvでpython3.xをインストール

Lambda の実行環境として Python3.6 を使いたいので、pyenv でインストールします。

まずインストール可能なバージョンの一覧を確認

$ pyenv install --list

一覧から、現時点の最新のリリースと思われる 3.6.1 が見つかったので、以下のようにインストール

$ pyenv install 3.6.1

インストールが完了したら、以下のコマンドでインストールされているバージョンを確認

$ pyenv versions
* system (set by /home/vagrant/.pyenv/version)
  3.6.1

このように 3.6.1 がインストールされていることがわかります。

pyenv-virtualenv で環境作成

# 一旦、 shell で利用する python のバージョンを 3.6.1 に切り替え
$ pyenv shell 3.6.1

pyenv-virtualenv では Python3系に標準添付の venv モジュールがあればそれが利用されますが、それ以下のバージョンでは virtualenv パッケージが別途インストールされている前提で動作するような挙動となっているようです。
もし、ここでバージョンを切り替えずに system 環境に virtualenv パッケージがインストールされていない場合、 pyenv-virtualenv の実行中ににエラーとなります。

# 3.6.1 に python3.6 という名前で環境を作成
$ pyenv virtualenv --python ~/.pyenv/versions/3.6.1/bin/python3.6 python3.6

–python ~/.pyenv/versions/3.6.1/bin/python3.6 の箇所が重要。
これが無いと、仮想環境の bin ディレクトリに python3.6 コマンドが無いため、前回の記事のようなエラーとなります。

プロジェクトディレクトリで利用するバージョンを指定

プロジェクトのディレクトリに移動して、利用するバージョン(環境名)を指定します。

$ cd path/to/project
$ pyenv local python3.6

ここで指定する python3.6 は前述の pyenv virtualenv コマンドで指定した環境名です。

上記コマンドの結果、カレントディレクトリに.python-version が出来て、このディレクトリ配下で利用するバージョン(環境名)が保存されます。

試しに現在のバージョンを確認します

$ pyenv version
python3.6 (set by /home/vagrant/path/to/project/.python-version)

# 念のため python3.6 コマンドにPATHが通っていることも確認
$ type python3.6
python3.6 は /home/vagrant/.pyenv/shims/python3.6 です

必要なパッケージをインストール

環境ができたのでこの中に必要なパッケージをインストールしていきます。
今回、Lambdaへデプロイする前提のため、boto3をインストールします。

$ pip install boto3

以上で、Serverless Framework を使うための環境が用意できました。

試しに Python3.6 向けの Lambda 関数をローカルで実行してみる

以下のようにテスト用のサービスを作ります。

$ sls create --template aws-python3 --path hello36
$ cd hello36

handler.py を以下のように変更

import sys
import json

def hello(event, context):
    return {
        "message": "Go Serverless v1.0! Your function executed with %s" % sys.executable ,
        "event": event
    }

ローカルでこの Lambda 関数を実行してみます。

$ sls invoke local -f hello
{
    "message": "Go Serverless v1.0! Your function executed with /home/vagrant/.pyenv/versions/3.6.1/envs/python3.6/bin/python3.6",
    "event": {}
}

無事、ローカル環境でも Python3.6 上で Lambda関数が実行できるようになりました。

実際、この Lambda 関数を AWS 上にデプロイして実行するためには serverless.yml をいろいろ設定する必要がありますが、その点についてはこの記事では触れません。

詳しくは Serverless Framework – AWS Lambda Guide などを参考にしてください。

さいごに

自分自身、まだ python の環境構築系のツールの使い方に慣れていないので、もっと良いやり方があれば指摘もらえると幸いです。

最後に、環境を構築するにあたって参考としたサイトを記載しておきます。

リスティング広告の費用対効果が高い理由と効果が高い企業の特徴3選

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

リスティング広告は一般的に費用対効果が高いと言われている。そこで本記事ではリスティング広告の費用対効果が高い理由と、特に高い費用対効果が期待できる企業の特徴を3つ紹介する。

リスティング広告の費用対効果は高いと一般的に言われているが、あなたはその理由をご存知だろうか。本記事では、なぜリスティング広告は費用対効果が高いのかの理由について解説し、さらに特に高い費用対効果が期待できる企業が持つ3つの特徴について紹介していく。

リスティング広告の費用対効果が高い理由1:高精度のターゲティングが可能

リスティング広告はGoogleやYahoo!等の検索結果の上部にある広告枠に掲載される。検索結果はユーザーがキーワードで検索した際に表示されるものだが、リスティング広告では管理画面上で「どのキーワードに広告を出すか」「どの時間帯・曜日に広告を出すか」「どの地域に広告を出すか」など、さまざまな条件を絞り込むことができる。そのため、商品が売れやすかったり、問い合わせが得られやすい”条件にだけ”広告を出すことができるのだ。

例えば、ターゲティングの条件には以下のようなものがあるが、それぞれを高精度で絞り込むことができる。

  • キーワードターゲティング:どのキーワードに広告を出すかを設定できる
  • 時間帯・曜日ターゲティング:どの時間・曜日に広告を出すか設定できる
  • 地域ターゲティング:どの地域・都道府県・市区町村に広告を出すか設定できる
  • 性別・年齢ターゲティング:どの年齢層・性別に広告を出すか設定できる
  • リマーケティング:サイトに訪問したユーザー等特定条件を満たした場合に広告を出すか設定できる

上記のターゲティングを組み合わせて使うことによって、本当にコンバージョン(商品購入・問い合わせ)が発生するところ”だけ”を狙って広告を打つことができるため費用対効果が高い。

リスティング広告の費用対効果が高い理由2:少ない広告費用でも効果が期待できる

マス向けの広告では費用対効果を計測することが難しいことが多く、実際に見られているのか、効果に繋がっているのかを調査するにはある程度分析スキルや環境が必要になる。

一方で、リスティング広告をはじめとするネット広告では理由1の高精度なターゲティングもあり、効果の高い条件だけに絞り込むことができるため、少ない費用からでも効果が出やすい。

また、アナログではなくデジタルな世界のため「どれだけ広告が見られたのか」「広告を経由して発生した商品購入はどれぐらいあるのか」「収益にどれだけインパクトがあったのか」などをリアルタイムに数値で確認することが簡単にできる。そのため、高い費用対効果を維持しやすいのである。

リスティング広告の費用対効果が高い理由3:広告設定チューニングで費用対効果の改善が可能

リスティング広告は、広告を打てば打つほどデータが蓄積する。その蓄積したデータをもとに、どういった条件の時に商品が売れやすいのか。問い合わせが得られやすいのかを把握することができる。そのため、以下のような設定をチューニングすることによって、コンバージョン率(商品購入されやすい・問い合わせされやすい)条件にだけ広告を出稿することができる。

1.キーワードで絞り込む

リスティング広告はどんなキーワードで検索されたときの検索結果に広告を出したいかを選ぶことができる。そこで、各キーワード別にコンバージョン率やクリック率が高いキーワードに”だけ”広告を絞り込む設定をすることによって費用対効果が改善する。

2.時間帯・曜日を絞り込む

管理画面やレポートでどの時間帯・曜日のコンバージョン率・クリック率が高いかも知ることができる。こちらも同様に効果の高い時間帯や曜日に”だけ”広告を絞り込むことで費用対効果が高まる。

3.地域で絞り込む

リスティング広告では地域・都道府県・市区町村など、かなり細かに広告出稿対象のエリアを設定できる。そこで、特定の地域に根付いたビジネスをしていたり、特定のエリアにだけ広告を出したい場合なども可能だ。広告効果の高い地域に”だけ”広告を絞り込むと費用対効果が改善する。

4.リマーケティング(RLSA)で絞り込む

リマーケティング広告という言葉を聞いたことがないだろうか。この機能は上記の3つと比べると少し難易度が高いが、WebページにJavaScriptのソースコード(いわゆるタグ)を埋め込んでおくことで、サイトに訪問したことがあるユーザーをリストに登録することができる。これがリマーケティングリストだ。

リマーケティングリストを活用したリスティング広告をRLSA(リマーケティング・フォー・サーチ・アド)といい、つまりリスティング広告にリマーケティングリストを使うことができる。これはとても革新的なことで、自社のサイトに興味を持って、サイトを訪問したことがあるユーザーは商品購入率や問い合わせ率が高い傾向にある。そういったユーザーだけに絞り込んで費用対効果を高めることができる。

5.性別・年齢(DFSA)で絞り込む

デモグラフィックという言葉がある。これはユーザーの性別や年齢層のデータを示している。リスティング広告の中でこちらも新しめの機能だが、ユーザーの性別や年齢層を設定できるDFSA(デモグラフィック・フォー・サーチ・アド)がある。この機能を活用することによって、効果の高い特定の性別や年齢層に絞り込むことができるため費用対効果を高めることができる。

特に費用対効果が期待できる企業の3つの特徴

リスティング広告には相性が良い企業特徴というものが存在する。以下の3つの特徴を持っている企業の場合は、比較的高い費用対効果が期待できる。

企業ブランド・商品ブランドが既に認知されている

リスティング広告とブランド力はとても相性がいい。なぜならブランドが認知されていると”検索される”からである。ブランドが認知されていればされているほど検索ボリュームが多くなり、いわゆる”ブランドキーワード”つまりブランド名を名指しで検索しているワードに対してリスティング広告を打てば、高い費用対効果が期待できる。

SEO(自然検索経由)流入で既にコンバージョンしている

SEO、つまり広告枠ではなく、自然な検索でサイトへ訪問したユーザーが既にコンバージョンしているケース。この場合はSEOで効果が高いキーワードにリスティング広告を打つことで、最初から高い費用対効果が期待できる。

中には、SEOで既に1位や2位のキーワードに、リスティング広告を打つ意味があるのか?と思われるかもしれないが、実際にPCやスマホの検索結果を見てほしい。リスティング広告をはSEOの自然検索枠よりも”上”に表示される。これは特にスマホでは画面の大半を占めることになる。そのため競合よりも自社のサイトに訪問してもらうために、SEO・リスティング広告の両面で上位を獲得することには意味がある。

1コンバージョンあたりの売上・利益が高い

例えば転職・求人サービス等のように紹介単価の高いサービスであったり、ある程度単価の高い商品を取り扱っているECサイト等の場合は1つのコンバージョンを手に入れるために、使える広告予算が高い。そのため、データの蓄積が容易であるため、絞り込みの精度が高くなりやすく、リスティング広告と相性が良い。

最後に

リスティング広告は基本的には費用対効果が高い集客施策として知られている。しかし、上記の費用対効果を改善する体制やノウハウが無く、あまり良い効果を得られていないケースもあるかもしれない。そういった場合はまずこの記事に書かれている項目について設定の改善を試みてほしい。

また、効果が期待できる3つの特徴に当てはまっているが今現在リスティング広告を導入していない場合は、ぜひ費用対効果の高いチャネルの1つとして検討してみてほしい。


■アピリッツのリスティング広告出稿代行サービス

弊社アピリッツでは、上記をふまえたリスティング広告出稿代行サービスを行っています。

現在のリスティング広告の効果に満足できていない。もっと改善する余地があるのではないか。
また、これからリスティング広告を導入したいが、高い費用対効果に向けて取り込んでいきたいと考えている担当者様。

お問い合わせ・ご相談を承っております。
サービス詳細 | リスティング広告出稿(SEM)代行サービス | アピリッツ

`sls invoke local` すると`Error: spawn python3.6 ENOENT`と言われた

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Serverless Framework 使ってみてますが便利ですね。Serverless Frameworkの「売り」のひとつである「ローカル環境での Lambda関数の実行」がなぜかエラーになっていたので少し突っ込んで調べてみました。

環境

以下のような環境で確認しました。

  • macOS 10.10.5 (Yosemite)
  • python 3.6.1 (pyenvでインストール)
  • Serverless Framework 1.14.0
  • node 4.4.5

原因

serverless コマンドのソースコードを覗いてみました。
どうやら、lib/plugins/aws/invokeLocal/index.js の ここ や ここ で process.env の 環境変数 PATH を書き換えているが、pyenvでインストールしている python3.6 にPATHが通っていないため発生している模様。

対処

最初、Serverless Framework側にプルリク投げる必要があるかと思ったが、いろいろ見たら、pyenv はいらないという結論になったのでpyenvをアンインストール。

あらためて pytho3.6 をインストール

$ brew install python3

boto3 も入れ直す

$ pip3 install boto3

以上で正常に動作するようになった。

さいごに

最近、rbenv で Ruby 環境を構築するのに慣れてて、同じ感覚で Python 環境も構築してましたが、ちょっと勝手が違ったようです。

今回は、Python 2.x 系と 3.x 系を共存させたいという要件はなかったため、Python 3.6 をそのままインストールしてしまいましたが、共存させる場合は前述の Qiita の記事にあるように virtualenv(venv) 使うのが良さそうです。

2017/6/4 追記

この記事では pyenv をやめて直接 Python3.6 をインストールしたという結果になりましたが、後日調査して pyenv でも Python3系でのローカル実行できる環境が作成できることがわかりました。
以下の記事をご覧ください。

method_missingを使ってみる

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

method_missing とは

何かメソッドを呼び出したとき、
rubyはそのクラスに該当メソッドがあるか捜索し、なければ継承元のクラスを捜索しに行きます。
これはごく普通の挙動ですよね。

ですが捜索した結果該当メソッドが存在しなかった場合呼び出されるのが method_missing です。
これをうまいこと使うとコードが一気に短縮できるのでそのパターンを紹介します。

実際以下のようなクラスがあった場合を想定します。

class User
  def update
     puts "更新されたよ"
  end

  def login
    puts "ログインしたよ"
  end
  # more methods...
end
class UsersManager
  def initialize
    @array_users = []
  end

  def add_user(user)
    @array_users << user
  end

  def update 
    @array_users.each do |user|
      user.update
    end
  end
end

UsersManagerが持っている配列内のUserのメソッドをまとめてコールするというだけのものです。

manager = UsersManager.new
manager.add_user(User.new)

manager.update
=> "更新されたよ"

問題なく使用できると思います。

ですが今の状態で下記のように実行すると

manager.login

NoMethodError: undefined method `login'

もちろんエラーになります。
単純に考えるとUserManagerにloginの処理を追加すれば実行できますが、Userが100や150のメソッドを持っていてそれらも実行しようとしたとき、その数分メソッドを作るのは現実的じゃないですよね。

method_missingを利用してみよう

上の実行ではNoMethodErrorが出力されています。
rubyでは呼び出されたメソッドが存在しなかった場合に

manager.send(:method_missing, :login)

が呼ばれ、その結果NoMethodErrorになります。

これがどうかしたのかというと、あくまでただのメソッドなので
継承先に method_missing を実装してやることで挙動を制御することができます。

先ほどのクラスに method_missing を下記のように実装して実行すると、

class UsersManager
  def initialize
    @array_users = []
  end

  def add_user(user)
    @array_users << user
  end

  def method_missing(name, *args)
    @array_users.each do |user|
      user.send( name, *args )
    end
  end
end
manager = UsersManager.new
manager.add_user(User.new)

manager.login
=>ログインしたよ

という形になります。
これは呼び出したメソッドがUserManagerクラスに存在しなかったので method_missing が呼び出されるのですが、その時UserManagerクラスに method_missing がないか捜索してくれるのでこのような実行結果になるわけです。

こうすればUserクラスにどれだけメソッドが増えたとしてもUserManagerには処理を追加する必要がなくなります。
とっても便利ですよね。

使用時の注意点

無限ループに陥りやすい?

method_missingを記述するとき、「継承元にあるmethod_missingは呼ばれない」ということに気をつけなければいけません。
例えば先ほどのUserManagerクラスを以下のように変更します

def method_missing(name, *args)
  self.hoge
  @array_users.each do |user|
    user.send( name, *args )
  end
end

この状態でmethod_missingが呼ばれると

manager.login
=>output error: SystemStackError: stack level too deep

どうやらStackOverFlowが起こっているようです。

self.hogeが存在しない -> method_missingが呼ばれる -> self.hogeが存在しない -> ……
といった風に無限ループを発生させてしまっています。

今回のパターンではかなり露骨な書き方をしているのでわかりやすいですが、NoMethodErrorは比較的やってしまいがちなエラーだと思います。それがいきなりStackOverFlowになってしまうので、この危険性は頭の隅に置いておかないと何のエラーだかわかりにくく危険です。

処理を追いにくい

method_missingを使用したコードを他の人が追おうとした時、クラスに呼んだメソッドが記述されていなかったらまず親クラスのメソッドなのかと疑うと思います。そもそもmethod_missingを知らない人はどうしようもないですよね。

まとめ

実際うまく使えたらとっても便利だと思いますが、
method_missingを知っておかないと何をしているのか分からないコードだなという印象を強く感じ、
こういった特殊な動きをするものは知識として入れておかないといけないなと再認識できました。
これから先難解なコードに手をつける機会が訪れた時に迷うことを極力減らせるように、rubyの知識を増やしていこうと思います。

systemd でデーモン化しつつ logrotate に対応したスクリプトを書く

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ときどき、「rubyでちょっとしたデーモンを動かしたい」かつ、「出力されるログファイルもローテーションさせたい」ということたびたび発生します。 そんなとき、どのようにスクリプトを組むのが良いかという点についてまとめてみました。

TL;DR

ポイントは以下です。

  • ふつうにRubyのスクリプト書いて systemd でデーモン化する
  • logrotate の postscript の中で実行中のスクリプトに対してUSR1を送出する
  • スクリプト側ではUSR1シグナルを受け取ったらログファイルをreopenする

スクリプト本体

デーモンとなるスクリプト本体です。

log_file = File.expand_path("hoge.log", File.dirname(__FILE__))
pid_file = File.expand_path("hoge.pid", File.dirname(__FILE__))

# pid 作成
File.write(pid_file, Process.pid)

# logger 初期化
logger = Logger.new(log_file)
logger.level = Logger::INFO

$reopen_log = false

# USR1シグナルでログのreopenフラグを立てる
trap("USR1") do
  $reopen_log = true
end

# 終了時に pid ファイルを削除
END {
  File.delete(pid_file)
}

loop do
  # フラグ立ってたらログを reopen する
  if $reopen_log
    logger.reopen(log_file)
    $reopen_log = false
  end

  logger.info "hogehoge---"
  sleep 10
end

スクリプトのポイント

いくつかポイントとなる箇所があるので解説。

プロセスIDをファイルに出力する

理由は、logrotate の postrotate のスクリプトで kill -USR1 でプロセスに対してシグナルを送出するためです。

# pid 作成
File.write(pid_file, Process.pid)
# 終了時に pid ファイルを削除
END {
  File.delete(pid_file)
}

シグナルを受け取ってログを再オープンする

普通にログローテートすると、対象ファイルがローテーションした際、既存のファイルがリネームされて新しいファイルが作られるが、reopenしないとずっと古いファイル(リネームされた方)に出力されてしまう。
そこで、USR1(たいていUSR1が使われるらしい)のシグナルを捕捉して、シグナルを受け取ったらreopenする処理を組み込む。

# USR1シグナルでログのreopenフラグを立てる
trap("USR1") do
  $reopen_log = true
end
  # フラグ立ってたらログを reopen する
  if $reopen_log
    logger.reopen(log_file)
    $reopen_log = false
  end

ちなみに、trap()のブロック内(シグナルハンドラと呼ぶらしい)でreopenしてみましたが、Threadがなんちゃらというエラーが出て落ちてしまいました。
一般的にシグナルハンドラの中では入出力を伴う処理等を行うのはよくないらしく、フラグを立てるくらいしたほうが良いらしいです。

systemd に登録するやつ

特に解説はしません。
Systemdを使ってさくっと自作コマンドをサービス化してみる – Qiita などを参考に。

[Unit]
Description = xxxx daemon

[Service]
ExecStart = /home/xxxx/.rbenv/shims/ruby /path/to/hoge.rb
Restart = always
Type = simple
User = hoge
Group = hoge

[Install]
WantedBy = multi-user.target

このファイル名 hoge.service がサービス名(hogeと省略可能)となります。

logrotate

日毎のローテーションで、履歴を10件保持する設定です。
この設定のポイントは、postrotateのブロックに記述されたスクリプトで、kill -USR1 $(cat $pid) の部分です。
これによってローテーション完了後、スクリプトにUSR1シグナルが送出され、それによってスクリプト側ではログファイルがreopenされ、結果としてローテーション後の新しいログファイルにログが出力されるようになるという仕組みになっています。

/path/to/hoge.log {
    daily
    rotate 10
    missingok
    su hoge hoge
    create 0600 hoge hoge
    postrotate
        pid=/path/to/hoge.pid
        test -e $pid && kill -USR1 $(cat $pid) || true
    endscript
}

デーモンの起動/停止

以下のコマンドでデーモンが起動します。

$ sudo systemctl start hoge

停止は以下

$ sudo systemctl stop hoge

さいごに

こんな感じで、意外なほど簡単にRubyで気軽にデーモンが作れるのでbotとかいろいろ作ってみたらどうでしょうか。

ActiveRecord::Relationの落とし穴

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

モデルをwhere句等で取ってくると、ActiveRecord::Relationが返ってくる。それを利用した操作はとても遅くなる時があった。

近況+直面した問題

 おやつをこんにゃくゼリーにしたら便通が良くなったHelloWorld?です。
 Ruby, Railsを学び始めて合計2ヶ月程(事前研修+入社してから1か月半)が過ぎ、新機能の実装をちょっとずつやり始めるようになりました。
 その機能の実装の一つで、普通に実装したらそのメソッドを実行するのに5秒程掛かっていてこれじゃあ運用できないよ、となっていたのが、ボトルネックを調べてそこ辺りの解消を試みてみたら、実行に掛かる時間が0.5秒以下まで抑えられたと言う事がありました。
 その理由を突き詰めてみました。
(バージョンは以下の通りです。
Rails: 4.1.9
Ruby: 2.1.5p273
Mysql: 5.6.36
)

原因、解決

 実際の実装でボトルネックを調べると、
 実装する為に分割した一つの、以下のようなメソッドに問題がありました。

    find_suitables(w_models)
      ret_models = []
      w_models.each do |model|
        if ...
           ...
          ret_models << model
        end
      end
      ret_models
    end

 w_models: 別のモデルからwhere句で取ってきたActiveRecord::Relation

 この中で、each文の中身が一番のボトルネックかな、と思っていたのですが、一向に軽くならないので、each文の中身全て削除して時間を計測してみたら、そのeach文そのものに時間をかなり取られていた事が分かりました。
 さて、これはどう解決すれば良いんだろう、と思って。
 試しに一旦そのw_modelsの型をActiveRecord::Relationからハッシュや配列に変換してからeach文に入れてみたら、劇的な動作速度の向上が出ました。
 でも、ActiveRecord::Relationから変換するにも、取ってきてから変換しているんじゃ意味が無いよな、と思って色々調べてみたら、以下のページが見つかりました。
http://qiita.com/yut_h1979/items/4cb3d9a3b3fc87ca0435
 ActiveRecord::Base.connectionから生SQLでDBにアクセスできる! そして返り値を配列やらハッシュやらで取ってこれる!
 これは使うしか無いな、ともう、自分のコードの中でActiveRecordを使っていた部分の大半をこれで生SQLを打ち込んで、コードもActiveRecord::Relationからハッシュや配列を扱うようにしたら、実行に掛かる時間がとても短くなりました。

検証

 実装した後、(テストコードも実装して)ちょっとその理由を様々な観点から確かめてみる事にしました。
 以下のように十分なレコード数がある適当なモデルからデータをActiveRecord::Relation、hash、arrayの形式で取得してきて、

    def take
      ar = ModelX.where("id <= #{NUMBER}") #ActiveRecord::Relation...takeで取ってくると配列になる。
      hash = ActiveRecord::Base.connection.select_all("SELECT * FROM model_xes LIMIT #{NUMBER}").to_hash #hash
      array = ActiveRecord::Base.connection.select_rows("SELECT * FROM model_xes LIMIT #{NUMBER}") #array
    #NUMBER: 1000, 2000, 3000, 4000,idに抜け落ちはありません。
    end

 時間の計測に関しては、測りたいコードの前後に

    time = Time.now
    code
    time = Time.now - time
    print "#{time}"

 を書けば小数点以下の時間も計測出来るとのことです(後で、benchmarkの存在も知りました)。
 eachで回したり、findと線形探索を比較してみたり、他にも様々な検証をrailsのコンソール上でしてみました。

 以下のメソッドをtakeからそれぞれ呼び出してみて、時間を計測しました。

    def get_each_time(ar, hash, array)
      time = Time.now
      ar.each do |n|
        if n.id % 10 == 0
        end
      end
      time = Time.now - time
      print "#{time}"

      time = Time.now
      hash.each do |n|
        if n["id"] % 10 == 0
        end
      end
      time = Time.now - time
      print "#{time}"

      time = Time.now
      array.each do |n|
        if n[0] % 10 == 0
        end
      end
      time = Time.now - time
      print "#{time}"
    end

    def get_find_time(ar, hash, array)
      id = ar.count * 3/4 #どのような探索でもちょっと探索をするような値を。
      time = Time.now
      ar.find(id)
      time = Time.now - time
      print "#{time}"

      time = Time.now
      hash.each do |n|
        if n["id"] == id
        break
        end
      end
      time = Time.now - time
      print "#{time}"

      time = Time.now
      array.each do |n|
        if n[0] = id
        break
        end
      end
      time = Time.now - time
      print "#{time}"
    end

    def get_find_by_time(ar, hash, array)
    #絶対に条件に引っかからないものを検索
      time = Time.now
      ar.find_by(A: 'AAA', B: 'BBB', C: 'CCC')
      time = Time.now - time
      print "#{time}\n"

      time = Time.now
      hash.each do |n|
        if n["A"] == "AAA" && n["B"] = 'BBB' && n["C"] == "CCC"
          break
        end
      end
      time = Time.now - time
      print "#{time}\n"

      time = Time.now
      array.each do |n|
        if n[1] == "AAA" && n[2] == "BBB" && n[3] = "CCC"
          break
        end
      end
      time = Time.now - time
      print "#{time}\n"
    end

 その結果は以下です。



 eachにおいては時間の軸を対数にしないと、全部表示できないようなレベルの差が出ました。これは、 SQL呼び出しの時間を鑑みても、無視できないレベルです。
 また、それぞれをメソッドとして呼ばずに、takeのメソッドの中でそのまま呼び出した場合をグラフにしてみると。


 find_byで値に変化が生じました。これはキャッシュ関連の問題だと思います。

結論

 each, findの操作をする時は、ActiveRecord::Relationを使用するべきではない、というよりActiveRecord::Relationは極力使うべきでは無い、と自分は思いました。
 1000以上のレコード数のときではありますが、大抵の場合ハッシュや配列よりも時間が掛かっていますし、また、一気に処理時間が多くなるような事も容易に起こり得るようなものだと自分は危険視し始めています。

 実際の実装の時は、ハッシュを利用しました。
 配列の方が速いときもありますが、そう大きな差ではありませんし、また、可読性の面からも見て、ハッシュの方が良いと思ったからです。

展望

 現在配属されているプロジェクトにおいて、似たような事でちょっと遅くなっているメソッドとかがあれば、同様にして処理の時間を減らせたらな、と思っています。

後日

 なぜ、ActiveRecord::Relationが特にeach文では遅いかという理由を、この記事を読んだ同じ会社の同期や先輩からご教授頂きました。
 その理由は、ActiveRecord::Relationは、where句で取ってきたタイミングではなく、each文の中で初めてSQLを叩いているからだ、という結論で。
 なので、一番最初に行ったeachの比較でActiveRecord::Relationだけ、SQL文を叩いた時間を含める事となったようです。
 という訳で、どうやら、検証自体が余りフェアなものでは無かったのかもしれません。
 ただ、find, find_byに対しては多分大丈夫だと思います。後日、再度検討してみます。

https://doruby.jp/users/mkobayashi/entries/ActiveRecord–Relationとは一体なんなのか
 同期がそれに関して詳しく調べた記事を書いたので、そのリンクも載せておきます。

https://doruby.jp/users/hello_rails/entries/ActiveRecord–Relationの落とし穴-解決編
 後日、再度検討しました。

自社ブログで記事を書く人必見!無理せず読まれる記事を書く4つのポイント

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

この記事は、これからDoRubyに記事を投稿していくであろう新卒の皆様向けに「そんなに無理をしないでできるSEOライティング」について書いていく記事である。

この度、弊社アピリッツにも2017新卒の皆様が入社された。この場を借りて、入社おめでとうございます。

ところで、アピリッツには入社してしばらくすると、新卒合宿なるものがある。その合宿では毎年、会社をもっと良くするための課題が出される。今年は度重なる話し合いのすえ、この”DoRuby”に持ち回りで記事を投稿して盛り上げよう!という話になったらしい。対象は新卒全員。どうやら1ヶ月に1記事ずつ、おそらく今月あたりから、入社2年目の今頃まで投稿していくそうなので、人数を考えると、大まかに200から300記事くらいは投稿されそうな予感がしている。私も去年の5月頃、新卒にもかかわらずDorubyのサイトリニューアルに関わらせて頂いたので、新生DoRubyが少しずつ成長していくようで非常に嬉しい。

この記事は、これからDoRubyに記事を投稿していくであろう新卒の皆様向けに「そんなに無理をしないでできるSEOライティング」について書いていく記事である。

そもそもSEOとは何か?

おそらく、これを読んでくれている方の中には少なからず『SEOってなに?初めて聞いた。』と疑問を抱いている方もいるかと思う。一言でいうと「Googleなどの検索エンジンで検索にヒットして、かつ、できるだけ上部に掲載するための技術と考え方』だ。もしかすると、この記事に書いてあることを参考にして記事を書いてみると、検索したときに自分の書いた記事がでてくるかもしれない。

なぜ検索結果の上の方に掲載されたほうがいいか?

もう少し前提の話をすると、Dorubyに投稿した記事は、検索されたときに検索結果の上部にあった方がいい。例えば、検索結果の1位と2位では記事が読まれる確率に10%~20%くらいの差がある。なのでなるべく上にあったほうがいい。


仮に「読まれる記事 書き方」というキーワードが月に1,000回検索されているとする。そのときに1位に記事があると月に300回くらい誰かが読んでくれる。これは検索ユーザー全体の30%にクリックされたことになる。一方、2位では100回くらいしか読んでもらえなかったりする。これだと全体の10%程度にしかクリックされていないことになる。あくまで傾向なので、かなりざっくりしているが、とにかく差がある。詳しく知りたい人は、この記事が参考になる。検索順位別クリック率(CTR)と年代別推移まとめ

検索結果の1位になるのがゴール?

1位になってもその先がある。検索結果の中でクリックされるかどうか問題である。これも記事のタイトルのつけ方だったり、記事の説明文の内容だったりで結構変わってくる。例えば、nanapiというサイトは、記事タイトルや概要文を徹底的に書き直し、クリックされる確率を40%以上にあげたという話がある。同じ1位でも更にユーザーがきてくれる確率が上がっている。ちなみに40%はめちゃくちゃ高い。平均は30%前後。それについてはこの記事が参考になる。nanapiが人力でやっている細かすぎるが効果的なグロースハック

ちなみにnanapiのグロースハッカー(SEOの戦略とかを考えている人)はこの人。けんすう@kensuu
Webマーケティングに詳しくなりたい人はフォローしておくとよいかもしれない。

ここからは、そんなに無理をしないで、検索結果にヒットさせつつ1ページ目の上部に掲載されやすくなるSEOライティングの方法について書いていく。

誰かに読まれる記事ってどんな記事?

まずはこれを自分のことに置きかえて考えてみてほしい。どんなときにググるのか?おそらく、何かを知りたいときだったり、欲しいものを買うときだったりすると思う。つまり、何らかの悩みを解決したいときに検索する。知りたい。見たい。買いたい等。

なので、記事を書くときは、以下を考えてみてほしい。

  • そもそも誰がどんなことで悩んでいるときに役に立つ記事なのか?
  • その悩みを抱えている人は、どんなキーワードで検索をするか?
  • その悩みはどんな情報があれば解決するか?

    実は、これ最強のSEOであり、↑の3つを一番しっかり考えているページが1位になる。

1.記事タイトルの考え方

まずは、その記事がどんな検索キーワードで検索してきた人が読むのか?を考えたときに思いついたキーワードを記事に含めよう。例えば、この記事は、「読まれる記事 書き方」などで検索する人にとって有益かもしれないので、このキーワードを含めてみる。

それと同時に、検索結果には30文字前後が表示されること。はてなブックマークなどのトップページでは32文字程度が表示されることを考えると、だいたい記事のタイトルは30文字ピッタリかどうか、ぐらいを狙って考えると良い。(ちなみにDorubyはサイト名とカテゴリ名が自動的にタイトルに含まれる設定なので、それを考慮して20文字くらいにすると良い。)

例えば、『自社ブログで記事を書く人必見!無理せず読まれる記事を書く4つのポイント|SEO|Doruby』 とかである。だが、仮にこの記事をこのタイトルで投稿しても、このキーワードの競合は強いので1ページ目に入るかは難しい。(”|”以降は自動部分)

2.記事の説明文の考え方

これはその記事が、検索されたときに検索結果のタイトルの下にでてくるものである。そのため、検索結果に並んだ時に、この記事を読みたい!となるような情報を書くといい。PCの検索結果では120文字、スマホでは50文字くらいが表示されるので、50文字で読んでも意味が通じて、120文字で読んでも大丈夫な説明文にするといい。重要な部分は前半の50文字に含めよう。

3.文章を1500文字以上書く。

一概に、文章量が多ければ多いほど、SEOに強くて検索上位にあがりやすいか?と言われると、悩みによって違う。しかし、おおよそ無理なく、かつ品質の高い記事のラインは1500文字程度ではないかと思う。なので、これくらいの文章量を超えることをまず目指すと良い。

4.見出しをつける

文章はある程度見出しが付いていたほうが読みやすい。それに検索エンジンにとっても、ページに書かれている内容が理解しやすい。なので、見出しをつけよう。

わかりやすければ、基本的に見出しは何でもいい、文字数も特に決まりはない。区切り方にも決まりはないが、少なくとも500文字に1個は見出しがあったほうがいい。

まとめ

ここまでのことを実践するだけでも、なにも意識しないで記事を書くよりSEOに強くて役に立つ記事になりやすい。

おまけ

記事のアイキャッチ画像は付けたほうがいいか?

付けたほうが良い。SEO的にも、ソーシャル流入を狙う観点でもアイキャッチ画像があると効果が高いと言われている。アイキャッチなので、なるべく記事と関連性がある画像や写真を使うといい。特に解像度が高くてサイズが合っていると記事に馴染む。よくわからないという人は、商用利用可能で高品質なフリー素材を提供している「ぱくたそ」にアクセスし、気に入った写真を使ってみよう。

ちなみにこの記事の写真はこれ。
なかなか仕事が捗らない新卒の女の子 [モデル:河村友歌]

SEOについてもう少し知りたい

SEOについておすすめのサイトの中でも、わかりやすく、SEOに詳しい人が良く見ているサイトは以下。

SEO HACKS
バズ部

関連記事や参考記事のリンクをはる

SEO的にも、記事の読者的にも、その記事と一緒に読むと役に立つ記事であったり、その記事の参考や情報ソースとなる記事へのリンクは有益なため、できることなら付けたほうが良い。その際、テキストリンクの文字列は、URLをそのままにするのではなく、この記事のようにリンク先の記事のタイトルであったり、関係のある文章にしよう。

どんな記事を書くか決めるのが難しい。記事執筆に時間がかかる。

そんな人は、仕事で覚えたことをメモやアウトプットとして整理して記事にしてみよう。Dorubyに記事を投稿するためだけに何かを勉強するのではなく、仕事で覚えたことを投稿すれば、既に知っていることを書くだけなのでネタも尽きないし、執筆もはやくなる。

SEO等について質問や要望があれば追記していきます

この記事を読んでみて、聞いてみたい事、調べてもでてこないことなどあれば気軽に質問をください。内容によっては追記していきます。

HTTPS使用暗号スイートをサーバーログ記録

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Webサーバー(Apache、Nginx)の利用者が、HTTPS通信時に使用するSSL(TLS)のバージョンプロトコルと暗号スイート(cipher)をサーバー側のログに記録します。

はじめに

Webサーバーのログに、SSL(TLS)のバージョンプロトコルと暗号スイートを記録しているでしょうか?
これらの情報を記録し、アクセス解析することによって、強度に問題のある暗号通信が、どの程度使われているか知ることができます。
また、クラウド環境など各種負荷が直接料金に反映されることもあるため、環境に適した暗号スイートを選択する際に必要な情報としても利用できます。

通信中については、スマホアプリのHTTPS通信をBurp Suiteで確認などを参考にしてください。

Webサーバーの設定方法

それぞれ設定ファイルの適切な箇所に下記を追加します。
ログのパス、ファイル名などは任意。同時に記録する内容は、公式マニュアル等を確認ください。
設定後、設定ファイルの再読み込みか、再起動を行ってください。

残念ながら、この方法でハンドシェイクの段階は記録できません。

Apache 2.4系

SSLOptions +StdEnvVars
CustomLog logs/ssl_cipher.log "%t %h %{SSL_PROTOCOL}e %{SSL_CIPHER}e %{SSL_SESSION_ID}e %{SSL_SESSION_RESUMED}e"

Nginx

log_format ssl "$time_local $remote_addr $ssl_protocol $ssl_cipher $ssl_session_id $ssl_session_reused";
access_log /var/log/nginx/ssl_cipher.log ssl;

ログ出力例

FirefoxとIE6で、記録したログは以下のような表示になりました。
バージョンプロトコルと暗号スイート(cipher)が記録されています。

SSL TLS cipher ログ

関係団体の公開情報など

BEAST、 Poodleなど、プロトコルに対する攻撃が有名です。

2015年06月、IETFがSSLv3の廃止を求めるRFC7568を公開しています。
またIPAも、SSL 3.0 の脆弱性対策について(CVE-2014-3566)を掲載しております。

ECサイトなどでも用いられるクレジット業界におけるグローバルセキュリティ基準 PCI DSSでは、
2016年11月からの審査基準 v3.2で、新規実装では、SSLプロトコル、初期のTLSが使用できません。
また、稼働環境でも2018年6月30日SSLプロトコル、初期のTLSの使用を停止する必要があり、それ以前にリスク軽減と移行計画が必要になります。
詳しくは、PCI Document Libraryを、確認してください。

参考サイト

SSL導入になどに、下記のサイトを参考にApacheの場合はSSLCipherSuite、Nginxの場合は ssl_ciphersを、設定ファイルに確実に記述しましょう。

SSL/TLS暗号設定ガイドライン~安全なウェブサイトのために(暗号設定対策編)~
IPAのサイトです。PDFで全93ページのSSL/TLS暗号設定ガイドラインや、チェックリストがダウンロードできます。

CRYPTREC
日本政府による暗号技術評価プロジェクト。

Mozilla SSL Configuration Generator
Mozillaが提供している、主要ミドルウェアのSSL設定ファイル生成サイト。

Symantec CryptoReport
Symantecが提供している、外部からのSSLチェックが実施できるサイトです。

SSL Server Test (Powered by Qualys SSL Labs)
Qualysが提供している、外部からのSSLチェックが実施できるサイトです。

おわりに

元々、ECサイトやマーケティングに重きを置いている組織では、機会損失になることを恐れ、対応端末の減るバージョンプロトコルや暗号スイートの見直しをなかなか行ってくれない傾向があります。
Googleアナリティクスなどを利用し、古いブラウザの使用状況や購入状況を確認して、見直すのがスマートです。
しかしながら、パフォーマンス測定など、実際使用された暗号スイートを記録したい事情がある場合などは、今回のようにログに記録してみてください。

関連記事など

脆弱性診断サービスなど

弊社、アピリッツではセキュリティ診断サービスを行っております。

下記リンクから内容の確認と、問い合わせが可能です。

http://security.appirits.com/

Kali Linux 2017.1 導入と日本語化

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Kali Linux(2017.1)をVirtualBoxにインストールして日本語化を行ってみました。Kali Linuxは、セキュリティ診断用ツールが標準で用意されている、Linuxディストリビューションです。新バージョン2017.3については、関連の記事を参照ください。

はじめに

Kali Linuxは、セキュリティ診断ツールを含むLinuxディストリビューションです。利用の仕方により不正アクセス行為と判断される可能性ががあります。またサービス停止やデータの破損が起こる場合もありますので事前にバックアップを行うなどしてください。そして必要に応じて管理者の許可を得て利用してください。

今回は、Light版の導入を行います。通常版については、下記の記事などを参照してください。

Kali Linux 2017.3 リリース

Kali Linux 2017.3 がリリースされてます。とても導入が楽になってます。新バージョンについては下記の記事も参照ください。
Kali Linux 2017.3 導入と日本語化

Kali Linuxの特徴などについて

  • Debian派生のLinuxディストリビューションです。
  • デジタルフォレンジック、ペネトレーションテスト(侵入テスト)用などのツールが用意されている。
  • 基本的に、root権限で作業を行う。
  • 現在は、ローリングリリースを採用している。
  • バージョン2017.1がリリースされた。

Kali Linux 公式サイト
https://www.kali.org/

主な収録ツール

今回はLight版を初期導入しますが、通常盤には多数のツールが導入されています。(Light版も容易に追加導入できます。)
Nmap、Aircrack-ng、Wireshark、Metasploit Framework、Armitage、Burp SuiteOWASP ZAP、BeEF、sqlmap、wpscan など

※Burp Suiteの日本語化については、Burp Suiteを日本語化する方法として記事を書いております。
※Owasp ZAPについては、Mac版のOWASP ZAPで脆弱性チェックの設定として記事を書いております。

VirtualBox上にインストールする

仮想化ソフトウェア、VirtualBoxをインストールし、Kali Linuxのイメージを導入、起動させます。

VirtualBoxをインストールする

あらかじめ下記サイトからダウンロードを行いVirtualBoxをインストールしてください。

VirtualBox 公式サイト
https://www.virtualbox.org/

Kali Linux イメージファイルのダウンロード

Kali Linux Downloads – Virtual Images イメージファイルのダウンロード先
https://www.offensive-security.com/kali-linux-vmware-virtualbox-image-download/

書いている時点で、直接ダウンロード出来るのはバージョン2017.1です。
中段のKali Linux VirtualBox Imagesタブをクリックし、環境に適したものをダウンロードします。今回は、Light版を導入してみます。

Kali Linux ダウンロード

Kali Linux 仮想アプライアンスのインポートと設定

VirtualBoxを起動し、ファイル、仮想アプライアンスのインポートで、先ほど展開したKali-Linux-Light-2017.1-vbox-XXXXX.ovaを選択しインポートします。

Kali Linux インポート

トラブルを避けるため、すべてのネットワークカードのMACアドレスを再初期化にチェックを入れます。

Kali Linux VirtualBox MACアドレス設定

デフォルトの設定でも問題はないですが、ネットワークの割り当ては、診断対象環境との通信の関係上、ブリッジ などがよいかと思います。その他は、好みによって設定を変更します。私はメモリを4GBぐらいにしています。

Kali Linux VirtualBox ネットワーク設定
Kali Linux VirtualBox メモリ設定

Kali Linuxの起動と更新

Kali Linuxの起動を行いログインします。Kali Linuxのパスワードは、toorに設定されています。
 ユーザー名:root
 パスワード:toor

Kali Linux ログイン画面

他のパッケージ導入前に、既存のパッケージを最新に更新してしまいましょう。
画面下部の黒っぽいアイコンのターミナルを起動します。
そして下記のコマンドを入力します。しばらく時間がかかり、確認のため途中にyなどの入力が必要となります。

# apt-get update
# apt-get upgrade

Kali Linuxの日本語利用について

英語環境のまま利用している方も多いようですが、ここでは日本語で利用できるように設定します。

1. Kali Linuxの日本語設定

ターミナルからコマンドで設定変更します。
変更画面では、タブキー、スペースキー、エンターキーなどを使います。

ロケールの変更

# dpkg-reconfigure locales

ja_JP.UTF8 を選択します。

Kali Linux ロケール変更1
Kali Linux ロケール変更2

キーボードの変更

日本語キーボードを利用できるようにします。

# dpkg-reconfigure keyboard-configuration

106キーが、ぱっと見で見当たらなかったのでとりあえず105キーで進めます。

Kali Linux キーボード変更1

Otherを選びます。

Kali Linux キーボード変更2

2回ほどJapaneseを選びます。あとはデフォルトでよいかと思います。

Kali Linux キーボード変更3

タイムゾーンの変更

タイムゾーンを環境に合わせて変更します。今回は東京に合わせます。

# dpkg-reconfigure tzdata

Asiaを選びます。

Kali Linux タイムゾーン変更1

Tokyoを選びます。

Kali Linux タイムゾーン変更2

2. Kali Linuxへ日本語関連パッケージの導入

下記コマンドで日本語関連パッケージをまとめて導入してしまいます。

# apt-get install task-japanese task-japanese-desktop

完了したら、一度シャットダウンして起動しなおします。

3. Kali Linuxの日本語変換の設定

Mozcがroot権限で、そのまま動かないため、ここではMozcを無効にします。
Mozcを利用したい場合は、一般権限で動作する別のディストリビューション(BackBoxなど)をお勧めします。Mozc自体の変更でも動作させることはできるようです。

右上のアプリケーション 設定 入力メソッド(青いアイコンの方)を選択します。

Kali Linux 日本語入力メソッド

使用可能にする入力方式を編集します。

Kali Linux 日本語入力方式

Mozcを無効にします。

Kali Linux Mozc無効

通常版のパッケージ追加

Light版は、導入されているツールが少ないです。
下記のコマンドで、通常版と同様のツールをまとめて導入できます。

# apt-get install kali-linux-full

Kali Linux 2017.1 導入完了

Kali Linux 2017.1 Lightを、VirtualBoxにインストールし日本語表示、日本語キーボードの利用、日本語変換が行えるようになりました。

Kali Linux 日本語化

関連記事など

脆弱性診断サービスなど

弊社、アピリッツではセキュリティ診断サービスを行っております。
下記リンクから内容の確認と、問い合わせが可能です。

http://security.appirits.com/

アピリッツの新卒合宿2017

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。久々に記事を書きます。 今回は、今年の新卒合宿の風景をご紹介したいと思います。

今年は、新卒26名と先輩社員で千葉県にある「リソルの森」に行って参りました。
運良く前日降っていた雨も上がり、清々しい朝を迎え緑いっぱいの目的地へ到着。
enter image description here

早速、研修室に集合してグループワーク開始!緊張する新卒の皆さん。
enter image description here

おじさんたちが見守る中、毎年グループワークを中心に、様々な難題をクリアしていくのですが、今年はアイスブレイクとしてゲーム性のあるグループワークをはじめに行いました。緊張していた面々も一つ目のグループワークを行うことで、コミュニケーションが取れはじめました。
enter image description here

意見をまとめて各グループでの発表。最初の発表は流石に緊張してましたが、徐々にペースを掴み自分たちの言葉でしっかりと自分たちの意見を発表していました。
enter image description here

その後、様々な難題を力を合わせクリアしていき、夜は付き添って頂いた先輩社員とBBQをしながらコミュニケーションを取りました。(轆轤を回す魚谷取締役
enter image description here

掲載できる写真だけアップします。
enter image description here

そして翌日は、また朝から課題をクリア。
運動を行い、大浴場で汗を流して、最後の課題。
とある新卒に全ての笑いを持っていかれるというハプニングもありつつ、疲れと反省でぐったりしながら帰宅の途に就きました。

フレッシュな新卒の皆さんが、社会人としての心得を感じ取り、キリリとした表情に変わっていく、そんな合宿なのでありました。(先輩社員たちは、それはそれで刺激を貰っております)

また来年忘れなければ、合宿の風景をアップしたいと思います。

Rails×Basic認証×Rspecでつまづいた

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

 入社してから3週間目の新入社員、HelloWorld?です。
 現在、先輩から渡された課題をある程度こなした頃です。
 その課題に関しては色々とつまづいた所があって、その一つに対してこのappiritsでこういうサイトがあるよー、という事でアウトプットしてみようかなと(新卒一番乗りしたかったのもあるよ!)。

 で、問題のつまづいた所に関して、の前にどういう課題を渡されたかに関して大まかに。
 ・Railsを使って簡単な擬似管理画面を作る
 ・Rspecでテストコードを入れる
 この他にも様々な要件がありましたが、取り敢えず問題となったのは、この組み合わせで起きた事でした。

 後、自分のスキルも提示しておきます。
 ・プログラム経験:大学で4年間、主にC,C++、それから多少のJava,Javascript
 ・Ruby,Railsに関してはこのAppiritsでインターンの時に2週間教わった+社員となってからの2週間程度
 ・フレームワーク使用経験は上記のみ
 プログラム自体は書き慣れてはいるけど、フレームワークとかは使った事ないよー、という感じです。


 そして、詰まった所に関して。

 管理画面という事で、Basic認証を導入してみて。そして、Basic認証を通してテストコードも書こう、という事をやってみる事にしました。
 実装した所で参考にしたサイト:
 http://threetreeslight.com/post/59357292457/rspecにおけるbasic-auth対応

 Basic認証設定部分。全てのページに対して掛けています。
app/controller/apprication_controller.rb

class ApplicationController < ActionController::Base  

protect_from_forgery with: :exception
before_filter :basic

    private
      def basic
        authenticate_or_request_with_http_basic do |user, pass|
          user == 'user' && pass == 'admin'
      end
end

Controllerのテストをさせる部分&テストをさせる為にBasic認証を通す部分
(DRYの為にSupportに書いてmoduleを作ったり、spec_helperに書き込んだりするべきだけど、取り敢えずここのテストしか書いてないので)
(更に加えるとテストする時はBasic認証とか外してテストするべきだよね、とか書いてあったりしたけど、今回はこういう事をしました、という事で)
spec/controllers/users_controller_spec.rb

RSpec.describe UsersController, type: :controller do

  before(:all) do
    @request.env ||= {}
    user = "user"
    pass = "admin"
    @request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pass)
  end

  describe "GET #index" do
...

結果
 動くけど、Basic認証通ってない!

 それから色々試した所、
 ・requestがそもそもnilだと言われていた。
 ・before(:all)に入れずにテスト単体それぞれでBasic認証を通すようにしたら通った。
  ┗before(:all)はその前のモデルのテストでちょっと使ったりもしたから、これは問題ないんじゃないか……と思って訳が分からなくなる。
 そこまで分かった後、先輩がちゃっと解決してくれました。

 その事が色々書いてあったりするサイト:
 http://qiita.com/srockstyle/items/6397c458d8f12dfcd02c
 http://nilp.hatenablog.com/entry/2014/05/28/003335


結論
 参考にしたサイトは、実装をした際に単一のテストしか記述していなくて。複数のテストに対してBasic認証を通す為には一つ、:allというホックに対して問題がありました。

describe MyClass do
  before(:each) { } # このグループのそれぞれのテストの前に実行される
  before(:all)  { } # このグループの最初のテストの前に1度だけ実行される
end

 before:allで一回だけ認証通しても、それぞれで認証通さないと全部弾かれてしまうよね、という結果でした。


修正
 spec/controllers/users_controller_spec.rbのbefore(:all)をbefore(:each)に変更。
 それだけ。


反省
 まだ合計で1ヶ月程もrubyに対してもrailsに対しても学んでいないから、仕方ない事だけれども、それぞれのメソッドとか、仕様とかに対して上部しか分かっていないなー、と。分かったつもりになっている、という事でここは間違いないだろう、と決めつけてそこをエラー箇所から外していたので、自分では見つけられなかった。
 まだ、そんな前提から疑わなければいけない段階でもあるし、そんな前提からこれからも疑っていたら時間が掛かり過ぎるし、デバッグの時間を削る為に、幅広い事が出来るようになる為にも積極的に知識を身につけていかないとなー、と。

プロジェクト管理するうえで簡単で効果のある小技みっつ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

たまごです。 今日は、プロジェクト管理するうえで簡単で効果のある小技をいくつかご紹介したいと思います。

新規参画者には、まずレビュータスクを振る

新規参画者がプロジェクトに入ってまずやる作業といえは、環境構築とドキュメント読みです。

自分も経験があるのですが、このドキュメント読みはなかなか苦行です。よくわからない状態で延々と文字を読まなければいけないのは、辛いことです。えてして「とにかく読み切ること」に目的がすり替わったり、場合によっては睡眠導入剤と化してしまうこともあるでしょう。

そこで、自分の場合は、新規参画者に早い段階でレビュータスクを振るよう心がけています。

ドキュメント読みはつまらないけれど、人の粗を探すのは楽しいものです。「レビュー」という実作業を振ることで目的も明確になります。最終的に得られる効果は、新規参画者の案件理解という点で同じなのですが、こちらの方がはるかに理解度が高まります。

プロジェクトとしても、新しい目線で仕様の抜け漏れを指摘してもらるので、WinWinです。

うろうろする

朝会はもちろん効果的ですが、15時とか17時とか、午後のどこかのタイミングで人員の島をうろうろするのがオススメです。

島をうろうろすると、意外と困っていたり、外から見れば自明のことで考え込んでいる場合があります。そういう場合、声をかけて数分話すだけで二時間とか半日の時間を買い戻すことができます。

これが積み重なると、大きいです。

進捗報告表を作る

朝会では、大体昨日の実績と今日の目標を喋ると思います。

なので、昨日の実績と今日の目標を記録する進捗報告表をexcelやスプレッドシートで作って、皆に書き込んでもらうとよいです。

今自分が使っているのは、左が日付で上が人員名になっている進捗報告表です(画像参照)。探せばもっとナイスなツールがあるかもしれませんが、今のところこれです。毎日朝会前までにこれを書いてもらい、朝会では書いた内容を報告してもらうようにしています。

メリットは色々あるのですが、ひとつは口頭だと見逃しがちな点に気付けることです。

何もなしに朝会をしていると、どうしてもその一日にフォーカスして聞いてしまいますが、報告内容を蓄積&一覧化していると、一週間の推移としてどうかという視点でチェックできます。

未来日のタスク計画を書いておくこともできます。「三日かかります」というなら、あらかじめ三日先まで目標欄を埋めてもらえばよいですし、マネージャからの指示があれば、それもあらかじめ書いておけばよいです。

よしんば何かの事情で朝会がスキップになった時も、報告表を一覧化しておけば安心です。ざっとチェックすれば、皆の進捗具合がわかるし、翌日にまとめて朝会する際も追うのが楽です。

CloudFrontの「Restrict Bucket Access」と「Restrict Viewer Access」の違いがよくわからなかったので検証してみた

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

CloudFront の設定項目「Restrict Bucket Access」と「Restrict Viewer Access」がそれぞれどのような役割をもっているか理解が曖昧だったので実験で検証してみました。

TL;DR

  • S3バケット上のオブジェクトのACLをprivateにすると一般ユーザはS3のURLでオブジェクトへのアクセスが行えなくなる。
  • Restrict Bucket Access を Yes に設定すると、ユーザ自身の代わりに「オリジンアクセスアイデンティティ」に設定された権限によりS3にアクセスできるようになる。
  • Restrict Viewer Access を Yes にすると、署名付きURL(または署名付きCookie)によるアクセスしか許可しなくなる。
  • Restrict Bucket Access を Yes, Restrict Viewer Access を No の組み合わせで設定したら、署名付きURL/署名なしURLいずれでもアクセス可能となる。さらに署名付きURLの期限が切れていても問題なくアクセスできてしまうので注意‼️

上記については以下の公式ドキュメントに詳しく記載されています。(といっても初見ではイマイチ理解できなかったので結局検証したんですが…😅)

CloudFront を使用してプライベートコンテンツを供給する – Amazon CloudFront

実験内容

実験方法は以下のとおり。

  • S3 バケットのオブジェクトは private (オーナー以外のアクセス権なし)と、public(EveryoneのRead権あり)の 2 種類用意。
  • S3 バケット自身には以下のように CloudFront のオリジンアクセスアイデンティティによる参照アクセスを許可(以下は例のためIDとかバケット名は存在しないものになっている)
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity xxxxxxxxxxxxx"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::xxxxxx-bucket/*"
        }
    ]
}
  • CloudFront で Restrict Bucket Access, Restrict Viewer Access それぞれの設定の組み合わせによって、S3の public/private それぞれのオブジェクトへのアクセス結果がどのようになるか検証。

実験結果

実験の結果は以下のとおり

実験結果

実験の結果以下のことがわかりました。
(以下では、Restrict Bucket Access を “Bucket”、Restrict Viewer Access を “Viewer” と表現してます)

  • Bucket:YES, Viewer:YES の場合:
    • 現時点で有効な署名付きURLでのみアクセス可能。
    • 署名無しのURLでアクセスするとステータス 403 でXMLのエラーメッセージとして”Missing Key”が返ってくる。
  • Bucket:YES, Viewer:NO の場合:
    • 署名付きURL/署名なしURLいずれでもアクセス可能。
    • しかも、署名付きURLの有効期限が切れてもアクセス可能。
  • Bucket:NO, Viewer:YES の場合:
    • publicなS3コンテンツに署名付きURLでのみアクセス可能。
    • privateなコンテンツに署名付きURLでアクセスすると、ステータス 403 でXMLのエラーメッセージは”Access Denied”が返ってくる。
    • privateなコンテンツに署名なしURLでアクセスすると、ステータス 403 でXMLのエラーメッセージは”Missing Key”が返ってくる。
  • Bucket:NO, Viewer:NO の場合:
    • privateなコンテンツには一切アクセスできない。
    • publicなコンテンツには署名付き/署名なしいずれのURLでもアクセス可能。

この結果で予想外だったのが2番目のケースで、「署名付きURLの有効期限が切れていたとしても関係なく普通にアクセスできる」という点でした。

Restrict View Access で署名付きURLによるアクセス制限をかけていないので、当たり前と言えば当たり前のことなんですが、予想外の結果でびっくりしました。

もし設定をミスっても署名付きURLで普通にアクセスできてしまい、あえて有効期限切れの場合のテストを行わないと設定ミスに気付かずそのまま本番運用…😱 なんてことにならないように注意が必要ですね。

まとめ

CloudFont + S3 でプライベートなコンテンツを配信する場合、S3及びCloudFrontを以下のように設定する必要がある。

  • S3は以下のとおり設定する
    • S3にオブジェクトをアップロードする際のパーミッションは private(オーナーのみアクセス可能)とすること
    • S3バケットはバケットポリシーでオリジンアクセスアイデンティティによるアクセスを許可すること
  • CloudFront ディストリビューションは以下のとおり設定する
    • Restrict Bucket Access を Yes に設定し、S3のバケットポリシーで許可されているオリジンアクセスアイデンティティでS3にアクセスするように設定すること
    • Restrict Viewer Access を Yes に設定し、署名付きURLによるアクセスを必須とすること

設定内容を正しく理解して安全にシステムを運用したいですね。

S3から複数のファイルを取得しつつ on-the-fly でZipを作ってブラウザに返す

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

S3にダウンロードさせたいファイルが複数あるが、zipファイルでまとめて1度にダウンロードさせたいが、そんなAPIはそもそも無いので zipline という gem を使ってみました。

課題

S3にダウンロードさせたいファイルが複数あるが、zipファイルでまとめて1度にダウンロードさせたい

解決策

  • EC2インスタンスで稼働しているWebアプリケーション側でS3上の複数のファイルをまとめてzipを作成
  • zipファイルを作成するそばからクライアントへレスポンスを返す(chancked response)
    • ちょうどそんなことをやってくれる zipline という便利な gem が存在する

(タイトル画像のようなイメージ)

テスト用アプリを作る

試しに Rails アプリケーションを作ってみる

環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.10.5
BuildVersion:   14F2109

$ ruby -v
ruby 2.2.4p230 (2015-12-16 revision 53155) [x86_64-darwin14]

$ rails --version
Rails 5.0.1

Railsアプリの準備

まず、準備として rails コマンドでアプリの雛形を用意

$ rails new zipline_test

上記が完了したら作成されたディレクトリに移動

$ cd zipline_test

Gemfileを編集して ‘zipline’ と ‘aws-sdk’ を追加してそれらのgemをインストール

$ echo "gem 'zipline'" >> Gemfile
$ echo "gem 'aws-sdk'" >> Gemfile
$ bundle install --path ./bundle

これでほぼ準備OK
アプリケーションを書いていく

ルートとコントローラを作る

まずURIを定義するため、config/routes.rb を以下のように編集。

Rails.application.routes.draw do
  get "download/zip"
end

次に、上記で定義したURIに対応するコントローラを定義する。
以下のコマンドでコントローラの雛形を作成。

$ rails g controller download

すると、app/controllers/download_controller.rb が作成されるので、そのファイルを以下のように編集。

class DownloadController < ApplicationController
  include ActionController::Streaming
  include Zipline

  AWS_S3_REGION = "ap-northeast-1"
  AWS_S3_BUCKET = "zipline-test"

  def zip
    zipline(s3files, "s3files.zip")
  end

  private

  # ダウンロード対象のファイルを順次zipに固めながら chunked response としてクライアントに返す
  def s3files
    s3 = Aws::S3::Client.new(region: AWS_S3_REGION)
    # ダウンロード対象のファイル
    files = %w(
      file1.json
      file2.json
      file3.json
    )
    files.lazy.map do |file|
      logger.debug "get file from s3 : #{file}"
      s3_object = s3.get_object(bucket: AWS_S3_BUCKET, key: file)
      

[s3_object.body, file]

end end end

  • AWS_S3_REGION は自分のS3バケットを作成したリージョンに
  • AWS_S3_BUCKET は自分のS3バケットの名前に
  • file1.json, file2.json, file3.json はS3バケット上のダウンロードさせたいファイル名に

サーバを起動する

あらかじめAWSに接続するためのcredential関係の環境変数(AWS_SECRET_ACCESS_KEY,AWS_ACCESS_KEY_ID)を設定してからサーバを起動する

$ export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxx
$ export AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxx
$ rails s

これで http://localhost:3000/で サーバが立ち上がるはず。

URIアクセスしてみる

ブラウザで http://localhost:3000/download/zip にアクセスするとダウンロードが始まり、zipファイルがダウンロードされるはず。

参考

Rubyのサポート期間一覧

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

脆弱性診断などで、各種ソフトウェアのバージョンやサポート期限について調べることが多い為、プログラミング言語 Rubyの公式サポート期間、サポート終了期限(eol)の状況について、簡単に一覧にまとめました。また、確認できる公式のリンクを記載しています。

公式サポート期間

Ruby eol サポート期間

バージョン
メンテナンス状態
最新リリース
最新リリース日
セキュリティサポート終了

2.7系
通常
2.7.1
2020年3月31日


2.6系
通常
2.6.6
2020年3月31日


2.5系
通常
2.5.8
2020年3月31日


2.4系
メンテナンス終了
2.4.10
2020年3月31日
2020年3月31日(予定)

2.3系
メンテナンス終了
2.3.8
2018年10月17日
2019年03月31日

2.2系
メンテナンス終了
2.2.10
2017年3月28日
2018年3月31日

2.1系
メンテナンス終了
2.1.10
2016年4月1日
2017年3月31日

2.0系
メンテナンス終了
2.0.0-p648
2015年12月16日
2016年2月24日

1.9系
メンテナンス終了
1.9.3-p551
2014年11月13日
2015年2月23日

1.8系
メンテナンス終了
1.8.7-p374
2013年6月27日
2014年7月31日

※2020年4月現在
正確な情報は、公式サイトなどをご確認ください。

参考サイト

Ruby Releases
https://www.ruby-lang.org/en/downloads/releases/

Ruby Maintenance Branches
https://www.ruby-lang.org/en/downloads/branches/

JVN iPedia 脆弱性対策情報データベース(Ruby)

その他

ソフトウェアライフサイクル考慮した保守契約を行いまいましょう。
リスク受容を選択しなければならない場合、リスクを把握したうえで、ステークホルダーと合意、責任の所在を明確にし書面などに記録しておきましょう。

※詳しくは、別途調べてください。

脆弱性診断サービスなど

弊社、アピリッツではセキュリティ診断サービスを行っております。

下記リンクから内容の確認と、問い合わせが可能です。

http://security.appirits.com/

Windows でも Mac でもツールを使用せずに元に戻せるファイル分割

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

サイズの大きなファイルを分割して共有したい。 けれど、共有する相手にWindowsユーザとMacユーザがいる。 という様な場合、WindowsでもMacでも使用できるファイル分割・結合ツールを使用する方法もあるが、 以下の方法でファイル分割すれば、専用ツールなしで(WindowsやMacの標準で)結合できるようになる。

分割方法 (Mac)

split origin.txt -b 100m -d splitted.txt_

origin.txtの部分は分割したい対象のファイル。
100mの部分は、分割したいファイルの単位。この例では100MBごとのファイルに分割される。
splitted.txt_の部分は、分割後のファイル名。この例では「splitted.txt_00」、「splitted.txt_01」、…という様なファイルが生成される。

結合方法(Windows)

copy /b splitted.txt_* origin.txt

結合方法(Mac)

cat splitted.txt_* > origin.txt

注意

残念ながら分割の方はMacで行うしかない。ただし、Windowsでもbashが使えるツールがあれば、使用できる。

3分リファクタリング SelectableAttr 編

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

社内でRails標準のEnumよりも多く使われているSelectableAttrについて。

EXAMPLE

カードのレアリティを 0 〜 5 の整数値で表現します

class Card < ActiveRecord::Base
  include ::SelectableAttr::Base

  selectable_attr :rarity do
     entry 0, :N, 'ノーマル'
     entry 1, :HN, 'ハイノーマル'
     entry 2, :R, 'レア'
     entry 3, :HR, 'ハイレア'
     entry 4, :SR, 'スーパーレア'
     entry 5, :LG, 'レジェンド'
  end
end

BEFORE

レアリティの定数を参照するために、 xxx_id_by_key というクラスメソッドを使っています。

if @card.rarity == Card.rarity_id_by_key(:SR)
  puts "スーパーレアが限界突破!"
  @card.rarity = Card.rarity_id_by_key(:LG)
  @card.save!
end

AFTER

インスタンスメソッドに定義された xxx_key を使えば、値をシンボルで取り出すことができます。

if @card.rarity_key == :SR
  puts "スーパーレアが限界突破!"
  @card.rarity_key = :LG
  @card.save!
end

POINT

rarityというアトリビュートが定義されていると、以下の3つのアクセサが定義されます。

  • #rarity_key rarityの値に応じたシンボルを返す
  • #rarity_key= シンボルを受けて値に変換してrarityに代入する
  • #ratity_name rarityの値に応じた名称を返す

また、クラスメソッドのcreateや、インスタンスメソッドのupdateなどハッシュを引数にとるメソッドもrarity_keyという名前でシンボルを受け付けるようになります。

card = Card.create(rarity_key: :LG)
card.update(rarity_key: :SR)

REFERENCE

https://github.com/akm/selectable_attr

VERSIONS

Ruby MRI 2.1.1
Rails gem 'rails', '4.1.4'
selectable_attr (0.3.17)
selectable_attr_rails (0.3.15)

AWSでバウンスメール対策【AWS総連携】

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは、2017年初投稿の棚旬です。今回は、メール配信を行っているサービスで重要となってくるバウンスメール(何らかの原因で配信エラーになったメール)対策について記載しようと思います。バウンスメール対策は、AWSが提供しているサービスを使用すると簡単にバウンスメールの処理が可能です。この記事ではAWS周りの設定について記載しています。AWSが提供しているAPIを利用してバウンスとなったメールを取得する方法については別の記事で記載しようと思います。

AWSの各サービスについて

バウンスメール対策を行うにあたり、今回は3つのAWSサービスを使用していきます。各サービスについてはリンク先の説明で確認しましょう。
SES

Amazon SES は、ユーザー自身の E メールアドレスとドメインを使用して E メールを送受信するための、簡単で費用効率の高い方法を提供する E メールプラットフォームです。

Simple Email Service-Amazon Web Services

SNS

Amazon Simple Notification Service (Amazon SNS) は、高速かつ柔軟な完全マネージド型のプッシュ通知サービスです。このサービスを使用すると、個々のメッセージを送信したり、多数の受信者にメッセージをファンアウトしたりできます。Amazon SNS により、簡単かつコスト効率の高い方法で、モバイルデバイスユーザーおよびメール受信者にプッシュ通知を送信したり、他の分散サービスにメッセージを送信したりできます。

Simple Notification Service-Amazon Web Services

SQS

Amazon Simple Queue Service(SQS)は、高速で、信頼性が高く、スケーラビリティに優れ、十分に管理されたメッセージキューサービスです。

Simple Queue Service-Amazon Web Services

はい、では早速設定していきましょう。

SNSの作成

  1. AWSコンソールからSNSを選択(リージョンはバージニア北部)
  2. Create Topicを選択 enter image description here 3.【Topic name】【Display name】を入力 【Display name】は10文字以内の制限があるのと、バウンスを受信した時の宛名になるので分かりやすく判別しやすい名前にしましょう。 enter image description here

SESにアドレスの登録

  1. AWSコンソールからSESを選択(リージョンはバージニア北部)
  2. SES Home からEmail Addressesを選択し、Verify a New Email Addressを選択
  3. Email Address を入力する
  4. 認証メールが届くので確認。SESのアドレス一覧で認証されたアドレスのStatusがverifiedに変わる enter image description here

SNSのサブスクリプション登録

  1. SNSのメニューからTopicsを選択し、topic名を選択
  2. create subscription を選択
  3. 【Protocol】Email【Endpoint】SESに登録したアドレスを入力 【Topic ARN】は作成したSNSの詳細に明記されている値を使用 enter image description here
  4. 認証メールが届くので確認
    enter image description here
    click here to unsubscribeをクリックするとサブスクリプションが解除されてしまうので注意。(コンソールからでも削除可能)SESとSNSの連携
  5. アドレスの詳細からNotificationsのEdit Configurationを選択
    enter image description here
  6. SNS Topic Configuration
    【Bounces】【Complaints】は作成したSNSを選択
    ※BouncesとComplaintsの両方を選択しないと、Email Feedback Forwarding が選択不可となり、通知設定の解除がAPI経由で変更できない
    Email Feedback ForwardingはDisabledを選択

SQSの作成

  1. AWSコンソールからSQSを選択(リージョンは東京)
  2. 新しいキューの作成を選択 enter image description here
  3. 【キュー名】を入力する。キューの属性はデフォルトで良い。
  4. SNSからの受信設定 アクセス許可タブの【アクセス許可の追加】を選択
  5. 作成したキューへのアクセス許可 enter image description here 【効果】許可 【プリンシパル】全員 【アクション】SendMessage 【限定条件】None 【条件】ArnEquals 【キー】aws:SourceArn 【値】作成したSNSのARN値

SNSとSQSの連携(SNSにサブスクリプションの登録)

  1. AWSコンソールからSNSを選択(リージョンはバージニア北部)
  2. 作成したSNSトピック詳細からCreate subscriotionを選択
  3. 【Protocol】Amazon SQS 【Endpoint】作成したSQSのARN値

IAMユーザの作成

  1. AWSコンソールからIAMを選択
  2. メニューのユーザーから【ユーザーを追加】を選択
  3. 【ユーザー名】、【アクセスの種類】はプログラムによるアクセスを選択
  4. 【既存のポリシーを直接アタッチ】を選択(2回目からはアクセス権限を既存ユーザーからコピーで可能)
  5. SQSで検索し、AmazonSQSFullAccessを選択 同様にSESで検索し、AmazonSESFullAccessを選択
  6. .csvのダウンロードを選択 アクセスキーとシークレットアクセスキーを控える

設定確認

設定が終了したのでテストメールを送ってみましょう。
1. SESに登録したメールアドレスを選択し、Send a Test Emailを選択
2. Toにバウンス扱いになるメールアドレス(bounce@simulator.amazonses.com)を入力。Subject、Bodyは任意。
3. Send Test Mailを選択
4. 作成したSQSを選択し詳細をチェック
enter image description here
利用可能なメッセージ(可視)が1になっていたら正しく設定ができています。また、SESに登録したアドレスはSNSにサブスクリプション登録しているので、以下のようなメールも届いているはずです。
enter image description here

バリデーションでコンテキストを活用する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Railsのバリデーションではコンテキストと呼ばれる情報を使うことができます。
コンテキストはシンボルで表現されます。

コンテキストの種類

レコードをINSERTするときのコンテキストは :create、 UPDATEするときのコンテキストは :update です。

レコードを最初に保存するときと、あとで更新するときで検査する項目や内容を変えたいとき、 :create と :update で区別すればうまく実装できます。

またvalid?などで特に指定しない場合のデフォルトのコンテキストは nil です。

コンテキストを定義する

その他にも、ユーザーが任意のシンボルを使ってコンテキストを指定することができます。

たとえばここで、 :change_password というシンボルを使ってユーザーのパスワード更新というコンテキストを表そうと思います。

saveするときのコンテキストを指定する

user.save(context: :change_password)

バリデーションを実行するときにコンテキストを指定する

user.valid?(:change_password)

コンテキストを活用する

このコンテキストをバリデーション側で受け取るには on: パラメータを使います

validates :password, presense: true, on: :change_password

こうしておくと、savevalid?:change_passwordというコンテキストが指定されたときだけ、このバリデーションがチェックされます。

逆に「このコンテキストでないときだけチェックしたい」という指定をするときは、カスタムバリデーションのメソッドを書いて、その中でコンテキストをチェックすることができます。

validate :check_not_on_password

def check_not_on_password
  # コンテキストが :change_password のときはなにもしない
  return if validation_context == :change_password

  :
  :
end

【Rails】RailsのJavaScriptをクラス分け【JavaScript】

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

RailsでJavaScriptを読み込んでいるかと思いますがクラス分けをしていないではないでしょうか。 そんな時の参考になればと思います。

なぜクラス分けした方がいいのか。

アセッツパイプラインでjsやcssを結合して高速化してくれますがjsを一括で読み込んでしまうため、アクションによってjsの機能を切り替える必要があるためです。

機能を切り替えないとどんなことが起こるのか。

products.coffee

$ ->
  $('.name').css('font-size', '10px')

categories.coffee

$ ->
  $('.name').css('font-size', '20px')

この場合には読み込まれた順番によって.nameのフォントサイズが変わってしまいます。

クラス分けの手順

各コントローラ各アクション毎にクラスをnewするようにします。

1. app/views/layouts/application.slim

= javascript_include_tag 'application', 'data-turbolinks-track' => true
      .
      .
      .
body data-controller="#{controller.controller_name}" data-action="#{controller.action_name}"

2. app/assets/javascripts/application.coffee

#= require_tree .

3. app/assets/javascripts/js_loader.coffee

$ ->
  new JsLoader

class JsLoader
  constructor: ->
    @initialize_script_classes()

  initialize_script_classes: ->
    controller_name = $('body').data('controller')
    action_name = $('body').data('action')
    page_name = "#{contoller_name}:#{action_name}"

    switch page_name
      when 'products:index', 'products:show'
        new Product
      when 'categories:new', 'categories:create',  'categories:edit',  'categories:update'
        new Category
      .
      .
      .

4. app/assets/javascripts/products.coffee

class @Product
  constructor: ->
    @initialize_select_box()

  initialize_select_box: ->
    $('select').click ->
      .
      .
      .

これでクラス分け完了。

ついでにCSSも分ける

各コントローラ各アクション毎にstyleを切り替えられるようにします。

1. app/views/layouts/application.slim

= javascript_include_tag 'application', 'data-turbolinks-track' => true
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true
      .
      .
      .
body id="#{controller.controller_name}-#{controller.action_name}" data-controller="#{controller.controller_name}" data-action="#{controller.action_name}"

2. app/assets/stylesheets/application.scss

@import 'products';
@import 'categories';
.
.
.

3. app/assets/stylesheets/products.scss

#products-index {
  p {
    color: red;
  }
}

#products-show {
  p {
    color: blue;
  }
}

最近人気な記事