毎日SEの技術ブログ

平日は社内SE、休みは自宅でサービス開発するSEの技術ブログ

method_missingを使ってnilを無視する

tryメソッドを使ってnilを無視できますが、tryをそもそもしたくない。

object.try(:method).try(:method)

とかやりたくないわけですよ。汚いから

NilClassでmethod_missingをオーバーライドする

class NilClass
  def method_missing(name, *args, &block)
    nil
  end
end

# どこまでも続けられるよ!
# nil.map(&:id).join(',').....

これでNilClassに存在しないメソッドが呼ばれるとnilを返すのでtryなんてしなくてもnilを無視できる!

ちなみに、これはnilに対してNoMethodErrorが発生しなくなり、想定しないnilが返ってくるバグが発生した時、原因が見つかりにくくなる諸刃の剣であるため注意。

rails4.1 CHAPTCHAを使う

CHAPTCHAとは

入力フォームで機械的な投稿を防ぐために、画像の読みにくい文字を入力して認証させるやつ。
↓こんなの

f:id:UFUN:20140920211106j:plain

simple_captchaが便利そう

というかsimple_captchaしか見当たらない。
正しく動作させるまでに結構手こずった。手順通りやってもダメじゃん。
captcha画像の404エラーとか、
Error while running convert: sh: convert: command not found
みたいなエラーでつまづいている人に役立つかも。

インストール方法

Macでの方法 1 brew install ImageMagick
2 brew install ghostscript
3 Gemfileに以下を追記してbundle install

gem 'simple_captcha2', git: 'https://github.com/pludoni/simple-captcha.git', require: true

ここでインストール終了。

設定方法

1 rails g simple_captch を実行
2 rake db:migrate を実行
3 ApplicationControllerに以下を追記

include SimpleCaptcha::ControllerHelpers

4 表示させたいViewに以下を追記

<%= show_simple_captcha %>

5 実際に表示されていることと確認して終了

実際に機能させる

1 実際にCAPTCHAを利用するコントローラで以下の処理を追記

if simple_captcha_valid?
  # 認証成功したときの処理
else
  # 認証失敗したときの処理
end

カスタマイズする

1 CAPTCHAの文字入力フォームにクラスを適用したい場合

<!-- こうではなく 
<%= show_simple_captcha %> -->
<!-- こう -->
<%= show_simple_captcha(input_html: { class: 'classname' }) %>

bootstrap等でデザインを統一しているとき等に役立つ
2 生成される画像の複雑さをあげる config/initializers/simple_captcha.rbを作り以下を追記

SimpleCaptcha.setup do |sc|                                                                                                               
    # 画像のサイズ default: 100x28
    sc.image_size = '200x80'
 
    # 文字列の長さ default: 5
    sc.length = 6

    # 画像のスタイル 固定よりランダムが良い
    sc.image_style = 'random'

  # 画像のグニャグニャ感のレベル(上下の揺れ) default: low
    # possible values: 'low', 'medium', 'high', 'random'
    sc.distortion = 'high'

    # 画像のグニャグニャ感のレベル(立体感のある揺れ?)default: medium
    # possible values: 'none', 'low', 'medium', 'high'
    sc.implode = 'medium'
end

Ruby ファイルの種類からcontent-typeを取得する

拡張子からの判断ではなく、ファイルの内容で判別したい

具体的に言うと、jpegファイルを拡張子pngにして保存したときも"image/jpeg"が取得したい ということ。

MIME::Typesを使うと拡張子から判断するため、上記の場合"image/png"が取得されてしまう。

ruby-filemagicを使う

1.まず下記をインストール

// for Mac
brew install libmagic

// for CentOS
yum install file-devel 

2.gemをインストール

gem install 'ruby-filemagic'

3.下記で取得

path = 'test.png' # 実際のファイルはjpeg
FileMagic.new(FileMagic::MAGIC_MIME).file(path).split(';').first # =>image/jpeg 

【CSS3】フォントを細くする

最近のウェブサービスでよく見るようになりましたが、フォントを標準より若干細くする方法です。 

ウェブフォントで元々細いフォントを表示させるとかではなく、ゴシックやメイリオ等既存フォントを細くします。

body{
    -webkit-font-smoothing: antialiased;
}

RSpec before(:all)とbefore(:each)の違い

はまったのでメモ。

大きな違いは実行順番ではない

自分もそうなんですが:allと:eachの違いは実行順番だけだと思っていましたが実際は違います。 例えば下記のようなテストの場合

describe Account do
  context '#signin' do
    context 'メールアドレスとパスワードが一致していたら' do 

      before(:all)
        @mail = 'hoge@mail.com'
        @password = '1234'
        Account.create(mail: @mail, password: @password)
      end

      after(:each)
        Account.delete_all
      end
      
      it 'サインイン出来る' do
        # テスト処理
      end
    end
  end
end

この処理はサインインできることをテストするために、必要なアカウントをbefire(:all)で用意し、 テスト実施後に用意したデータを消すつもりで書いています。

しかし消えません。

いろいろ調べた結果、:allと:eachは実行順番以外の違いがあることが分かりました。
:eachは変数の書き換えやトランザクション発行を全てそのスコープ内限定(今回だとit サインイン出来る)で利用出来るようにしています。
:eachで用意したデータは特定のitでのみ利用するいう意味合いを含むためこのような仕様になっているのかと思います。

ではなぜ用意したデータが消えないかという、after(:each)で発行したdelete_all(delete処理)が他のテストに影響しないよう、丁寧にロールバックされているためです。 :eachでのトランザクションは全てロールバックされるので、before(:each)でAccount.createすれば、特にdelete処理をする必要も無かったということで一件落着しました。

Rails4.0でJasmineを使う

Jasmineとは

RSpecライクなjavascript用のテストライブラリです。 javascriptでも当然単体テストが必要ですがどのようなテストがあるのか分からなかったため、調べてみたらjasmineというのが引っかかりました。 今回はそのjasmineを導入します。

bundle install

Gemfileに以下を追加しbundle installを実行します。

group :development, :test do
   gem 'jasmine'
   gem 'jasmine-rails'
   gem 'jasmine-jquery-rails'
end

テストの例を作成

ターミナルで以下を実行

rails g jasmine:install
rails g jasmine:examples

サンプルファイルが生成されます。

実行

ターミナルで以下を実行

rake jasmine

実行するとテスト実行用のウェブサービスが起動されます。 デフォルトだとhttp://localhost:8888でアクセスできますのでアクセスします。 アクセスするとコンソール画面が表示されテスト結果が表示されます。 ここまでできればjasmineがrailsで実行できるようになったと言えます。

補足

rake jasmine:ciでコンソールでのテストが実施できます。

IEnumerable<T>にEachメソッドを生やす

List<T>にはForEachメソッドがあるんだけどIEnumerable<T>には無いから作った。

public void Each<T>(this IEnumerable<T> values, Action<T> action)
{
    foreach(var v in values) action(v);
}

使い方

var list = new[]{"1","2","3"};
list.Each(x=>Console.WriteLine(x));

下記が通常のforeachを使った場合ですが、foreachよりコンパクトになり良い。

var list = new[]{"1","2","3"};
foreach(var x in list) 
    Console.WriteLine(x));