前人未踏の領域へ WEB・インフラ・プログラミング全般編

フロントエンド、バックエンド、インフラ、言語など、アプリ開発、IOT以外の記録

ubuntuへのmysql2インストール時にエラーになる

課題

Railsの 5.2.4がリリースされたのでupdateしようとしたところ、mysql2のアップデートでエラーになった。

/usr/bin/ld: cannot find -lssl
/usr/bin/ld: cannot find -lcrypto
collect2: error: ld returned 1 exit status
Makefile:260: recipe for target 'mysql2.so' failed
make: *** [mysql2.so] Error 1

sslとcryptoのライブラリが足りないらしい。どうやってmysql2の 0.5.2はどうやって入れたんだ。

対応

ぐぐった感じだと libssl-dev を入れてあげれば良さそう。

$ sudo apt install libssl-dev
$ gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'
$ bundle update

一応これでインストール&アップデートできた。

参考

https://github.com/znort987/blockparser/issues/38

RSpecで _before_last_saveのテストが上手く動作しない

課題

値が変更されていた場合にのみ実行されるようなテストを書いたが、FactoryBotでcreateしたオブジェクトに _before_last_saveにFactoryBotでセットしていない値がセットされていて、調べるとDBのデフォルト値だった。

原因

FactoryBotでcreateしたオブジェクト(Railsで)は before_last_saveにmigrateファイルで定義したDBのデフォルト値を持つらしい。 そのため、変更が発生していなくても before_last_saveに値が入っているため、_before_last_saveに値がセットされているかどうか を条件としたテストで期待しない動作をすることがある。

対応

デフォルト値をnil にするか、リロードして古い値をクリアすることでテストを通過するようになった。微妙だが仕方ないかな。

xxx = FactoryBot(:hoge)
xxx.reload

Nginx CORS対応で複数ドメインを許可する

課題

SPAサービスを作るにあたり、APIとWebでドメインが異なるのでCORS対応をしたい。 かつ検品環境なのでlocalホストからのアクセスも許可したい。

環境

  • nginx version: nginx/1.14.0 (Ubuntu)

対応

Access-Control-Allow-Origin に同時に複数のドメインを記述するとエラーになる。そのため、送信元のドメインに応じた 処理の記述が必要になる。

ネット上にCORS対応の記述はたくさん転がっているものの、if文を使ったものだとどうにも動作しなかった。 最終的にうまくいったのはこちら。

map $http_origin $cors_header {
    default "";
    "~^https?://(localhost:3000|hoge\.fuga\.jp)" "$http_origin";
}
server {
      location / {
          add_header Access-Control-Allow-Origin $cors_header;
      }
}

CORS対応全体としては Access-Control-Allow-Origin 以外にも記述が必要。 こうやって皆がコードの断片しか書かないから自分のとこでは上手くいかないという人が多いのだろう

参考

www.jfabre.com

曜日付きで日付を表示する

課題

Rubyで現在の日付を曜日付きのJPフォーマット 2019年11月15日(金) で返したい。 どうするのがよいか。

結論

I18nにそのものが定義されてた。

I18n.l Date.today, format: :long
=> "2019年11月15日(金)"

フォーマットは strftime に従っているので ja.yml を編集して自分で定義することも可能

対応(I18nを使わない場合)

I18n使えば良いということが分かったので以下は試行錯誤の残骸。

直接ズバリ とか返してくれる方法はなさそうだったので参考サイトの情報を元に適当に見繕うことにする。 とりあえず日付は以下で取れるので、

> Date.today.strftime '%Y年%-m月%-d日'
=> "2019年11月15日"

あとは曜日について考える。 曜日の日本語表記は自前で配列を持つ

> DAT_OF_WEEK = ["日", "月", "火", "水", "木", "金", "土"]

この配列の位置を取得するために 'Time.strftime'の'%u'と'%w'フォーマット、または Time.wday メソッドが利用できるがwdayが目的にかなってもっともシンプルだろう。

> DAT_OF_WEEK[Date.today.wday]
=> "金"

日付とくっつけておしまい。

Date.today.strftime("%Y年%-m月%-d日(#{DAT_OF_WEEK[Date.today.wday]})")
=> "2019年11月15日(金)"

参考

docs.ruby-lang.org qiita.com www.sejuku.net

バリデーションを項目ごとに1つにしたい

課題

ある項目に対して数値チェックと存在チェックを行いたい。数値チェックがNGな時点で存在チェックを満たさないのは自明なので これをスキップしたい。どうするのが良いか。

対応

バリデーションがNGだった項目は errorsにaddされるので、その存在チェックをする

validats :code, length: { is: 3 }
validats :code, numericality:true  unless errors.include?(:code)?

ここで errors[:code].blank? でも同じようなことができるのだが、errors内に:codeが作られてしまっていた。
active_model/errors.rb には include? メソッドが用意されているのでそちらを使うのが良さそう。

参考

teratail.com

異なるカラム名のモデルに対するバリデーションをConcernで共通化したい

課題

バリデーションを共通化したい。Concernを使いたいがモデルごとに違う名前を割り当ててしまった。 カスタムバリデータは大げさなので使いたくない。どうすればよいか。

対応

ActiveRecordhas_attribute を使うと項目の有無をチェックしてくれるのでそれを使う。

module EmailValidator
  extend ActiveSupport::Concern
  EMAIL_FORMAT = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  included do
    if has_attribute?(:user_mail)
      m = :user_mail
    elsif has_attribute?(:company_mail)
      m = :company_mail
    end
    validates m, format: { with: EMAIL_FORMAT,
                           message: I18n.t('activerecord.errors.messages.invalid') },
              presence: false
  end
end

とりあえずできそうだけど書いてて全然イケてる感じがしないので使わないかも。

参考

https://qiita.com/hihats/items/f82b6fd99b18bf9569fd

RubyMineのRSpec実行時にテストが固まる

課題

Mac上のRubyMineからRSpecを実行しているが、config内のファイルやModelクラスのvalidationなどを編集すると テストを実行しても途中で止まってしまい、RubyMineを再起動しないとテストが実行できなくなった。

原因

springのリロードがうまく機能していない。 プロセスにはspringがいるが、statusを見ると起動していないと言われる。

$ ps -x|grep spring
28063 ??         0:00.35 spring server | hoge | started 1 min ago  
28083 ??         0:00.43 spring app    | hoge | started 0 secs ago | test mode      
28105 ttys001    0:00.00 grep spring
$ spring status
Spring is not running.

RubyMineでは SPRING_TMP_PATH という環境変数で定義されたパスに個別のspringインスタンスが生成される。 この変数は {temp_dir}/RMSpring と等しい値になる。 なので以下のようなコマンドを叩くと

$ SPRING_TMP_PATH=${TMPDIR}/RMSpring bin/spring status
Spring is running:

41298 spring server | hoge | started 5 secs ago

springが実行されていることがわかる.

対応

springを停止する

SPRING_TMP_PATH=${TMPDIR}/RMSpring bin/spring stop

でもなんか駄目なことが多い気がする。そんなときは kill してしまおう。

$ kill 28063

参考

www.jetbrains.com

/* Responsive: yes */