sorceryの細かい設定

sorceryを触っていて、気になったことがあったので記事として残す。

背景

railsのgem sorceryをユーザー認証として採用した。
sorceryのreset password機能も組み込んだが、間髪入れずに何回か連続で実行するも
1回目のメールしか届かなかった。

やりたいこと

メールの送信間隔を自由に設定したい。

方法

ドキュメントに従って、以下コマンドを入力すると
config/initializersにsorcery.rbが生成される。

rails g sorcery:install


sorcery.rbを細かく見ると、以下のような記述がある。

# Hammering protection: how long in seconds to wait before allowing another email to be sent.
# Default: `5 * 60`
#
# user.reset_password_time_between_emails = 


デフォルトでは、5 * 60 の300秒(5分)となっているとのこと。
コメントアウトを外し、ここの数字を設定してあげる。

# Hammering protection: how long in seconds to wait before allowing another email to be sent.
# Default: `5 * 60`
#
user.reset_password_time_between_emails = 5

以上のようにすると、5秒間隔でメールが送れるようになる。
メールが届かないのは意外と不安になるので、この設定はそこそこ大事かもしれない。

備考

また、よくあるリセットパスワードURLの有効期間もsorcery.rbで自由に設定できる。
以下記述を見つける。

# How many seconds before the reset request expires. nil for never expires.
# Default: `nil`
#
# user.reset_password_expiration_period =

コメント部分を和訳すると、

リセットパスワードのURL生成した後、何秒で無効化されるか。
nilの場合、一生有効のまま。

とのこと。
従って、この部分を

user.reset_password_expiration_period = 600

のようにしてあげると、10分間で切れるURLを生成することができる。

Cannot allocate memoryエラー

問題

AWS EC2上で無料枠でインスタンスを動かしていたところ以下内容のエラーに遭遇。
何を入力しても以下エラーしか出ないようになってしまった。

-bash: fork: Cannot allocate memory


調べたところ、「インスタンスの容量が足りないよ」という意味らしい。

条件

AWS EC2 + rails + nginx + unicorn

対処

仮想メモリというものがLINUXに備わっているらしく、それを追加してあげる。

まず、一旦exitして、もう一回ログインする。
ログインできたら、スワップファイルを確保するコマンドを入力。
※ sudoつけないとpermission errorが出てしまった。

sudo fallocate -l 512M /swapfile


スワップファイルのアクセス権を変更。

sudo chmod 600 /swapfile


次に、仮想メモリとして、使うファイルを指定

[user@ip-10-0-0-196 ~]$ sudo mkswap /swapfile
スワップ空間バージョン 1 を設定します。サイズ = 512 MiB (536866816 バイト)
ラベルはありません, UUID=26d53dd6-cb4d-4869-9334-102f63fde902


仮想メモリを有効化して完了。

sudo swapon /swapfile


仮想メモリの大きさは、自由に変更出来るようなので
状況に合わせて数値を変更してください。

therubyracerがinstallできない

はじめに・環境

このエラーについては様々な記事を読んだが、どれも自分に当てはまらないものが多かった。 libv8などのversionによっても解決方法が変わるため、あくまで参考程度に読んでいただくと良いかもしれません。


対象 Version
OS macOS Catalina version10.15.7
libv8 3.16.14.19
therubyracer 0.12.3
rails 5.2.3
ruby 2.6.5
bundler 2.0.2

therubyracerとは

therubyracerは、Javascriptの実行エンジンであるv8をrubyから叩くために導入するgem。
libv8は以下の様に、therubyracerとの依存関係があり、インストールされるようになっている。
Gemfile.lock

therubyracer (0.12.3)
      libv8 (~> 3.16.14.15)
      ref

経緯

まず、bundle install --vendor/bundleを実行した際に以下エラーが出現。

Fetching therubyracer 0.12.3
Installing therubyracer 0.12.3 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/myname/Desktop/runteq/advanced/workdir/vendor/bundle/ruby/2.6.0/gems/therubyracer-0.12.3/ext/v8
/Users/myname/.rbenv/versions/2.6.5/bin/ruby -I /Users/myname/.rbenv/versions/2.6.5/lib/ruby/2.6.0 -r ./siteconf20210123-53283-11tly30.rb extconf.rb
--with-v8-dir\=/usr/local/Cellar/v8/8.8.278.14
checking for -lpthread... yes
checking for -lobjc... yes
checking for v8.h... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/Users/hamorotaiga/.rbenv/versions/2.6.5/bin/$(RUBY_BASE_NAME)
        --with-pthreadlib
        --without-pthreadlib
        --with-objclib
        --without-objclib
        --enable-debug
        --disable-debug
        --with-v8-dir
        --with-v8-include
        --without-v8-include=${v8-dir}/include
        --with-v8-lib
        --without-v8-lib=${v8-dir}/lib
/Users/myname/Desktop/workdir/vendor/bundle/ruby/2.6.0/gems/libv8-3.16.14.19/ext/libv8/location.rb:50:in `configure': By using --with-system-v8, you
have chosen to use the version  (Libv8::Location::System::NotFoundError)
of V8 found on your system and *not* the one that is bundled with 
the libv8 rubygem. 

However, your system version of v8 could not be located. 

Please make sure your system version of v8 that is compatible 
with 3.16.14.19 installed. You may need to use the 
--with-v8-dir option if it is installed in a non-standard location
        from /Users/myname/Desktop/workdir/vendor/bundle/ruby/2.6.0/gems/libv8-3.16.14.19/lib/libv8.rb:7:in `configure_makefile'
        from extconf.rb:32:in `<main>'

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /Users/myname/workdir/vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-19/2.6.0/therubyracer-0.12.3/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /Users/myname/workdir/vendor/bundle/ruby/2.6.0/gems/therubyracer-0.12.3 for inspection.
Results logged to /Users/myname/workdir/vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-19/2.6.0/therubyracer-0.12.3/gem_make.out

An error occurred while installing therubyracer (0.12.3), and Bundler cannot continue.
Make sure that `gem install therubyracer -v '0.12.3' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  therubyracer

最後らへんに、

gem install therubyracer -v '0.12.3' --source 'https://rubygems.org/'

とあり、実行してもこんな感じのエラーが出る。

checking for -lpthread... yes
checking for -lobjc... yes
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

~中略~

extconf failed, exit code 1

~後略~

解決策

brew listを実行し、v8@3.15がインストールされているのを確認

autoconf                ghostscript             imagemagick             liblqr                  node                    pkg-config              shared-mime-info        yarn
composer                glib                    jpeg                    libomp                  oniguruma               postgresql              sqlite
docbook                 gnu-getopt              jq                      libpng                  openexr                 protobuf                v8@3.15
docbook-xsl             heroku                  krb5                    libtiff                 openjpeg                python@3.8              webp
freetype                heroku-node             libde265                libtool                 openssl@1.1             rbenv                   x265
gdbm                    icu4c                   libffi                  little-cms2             pcre                    readline                xmlto
gettext                 ilmbase                 libheif                 mysql                   phpmyadmin              ruby-build              xz

brew uninstall v8@3.15で、v8@3.15を一旦アンインストールする。
brew install v8@3.15で、再びインストールする。
④ libv8のパスの設定をする

bundle config --local build.libv8 --with-system-v8

⑤ therubyracerのパスの設定をする

myname@mbp workdir % bundle config --local build.therubyracer --with-v8-dir=$(brew --prefix v8-315)
You are replacing the current local value of build.therubyracer, which is currently "--with-v8-dir=/usr/local/Cellar/v8/8.8.278.14"

which is currently のあとが nilになってしまう場合は失敗している可能性がある。

--with-v8-dir=$(brew --prefix v8-315)

このフラグは、brew installした際に格納される場所を返している。
⑥ これでbundle install --vendor/bundleを実行


以上、手順で解決。

bundle install時に、mysql2のインストールが失敗する

bundle installをしていて、以下のエラーに遭遇した。

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Desktop/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3/ext/mysql2
/Users/.rbenv/versions/2.6.5/bin/ruby -I /Users/hamorotaiga/.rbenv/versions/2.6.5/lib/ruby/2.6.0 -r ./siteconf20210123-38999-1g3nre5.rb extconf.rb
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for rb_wait_for_single_fd()... yes
-----
Using mysql_config at /usr/local/bin/mysql_config
-----
checking for mysql.h... yes
checking for errmsg.h... yes
checking for SSL_MODE_DISABLED in mysql.h... yes
checking for SSL_MODE_PREFERRED in mysql.h... yes
checking for SSL_MODE_REQUIRED in mysql.h... yes
checking for SSL_MODE_VERIFY_CA in mysql.h... yes
checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes
checking for MYSQL.net.vio in mysql.h... yes
checking for MYSQL.net.pvio in mysql.h... no
checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes
checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes
checking for my_bool in mysql.h... no
-----
Don't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load
-----
-----
Setting libpath to /usr/local/Cellar/mysql/8.0.21_1/lib
-----
creating Makefile

current directory: /Users/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3/ext/mysql2
make "DESTDIR=" clean

current directory: /Users/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3/ext/mysql2
make "DESTDIR="
compiling client.c
compiling infile.c
compiling mysql2_ext.c
compiling result.c
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3 for inspection.
Results logged to /Users/vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-19/2.6.0/mysql2-0.5.3/gem_make.out

An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mysql2

エラー文を読んでいくと、以下がどうやらヒントらしい。

ld: library not found for -lssl

このエラー文は「mysql2 gemはlibssl.dylibをライブラリ検索範囲内で探せ」という意味。 どうやら、検索範囲内で探したが見つからなかった様子。

では、検索範囲が間違っている可能性を考え、どこを探しに行ったのか確認すると 以下が検索範囲だとわかる。

Setting libpath to /usr/local/Cellar/mysql/8.0.21_1/lib

ただ、そこに見に行ってもlibssl.dylibが見つからない。

@mbp workingdir % ls -l /usr/local/Cellar/mysql/8.0.21_1/lib 
total 48280
-rw-r--r--    1 hamorotaiga  staff  7284896 Oct 18 11:05 libmysqlclient.21.dylib
-r--r--r--    1 hamorotaiga  staff  8097728 Jun 17  2020 libmysqlclient.a
lrwxr-xr-x    1 hamorotaiga  staff       23 Jun 17  2020 libmysqlclient.dylib -> libmysqlclient.21.dylib
-r--r--r--    1 hamorotaiga  staff   772188 Oct 18 11:05 libmysqlharness.1.dylib
-r--r--r--    1 hamorotaiga  staff  8184928 Oct 18 11:05 libmysqlrouter.1.dylib
-r--r--r--    1 hamorotaiga  staff   249564 Oct 18 11:05 libmysqlrouter_http.1.dylib
-r--r--r--    1 hamorotaiga  staff    85764 Oct 18 11:05 libmysqlrouter_http_auth_backend.1.dylib
-r--r--r--    1 hamorotaiga  staff    24084 Oct 18 11:05 libmysqlrouter_http_auth_realm.1.dylib
-r--r--r--    1 hamorotaiga  staff     9760 Jun 17  2020 libmysqlservices.a
drwxr-xr-x   14 hamorotaiga  staff      448 Jun 17  2020 mysqlrouter
drwxr-xr-x    3 hamorotaiga  staff       96 Oct 18 11:05 pkgconfig
drwxr-xr-x  106 hamorotaiga  staff     3392 Jun 17  2020 plugin

解決策

正しい検索範囲を伝える。

つまり、以下を実行。 bundle install時に以下オプションでpathを指定する。

  • --with-cppflags
  • --with-ldflags

brew info openssl@1.1 と入力しpathを確認する。

~前略~

For compilers to find openssl@1.1 you may need to set:
  export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
  export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"

~後略~

あとは、フラグをつけて、以下のように実行。

gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/' -- --with-cppflags=-I/usr/local/opt/openssl@1.1/include --with-ldflags=-L/usr/local/opt/openssl@1.1/lib

これで無事解決しましたとさ。

Rubyメソッド集【備忘録】

チェリー本を読んでいたが、何も覚えていなかったので、アウトプットする。 www.amazon.co.jp


公式ドキュメントを読めば全て書いてあるので、全て知りたい人はそちらまで。

公式ドキュメント_Ruby 2.7.0 リファレンスマニュアル docs.ruby-lang.org

組み込みライブラリdocs.ruby-lang.org
組み込みライブラリは Ruby 本体に組み込まれているライブラリのこと。このライブラリに含まれるクラスやモジュールは、 require を書かなくても使うことができる。   

文字列編


to_s 文字列にする
to_f 整数から小数にする
to_i 整数にする
paizaをやっていると、デフォルトは以下のようになっている。

input_line = gets
puts input_line

getsメソッド(読み方は「ゲッツ」ではなく、「ゲットエス」get stringの略)を使っているため、変数input_lineには文字列が入る。     

整数同士の割り算は整数になり、小数点以下は切り捨てられる。
小数点以下の値が必要な場合は、どちらかの値に小数点の.0を付けます。
数値の切り捨て・切り上げ・四捨五入については以下の記事参照。
Rubyで数値の切り捨て・切り上げ・四捨五入する

sprintfメソッド 指定されたフォーマットの文字列を作成する

sprintf('%0.3f', 1.2)  # => "1.200"

%0.3f:小数第3位まで数字を表示させるフォーマット文字列

配列と繰り返し処理


sizeメソッド 配列の長さ(要素の個数)を取得できる。
エイリアスはlengthメソッド

puts [1,2,3].size
3
=> nil

sumメソッド 合計値を算出する。

puts [1,2,3].sum
6
=> nil

uniqメソッド 配列から重複した要素を取り除いた新しい配列を返す。

p [1,2,2,3,5,5,6].uniq
[1, 2, 3, 5, 6]
=> [1, 2, 3, 5, 6]

sampleメソッド

p [1,2,3].sample
3
=> 3

shuffleメソッド

p [1,2,3].shuffle
[1, 3, 2]
=> [1, 3, 2]

sortメソッド 昇順に並び替える

p [1,3,2].sort
[1, 2, 3]
=> [1, 2, 3]

降順にしたい場合は、reverseをつける

p [1,3,2].sort.reverse
[3, 2, 1]
=> [3, 2, 1]

joinメソッド

p [1,2,3,4].join
"1234"
=> "1234"

p [1,2,3,4].join("/")
"1/2/3/4"
=> "1/2/3/4"

splitメソッド スペース区切りになっている文字列を配列にして返す。

p ("a b c d e").split
["a", "b", "c", "d", "e"]
=> ["a", "b", "c", "d", "e"]

引数を指定すると、スペース以外の文字にも対応できる。

p ("abcde").split("c")
["ab", "de"]
=> ["ab", "de"]

deleted_at() 配列内の特定の1にある要素を削除したい時

a = [1,2,3]
a.deleted_at(2) 
#=> 3
a => [1,2]

divmodメソッド 割り算の商と余りを配列として返す

14.divmod(3) 
=> [4,2]

deleteメソッド 配列に指定した値に完全一致する要素を削除する

a = [1,2,3,1,2,3]
a.delete(2)
a => [1,3,1,3]

delete_ifメソッド 条件をみたした要素だけ削除したい時

a = [0, 1, 2, 3, 4, 5]
a.delete_if{|x| x % 2 == 0}
p a #=> [1, 3, 5]



ブロックを使う配列のメソッド


map 各要素に対してブロックを評価した結果を新しい配列にして返す
エイリアスはcollect

numbers = [1,2,3,4,5]
new_numbers = numbers.map { |n| n * 10 }
new_numbers => [10,20,30,40,50]

空の配列を用意して、他の配列をループ処理した結果を空の配列に詰め込むような処理に適している

select/find_all 各要素に対して、ブロックを評価し、その戻り値が真の要素を集めた配列を返す

numbers = [1,2,3,4,5,6]
even_numbers = numbers.select { |n| n.even? }
even_numbers => [2,4,6]

reject selectの反対で、真にならなかった要素を集めた配列を返す

numbers = [1,2,3,4,5,6]
odd_numbers = numbers.reject { |n| n.even? }
odd_numbers => [1,3,5]

find/detect ブロックの戻り値が真になった最初の要素を返す

numbers = [1,2,3,4,5,6]
even_number = numbers.find { |n| n.even? }
even_number => 2

inject/reduce たたみ込み演算を行うメソッド

numbers = [1,2,3,4]
sum = numbers.inject(0) { |result, n| result + n }
sum => 10

ブロックの第1引数は初回のみinjectメソッドの引数が入ります。この場合は0。
2回目以降は前回のブロックの戻り値が入る。

injectでフィボナッチ数列を考える

(0..10).inject([1,1]) { |fib, n| fib << fib[n] + fib[n+1] } 
#=>  [1, 1, 3, 3, 7, 7, 15, 15, 31, 31, 63, 63, 127]    

1回目:fib = [1,1], n = 0。fib[n] = 1, fib[n+1] = 1。fibに2が追加される
2回目:fib = [1,1,2], n = 1。fib[n] = 1, fib[n+1] = 2。fibに3が追加される
3回目:fib = [1,1,2,3], n = 2。fib[n] = 2, fib[n+1] = 3。fibに5が追加される


&とシンボルを使って、もっと簡潔に書く ['ruby', 'java', 'perl'].map { |s| s.upcase }
['ruby', 'java', 'perl'].map(&:upcase)

以下条件下のみ、&:メソッド名という書き方が出来る。
①ブロック引数が1つだけ
②ブロックの中で呼び出すメソッドには引数がない
③ブロックの中では、ブロック引数に対してメソッドを1回呼び出す以外の処理がない。


範囲(Range)


配列や文字列の一部を抜き出す

a = [1,2,3,4,5]
a[1..3] 
=> [2,3,4]
a[1...3] 
=> [2,3]

a = 'abcdef'
a[1..3] 
=> "bcd"

n以上m以下、n以上m未満の判定をする

def liquid?(temperature)
  (0...100).include?(temperature)
end

to_a
値が連続する配列を作る

(1..5).to_a #=> [1,2,3,4,5]
(1...5).to_a #=> [1,2,3,4]
('a'..'c').to_a => ["a", "b", "c"]

スプラット展開

[*1..5] #=> [1,2,3,4,5]
[*'a'..'c'] #=> ["a", "b", "c"]

繰り返し処理を行う
範囲オブジェクトに対して、直接eachメソッドを呼び出すことが可能

sum = 0
(1..4).each { |n| sum += n }
sum #=> 10

stepメソッドを使うと、値を増やす間隔を指定できる

numbers = []
(1..10).step(2) {|n| numbers << n }
#=> (1..10) 
numbers #=> [1,3,5,7,9]

nからmまで、数値をx個ずつ増やしながら処理を行う
始値.step(上限値, 1度に増減する大きさ)

numbers = []
1.step(10, 2) { |n| numbers << n }
#=> 1
numbers #=> [1,3,5,7,9]

times
配列を使わず、単純にn回処理したい場合

sum = 0
5.times { |n| sum += n }
sum #=> 10

upto
nからmまで数値を1つずつ増やしながら何か処理をしたい場合

a = []
10.upto(14) { |n| a << n }
a #=> [10,11,12,13,14]

a = []
'a'.upto('e') { |n| a << n }
a #=> ["a", "b", "c", "d", "e"]

downto
逆に減らしたい場合

a = []
14.downto(10) {|n| a << n }