コードロード

エラー討伐

【Rails×Capistrano】自動デプロイしようとしたら「ArgumentError: Missing `secret_key_base` for ‘production’ environment, set this string with `rails credentials:edit`」

エラー

ArgumentError: Missing `secret_key_base` for ‘production’ environment, set this string with `rails credentials:edit`

結論

この記事通りにやればうまく行った。

qiita.com

原因

上の記事でも述べられているように、私も同じく下記の記事通りにCapistranoの実装を進めていたところ、タイトルのエラーが出た。

qiita.com

解決までの流れ

ArgumentError: Missing secret_key_base for ‘production’ environment, set this string with rails credentials:edit でググってみた

qiita.com

いろいろ調べてみても、本番環境(サーバー)で設定したcredentials.yml.enc と master.key と、ローカルで設定したcredentials.yml.enc と master.key とが合致していないから、鍵と鍵穴がマッチしていなくこのタイトルのエラーがでるよ、という記事ばかりだった。

言われた通り、

[サーバーのappディレクトリ]$ rm config/credentials.yml.enc 
[サーバーのappディレクトリ]$ rm config/master.key

とやってみて、一度削除してから

[サーバーのappディレクトリ]$ EDITOR=vim rails credentials:edit

を打って再度生成。

そして生成されたcredentials.yml.enc と master.keyを、ローカルにコピペして、再度githubにプッシュした後、bundle exec cap production deployをするも、エラー内容は変わらず。

解決の兆しを発見

shikiyura.com

こちらの記事の下部に、Capistranoでデプロイ自動化するときに発生したエラーがいくつかまとめられていた。

よーくみると、

「secrets.yml」にかけ! 「master.key」をセキュアな方法でデプロイ先の「app_dir/shared/config」においてあげると動きます。 https://shikiyura.com/2018/05/ruby_rails-automate-deployment-by-capistrano/

との記載されている。

そういえば、Capistranoはshared配下に置かれるように、 config/deploy.rb で設定したような・・・

そして解決してくれる記事を発見!

Railsが標準でsecrets.ymlを見に行くので、ファイル名はsecrets.ymlになっていないといけないとのこと。

ローカルで設定したコードを下記の通り訂正。

# 訂正前
set :linked_files, fetch(:linked_files, []).push('config/settings.yml')

# 訂正後
set :linked_files, fetch(:linked_files, []).push('config/secrets.yml')

そしてサーバー側のファイル名も訂正。

$ cd /var/www/app名/shared/config
$ mv settings.yml secrets.yml

再度、 bundle exec cap production deploy を実行。

進んだ!!!

ちなみにサーバーの/shared/config/secrets.yml内にはrake secretコマンドを打って出てきたセキュアな値を貼り付ける。

[サーバーのappディレクトリ]$ rake secret
11111111111111122222222222223333333333333

[サーバーのappディレクトリ]$ vi shared/config/secrets.yml
production:
    secret_key_base: 11111111111111122222222222223333333333333

【Rails×Capistrano】自動デプロイ中に「SassC::SyntaxError: Error: File to import not found or unreadable: ~bulma/bulma.」エラー

エラー

環境はRails 6.0.3.6、Ruby2.7.2、Vue 2.6.12

SassC::SyntaxError: Error: File to import not found or unreadable: ~bulma/bulma.
        on line 16:1 of app/assets/stylesheets/style.scss
>> @import "~bulma/bulma";

結論

パスを明示的に全部記載してあげるだけ!!

@import "../../../node_modules/bulma/bulma.sass";

原因

bundle exec cap production deploy中のエラー。

曖昧なままだが、おそらく単純にパスが終えていなかったんだと思う。

ローカルだと読み込めていたのになぜだろう・・・

あと、そもそもパッケージマネージャー(yarn)でインストールすくことについてちゃんと理解していなかった。ググった記事のコピペで済ませてきた代償です。。。

解決方法

解決策として、最初に下記項目にあたりをつけてみた。

  • バージョン変わった?
  • importのやりかた変わった?
  • yarnでaddしたからCDNでやってみる?
  • ファイル名がおかしい?
  • またまたcapistranoの設定云々? ひとつめ、サーバーでyarn add bulmaしてみたらローカルと違うバージョンがインストールされてしまったので、戻してみてバージョンを揃えてみたが、エラーは変わらず。

二つ目、importのやり方が変わった?

これを突き進めていくに当たって、「あれ?importってそもそもどこのファイル読みに行ってるんだっけ?」となり、そういえばググった記事を見つけてコピペしたら動いたのでそのままにしていたのを思い出した。

ここにきて初めてちゃんとyarnとnodeについて調べてみた。

どうやら /node_modules/bulma/bulma.sass このファイルを読み込みに行っているらしい。

では丁寧にちゃんと明示してあげよう!と下記のとおり、修正してみた。

# 修正前
@import "~bulma/bulma";
# 修正後
@import "../../../node_modules/bulma/bulma.sass";

これでちゃんと通りました!

なぜローカルでは修正前の書き方でもいいのに、本番環境だと明示してあげないといけないかはまだ謎。

学んだこと

  • yarn add したものは、node_modules内のフォルダに格納され、それを読み込む必要がある。
  • 記事のコピペは後で痛い目見る!

【Rails×Capistrano】Gemfile not found (Bundler::GemfileNotFound)

解決方法

app/config/unicorn/production.rb に下記を追記

before_exec do |server|
  ENV["BUNDLE_GEMFILE"] = File.join(File.expand_path("../../../../", __FILE__), "current", "Gemfile")
end

ローカルにて下記コマンドでunicornをSTOPしてSTARTしてあげる。

$ bundle exec cap production unicorn:stop
$ bundle exec cap production unicorn:start

原因

deployを何度もやっていると、急にGemfileが読み込まれなくなり、再起動できなくなることがある。

app/config/unicorn/production.rb にて、 preload_app true を設定している場合に起こりうるらしい。

preload_app trueとは、ほっとホットデプロイ、緩やかなデプロイとよく言われるらしい。USR2。ググればたくさん出てくる。

この時点でENV[“BUNDLE_GEMFILE”]にはRAILS_ROOT/releases/日付的なやつ/Gemfileが入ってしまうので、これをunicornプロセスが覚え続けてしまう。

そうすると、そのうちSIGUSR2がなげられても、一旦BUNDLE_GEMFILEの方にGemfileを確認してしまうので、既に存在しないGemfileを確認にいってしまう。

参考

capistrano + unicornではまった。 – blog unlearned

【PHP】小数点以下の桁数を指定して切り捨てる方法(floor、number_format、sprintf)

やりたいこと

ある桁数以下は切り捨てて、それより上の桁数で値を返したかった。

例えば、小数点第三位以下は切り捨てて、小数点第二位までを返したい。

課題

ググると、 floorsprintfnumber_format があるよう。

floor だと小数点以下の切り捨てて整数にするのみで、桁数の指定はできない。

sprintfnumber_format なら、小数点以下の桁数を指定するだけなので簡単そう!と思ったが、よくよく調べてみると、なぜか四捨五入されてしまうらしい。

結論

結局、完全な切り捨てを行いたいなら floor を工夫して使うのが良さそうという結論に辿り着いた。

イメージは、元の数値を割って小数点の位置を左にズラしてから floor で小数点以下を切り捨てて、割った数分、倍にすれば良い。 例えば、小数第三位以下は切り捨てたいなら、ある数値を100倍してからfloorで切り捨てて、その後で100で割って、小数第二位までに戻す。

  • もし元の数字の小数点以下の桁数が動的であれば、その数字に number_formatsprintf で桁数を揃えてから(小数点第二位までにしたければ、第三位までを一旦揃える)、 floor を使って切り捨てれば良さそう。

  • もし元の数字の小数点以下の桁数が動的であれば、その数字に number_formatsprintf で桁数を揃えてから、 floor を使って切り捨てれば良さそう。

下記のサンプルコードは下記サイトから引用。

PHP 四捨五入/切り上げ/切り捨てのサンプル

<?php

// 小数第一位で切り捨て
print floor(2.26);  // 2

// 小数第一位で切り捨て
print floor(2.82);  // 2

// マイナスの場合
print floor(-2.82); // -3

// 小数第二位で切り捨て
print (floor(12.262 * 10) / 10); // 12.2

// 小数第三位で切り捨て
print (floor(12.262 * 100) / 100); // 12.26

// 1の位で切り捨て
print (floor(122.2 / 10) * 10); // 120

// 10の位で切り捨て
print (floor(122.2 / 100) * 100); // 100

?>

小数第二位で切り捨てています。以下の操作です。 1.対象の値に10を掛けます。(12.262 * 10 = 122.62) 2.floorメソッドを使用して小数点以下を切り捨てます。(122.62 → 122) 3.対象の値を再度10で割ります。(122 / 10 = 12.2)

number_formatとsprintfの挙動

number_format

number_format

number_format(
    float $num,
    int $decimals = 0,
    ?string $decimal_separator = ".",
    ?string $thousands_separator = ","
): string

num

フォーマットする数値。

decimals

小数点以下の桁数。 0 を指定すると、 返り値の decimal_separator は省略されます。

decimal_separator

小数点を表す区切り文字。

thousands_separator

千の位毎の区切り文字。

$number = 1234.56;

// 英語での表記 (デフォルト)
$english_format_number = number_format($number);
// 1,235

$number = 1234.5678;

// 千位毎の区切りがない英語での表記
$english_format_number = number_format($number, 2, '.', '');
// 1234.57  // ここ四捨五入されてる

PHPで小数点以下を2桁とか3桁に切り捨てる2つの方法 | PisukeCode - Web開発まとめ

なぜか四捨五入されてる。切り捨てたい。

sprintf

【PHP】小数点以下まで出力する - Qiita

sprintfとprintfの違いは、sprintfはフォーマットされた値が戻り値。printfはフォーマットされた値を標準出力する。

$num1 = 10;
$num2 = 1000.5;
$num3 = 0.456789;

echo sprintf('%.2f',$num1),PHP_EOL;
echo sprintf('%.2f',$num2),PHP_EOL;
echo sprintf('%.2f',$num3),PHP_EOL;
/*
10.00
1000.50
0.46    // ここがなぜか四捨五入されてる。
*/

なぜか四捨五入されてしまう場合もあるので、切り捨て対時は使えなさそう。