- 投稿日:2020-02-05T22:57:14+09:00
【Rails6】DEPRECATION WARNING: update_attributes is deprecated and will be removed from Rails 6.1 (please, use update instead)
TL;DR
update_attributes
=>update
に変更しましょう。
※安心してください。動作は変わりません。環境
- Ruby: 2.6.3
- Rails: 5.2.4.1 => 6.0.2.1 へアップデート
なんかWarning出たな?
DEPRECATION WARNING: update_attributes is deprecated and will be removed from Rails 6.1 (please, use update instead)
update_attributes
,update_attributes!
を使っているところでこんなWarningが出ました。
update_attributes
は Rails 6.1 で削除するから、代わりにupdate
を使ってねって言われています。変更しちゃって大丈夫?
Railsのソースを見てみましょう。
https://github.com/rails/rails/blob/v6.0.2.1/activerecord/lib/active_record/persistence.rb#L625alias update_attributes update deprecate update_attributes: "please, use update instead"
update_attributes
はupdate
のaliasとして定義されています。
なので、どちらを使っても動作は変わらないです。
update_attributes!
も同様ですね。
https://github.com/rails/rails/blob/v6.0.2.1/activerecord/lib/active_record/persistence.rb#L639-L640ガッと
update
,update!
へ変更してWarning解消出来ました。
- 投稿日:2020-02-05T22:06:25+09:00
【Rails】Docker環境下でbinding.pryを使えないとき確認すべきポイント4つ
はじめに
Docker環境下でこんなシーンに遭遇したことはありませんか?
「Railsでバグ発生!デバッグしなきゃ!よーし、
binding.pry
しよう!」↓
「うわ、コンソール出ない!!!これじゃ何も出来ない!!!」
こんなやるせない気持ちになった方のために、自分がこれまで詰まった箇所とその解決法を残しておこうと思います。
環境
OS: macOS Catalina 10.15.3 Ruby: 2.6.5 Rails: 6.0.2.1 Docker: 19.03.5 docker-compose: 1.24.11.
binding.pry
のコンソールが出ない
docker-compose up
などでrails serverを立ち上げていて、binding.pry
を入力した箇所で動作が止まっているのに、「コンソールが出ない!どうしよう!」
という状態を想定しています。
解決法
$docker container lsでRailsアプリのあるコンテナ名を確認します。
※ここではrails_app_web_1
とします。
↓$ docker attach rails_app_web_1
docker attach
で該当コンテナにattach
します。
これで、binding.pry
したときにコンソールが表示されます。※もし反応がなければ、
Enter
押下するとコンソールが出るかもです。2.せっかくコンソールが出たのに終了の仕方がわからない
多くの場合は
binding.pry
を一回だけして終了、ということはなく、続けて何度かデバッグ作業を行うかと思います。下手に
Ctrl + C
で終了してしまうと、コンテナが停止してしまうので、立ち上げ直しになってしまってかなり面倒です。解決法
pry
の画面から終了するならcontinue
と入力してrails serverを通常動作に戻し、docker attach
を維持するのが便利です。この状態であれば、次に
binding.pry
したときもスムーズにデバッグ作業が可能です。※デバッグが終了してコンテナから抜けたい場合、
Ctrl + P + Q
(Macの場合)でコンテナを停止せずに抜けられます。3.pryで日本語入力出来ない
少し外れますが、そもそも
rails console
でpry
を使っていて、日本語が入力できないパターンもあるかもしれません。解決法
DockerfileENV LANG C.UTF-8
Dockerfile
に上記のように追記すれば解決できます。これを忘れるとpryで日本語入力が効きません。
4.コンテナがすぐ落ちる、コンソールに文字が入力できない
2020/2/6追記
解決法
docker-compose.ymlweb: tty: true stdin_open: true上記が
docker-compose.yml
のRailsに関係する箇所に書かれているかどうか確認します。(今回はweb
としています。)
tty: true
ポート待受などをしていないコンテナを起動させ続けるオプションstdin_open: true
標準入力出来るようになるオプションおわりに
最後まで読んで頂きありがとうございました
どなたかの参考になれば幸いです
- 投稿日:2020-02-05T22:06:25+09:00
【Rails】Docker環境下でbinding.pryを使えないとき確認すべきポイント3つ
はじめに
Docker環境下でこんなシーンに遭遇したことはありませんか?
「Railsでバグ発生!デバッグしなきゃ!よーし、
binding.pry
しよう!」↓
「うわ、コンソール出ない!!!これじゃ何も出来ない!!!」
こんなやるせない気持ちになった方のために、自分がこれまで詰まった箇所とその解決法を残しておこうと思います。
環境
OS: macOS Catalina 10.15.3 Ruby: 2.6.5 Rails: 6.0.2.1 Docker: 19.03.5 docker-compose: 1.24.11.
binding.pry
のコンソールが出ない
docker-compose up
などでrails serverを立ち上げていて、binding.pry
を入力した箇所で動作が止まっているのに、「コンソールが出ない!どうしよう!」
という状態を想定しています。
解決法
$docker container lsでRailsアプリのあるコンテナ名を確認します。
※ここではrails_app_web_1
とします。
↓$ docker attach rails_app_web_1
docker attach
で該当コンテナにattach
します。
これで、binding.pry
したときにコンソールが表示されます。※もし反応がなければ、
Enter
押下するとコンソールが出るかもです。2.せっかくコンソールが出たのに終了の仕方がわからない
多くの場合は
binding.pry
を一回だけして終了、ということはなく、続けて何度かデバッグ作業を行うかと思います。下手に
Ctrl + C
で終了してしまうと、コンテナが停止してしまうので、立ち上げ直しになってしまってかなり面倒です。解決法
pry
の画面から終了するならcontinue
と入力してrails serverを通常動作に戻し、docker attach
を維持するのが便利です。この状態であれば、次に
binding.pry
したときもスムーズにデバッグ作業が可能です。※デバッグが終了してコンテナから抜けたい場合、
Ctrl + P + Q
(Macの場合)でコンテナを停止せずに抜けられます。3.pryで日本語入力出来ない
少し外れますが、そもそも
rails console
でpry
を使っていて、日本語が入力できないパターンもあるかもしれません。解決法
DockerfileENV LANG C.UTF-8
Dockerfile
に上記のように追記すれば解決できます。これを忘れるとpryで日本語入力が効きません。
おわりに
最後まで読んで頂きありがとうございました
どなたかの参考になれば幸いです
- 投稿日:2020-02-05T20:37:44+09:00
RSpecの導入【備忘録】
準備
Gemfileを編集
RSpecを使用するアプリのGemfileを以下の通りに編集する
・「group :development, :test do 〜 end」に「gem 'rspec-rails'」を追加
・「group :development do」に「gem 'web-console'」を追加group :development, :test do gem 'rspec-rails' end group :development do gem 'web-console' endインストール
・ターミナルで「bundle install」を実行
# RSpecを使用するアプリのディレクトリへ移動 cd ~/projects/sample-app # 「bundle install」を実行 $ bundle installRSpecの設定
RSpec用の設定ファイルを作成
・下記のコマンドを実行
$ rails g rspec:install.rspecを編集
・下記を追加
--format documentationRSpecのディレクトリ
・specフォルダ以下にモデルやコントローラーごとにフォルダを作成し、specファイルを管理する。
sample-app
└ spec
└ models
└ specファイル
└ controllers
└ specファイルspecファイルの命名規則
対応するクラス名_spec.rb
(例)post_spec.rbテスト実行
・ターミナルで以下のコメントを実行
bundle exec rspec
- 投稿日:2020-02-05T19:28:49+09:00
RailsでHamlを書く
概要
初心者向けにhamlの基礎的な書き方とhamlにおけるrailsヘルパーメソッドのルールを書きました。
特にヘルパーメソッドの書き方は初心者がよくsyntaxエラーを起こしやすい箇所なので参考になればと思います。HTMLタグ
基礎
HTMLタグは基本的に「%」をつければOKです。
haml%div %a %input %header結果(HTML)<div></div> <a></a> <input> <header></header>クラス名、ID名
クラス名は「.(ドット)」、ID名は「#(シャープ)」をそれぞれHTMLタグの後ろにつけることで作成できます。
「.」や「#」を連続することで複数のクラス名やID名をつけることができます。また、HTMLタグ無しでクラス名やID名を記述するとdivタグになります。(divタグの省略記法)
haml%div.class-name %div#id-name %div.class1.class2.class3 .no-html-tag #no-html-tag結果(HTML)<div class="class-name"></div> <div id="id-name"></div> <div class="class1 class2 class3"></div> <div class="no-html-tag"></div> <div id="no-html-tag"></div>入れ子(ネスト)
ネストは半角2スペースで表現します。
(厳密に言うと2スペース以外もできますが、通例では2スペースです。)haml.parent .child結果(HTML)<div class="parent"> <div class="child"></div> </div>haml.parent .child 子供だよ結果(HTML)<div class="parent"> <div class="child">子供だよ</div> </div>ネストの深さでどのHTMLタグがどのHTMLタグの親かが決定します。
最初は見慣れないですが、慣れると可読性が高く、記述もHTMLより素早くできます。読むコツとしてはそのHTMLタグから視線をまっすぐ下に降ろすことです。
<下記hamlコードを例に>
「.parent」の子供はどこまでかを把握したい場合
「.parent」と同じネストの深さ(0 space)で書かれているのは「.parent-brother」なので、それまでの「.child」「.grand.child」「.brother」が子供です。「.child」の子供はどこまでかを把握したい場合
「.child」と同じネストの深さ(2 space)で書かれているのは「.brother」なので、それまでの「.grand.child」が子供です。「.brother」の子供はどこまでかを把握したい場合
次の行が自分より浅いネスト(0 space)の「.parent-brother」なので「.brother」は子供がありません。haml.parent .child .grandchild .brother .parent-brother .child結果(HTML)<div class="parent"> <div class="child"> <div class="grandchild"></div> </div> <div class="brother"></div> </div> <div class="parent-brother"> <div class="child"></div> </div>railsヘルパーメソッド
基礎
erbでは変数やヘルパーメソッドなどの表示したいものは「<%= 記述 %>」
ifやeachなどの表示したくない処理等は「<% 記述 %>」で記述していました。hamlでは以下になります。
- 表示したいものは「= 記述」
- 表示したくないものは「- 記述」
erb<%= link_to root_path %> <% hello = "こんにちわ" %> <%= hello %>haml= link_to root_path - hello = "こんにちわ" = hello結果(HTML)<a href="/">/</a> こんにちわ <!-- 「- hello = "こんにちわ"の部分は表示されない」 -->クラス名・ID名
ヘルパーメソッドにクラス名・ID名を付与する場合はHTMLタグとは違い、それぞれのヘルパーメソッドの構文に従います。
例えばLink_toは以下のような書き方が可能なのでそれに従って書きます。構文link_to(body, url = {}, html_options = {}) # url is a String; you can use URL helpers like # posts_path link_to(url, html_options = {}) do # name endhaml= link_to "リンクだよ",root_path,{class:"class-name",id:"id-name"} = link_to root_path,{class:"class-name",id:"id-name"} do リンクだよHTML(結果、どちらも同じ)<a class="class-name" id="id-name" href="/">リンクだよ</a>ネスト
ネストのルールはHTMLの項目で述べたものと同じく半角2スペースが通例です。
ここで意識すべきは記述の始まりは「=」や「-」であることです。
以下は「link_to」の始まりが揃っていますが、「=」の位置が違うのでネストの深さが違います。
初心者はよくここでエラーを起こしやすいです。haml%div = link_to root_path -#=>正 2space nest = link_to root_path -#=>誤 1space nest結果(HTML)<div> <a href="/">/</a> </div>また、逆にrailsヘルパーメソッドへ他の要素をネストさせる場合はヘルパーメソッドの構文に従います。
ここで意識すべきは「do end」で閉じる系のメソッドはendの閉じタグが不要になることです。
例えば「do end」で閉じて他の要素をネストさせることができるlink_toは以下のようになります。erb<%= link_to root_path do %> リンクだよ <% end %>haml= link_to root_path do リンクだよ結果(HTML)<a href="/">リンクだよ</a>おわりに
初心者に「公式ドキュメントを読め!」は流石に鬼畜な気もするので近日中に頻出ヘルパーメソッドについてはまとめようかと思います。
また、当記事を読んで疑問・修正等があればコメントいただけると助かります。
いいねをしていただけるとモチベーションになります!!
- 投稿日:2020-02-05T19:18:05+09:00
【heroku】ActiveRecord::IrreversibleMigration が出たときの対処法
nemlog検索サイト https://searchnemlog.herokuapp.com/
作成の時herokuデプロイで詰まってしまったので解決方法をメモしときます。ActiveRecord::IrreversibleMigration
おそらくスクレイピングを通してデータベースに保存していたので起きてしまったエラーと思われます。
以下からはこのエラーの解決手順を記したいと思います。
ロールバック
heroku run rake db:migrate:reset恐らくエラー文が表示されると思います。
そこに
DISABLE_DATABASE_ENVIRONMENT_CHECK=1と書かれていたらそれを利用してDB生成が可能になります。
ドロップ
heroku run RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:drop先ほどのエラー文を利用してドロップするとなんとかドロップしてくれます。
DB生成
あとはdb:createを実行。
heroku run rails db:createマイグレーション
最後はいつも通り heroku run をしましょう。
heroku run rake db:migrateこの手順でいけばなんとかアプリが立ち上がると思います。
まとめ
データベース系のエラーにハマるとデリケートなイメージなのでめちゃくちゃビビり倒してしまいます。
herokuエラーは前回大概ハマったと思っていましたがまだまだ見知らぬエラーがたくさんである意味奥が深いですね。
とりあえず誰かの参考になればと思います。
- 投稿日:2020-02-05T18:31:59+09:00
bin とは
binファイルとは?
binとはbinaryの略で、binファイルとは
テキスト形式ではなくバイナリ形式で書かれているデータを扱うファイル。バイナリデータとは、コンピュータが理解するためのプログラムが書かれたデータのことである。
- 投稿日:2020-02-05T18:20:58+09:00
SSH認証するための鍵をBitbucketに設定する。
そもそも鍵とは...
そもそも鍵はなぜ必要なのか。
リポジトリにアクセスするために、SSH認証キーを使う。
SSH認証することで、
・セキュリティ向上(言わずもがな)
・アクセス時に毎回パスワードを聞かれなくてストレスフリー
私が今回この記事を書こうと決めたのは、パスワードを毎回聞かれ、
ストレスがやばかったから。
では、そのSSH認証するための鍵の生成について見ていきましょう。
SSH認証するための鍵をBitbucketに設定する
1.SSH認証の公開鍵/秘密鍵を作成
2.公開鍵をクリップボードにコピー
3.Bitbucketに公開鍵を登録
SSH認証の公開鍵/秘密鍵を作成
ターミナル上で以下コマンドを叩いて、公開鍵と秘密鍵を生成。
bash$ cd ~/.ssh $ ssh-keygen -t rsa -C hoge@example.com # 自分のメールアドレス以下コマンドを叩いて、生成されたファイルを確認。
bash$ ls -l 合計 12 -rw------- 1 hoge 1831 2月 5 18:00 id_rsa -rw-r--r-- 1 hoge 405 2月 5 18:00 id_rsa.pub各ファイル名は下記です。
秘密鍵:id_rsa
公開鍵:id_rsa.pub公開鍵をクリップボードにコピー
cat(またはless)コマンドで公開鍵の内容をクリップボードにコピー。
bash$ cat id_rsa.pubBitbucketに公開鍵を登録
1.Bitbucketにログイン後、左下のユーザアイコンをクリックし、view profileをクリック。
2.「設定」をクリックし、「セキュリティ」の中の「SSH 鍵」をクリック。
3.「鍵を追加」をクリックし、「Label」に適当な名前を入力し、「Key」に先ほどクリップボードにコピーした公開鍵の中身をペースト。
4.「鍵を追加」をクリックして設定完了。
これで、リポジトリにプッシュ!!!
- 投稿日:2020-02-05T16:13:20+09:00
link_to の復習
link_toの基本形
<%= link_to "テキスト", "リンク先のパス" %> <!-- 例 --> <%= link_to "Yahoo!", "https://www.yahoo.co.jp/" %>link_toのmethodオプション
<!-- 例 --> <%= link_to "削除", "/users/1", method: :delete %>何も指定しないとGETが指定される。
link_toのtargetオプション
_blankで新規のウィンドウを開いて表示させる。
_selfで現在のウィンドウで表示させる<%= link_to 'link_toリファレンス', yokota_path , { :class => "outer", :target => "_blank"} %>link_toのclassオプション
<%= link_to "トップページ", "/", class: "hoge" %>link_toとhtmlの合わせ技
<%= link_to "/" do %> <i class="fas fa-home"></i> トップページ <% end %>画像のリンクを作成しよう
<%= link_to image_tag('test.jpg', class: "クラス名"), 'パス' %>dataオプションを使う
<%= link_to "削除", user_path(user), method: :delete, data: { confirm: "本当に削除しますか?" } %>
- 投稿日:2020-02-05T15:16:52+09:00
rails_same_site_cookie gemで、RailsアプリにChrome 80向けのSameSite属性を指定する
はじめに
以下の記事にあるとおり、Chrome 80では2020年2月17日の週以降にデフォルトのSameSite属性が変更されます。
Chrome 80が密かに呼び寄せる地獄 ~ SameSite属性のデフォルト変更を調べてみた - Qiita
この変更が入ると、次のように「決済や認証などで外部サービスを利用し、外部サイトからPOSTで戻ってくるサイト」でユーザーが識別できないエラーが発生します。
(画像の引用元:Chrome 80が密かに呼び寄せる地獄 ~ SameSite属性のデフォルト変更を調べてみた - Qiita)本記事ではRailsアプリケーションでこの問題に対応する方法を紹介します。
免責事項 (disclaimer)
この記事のとおりにあなたのRailsアプリケーションを変更して、何らかの不具合やセキュリティ上の問題が発生しても筆者は一切の責任を負いません。
技術的な背景と最新の技術情報を十分理解した上で、本記事の内容を適用してください。
(適用する必要がない場合は何もしないでください)対応方法
rackのバージョンを2.1.0以上に上げます。
(2.1.0以上でないと、SameSite=None
属性に対応していないため - 参考)(訂正:rails_same_site_cookieはrackの機能ではなく、独自にCookieを設定しているため、必ずしもrack 2.1.0以上に上げる必要はないようです)
rails_same_site_cookie gemをインストールします。
Gemfilegem 'rails_same_site_cookie'$ bundle install対応は以上です。
rails_same_site_cookie gemがやってくれること
rails_same_site_cookie
gemをインストールすると、自動的に全cookieにSameSite=None; Secure
属性が追加されます。ただし、iOS 12とmacOS 10.14のSafariなど、
SameSite=None; Secure
属性を付けると不具合が発生するブラウザ(参考)に対してはこの属性を付与しません。rails_same_site_cookie gemがやってくれないこと
rails_same_site_cookie gemはRails側のCookieを変更するだけで、JavaScript側で設定するCookieには何も変更を加えません。
もしJS内でCookieを設定しているコードがある場合は、何らかの対応が必要になります。(詳細未調査)参考1:動作確認の手順(例)
「決済で外部サービスを利用し、外部サイトからPOSTで戻ってくるサイト」を想定した場合の確認手順です。
いきなり本番環境で試すのではなく、テスト環境(ステージング環境)で試すようにしてください。
- こちらの手順に従って、Chromeの設定を変更する
- Railsアプリサイト上で商品を購入し、外部の決済サービスに遷移する
- 2分以上待つ(2分以上待たないとChromeがCookieを送信してしまうため)
- 決済を実行して、自サイトに戻る
- ログイン情報が維持されたまま、正常に決済が完了することを確認する(修正前は何らかの不具合が発生することも事前に確認しておく)
参考2:リクエストスペックでテストを書く(例)
SameSite=None
属性が適切に付与されているかどうかを確認するリクエストスペックの記述例です。
(非SSLで接続する場合、rails_same_site_cookie gemはSameSite=None
属性だけを付与し、Secure
属性は付与しません)ログイン処理はDeviseで実現されていることを前提とします。
テストコード内の_your_app_session
は、適宜ご自身のアプリケーション名に合わせて変更してください。spec/requests/cookies_spec.rbrequire 'rails_helper' RSpec.describe 'Cookies', type: :request do describe 'Cookie の SameSite 属性' do before do user = create :user login_as user end it 'User-Agent指定無しの場合 SameSite=None がつく' do get new_user_session_path expect(response.headers['Set-Cookie']).to match /_your_app_session=.*SameSite=None/ end it 'SameSite=Lax がデフォルトになる Chrome 80 では SameSite=None がつく' do mac_chrome_80 = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.42 Safari/537.36 ' win_chrome_80 = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.16 Safari/537.36' get new_user_session_path, headers: { 'User-Agent' => mac_chrome_80 } expect(response.headers['Set-Cookie']).to match /_your_app_session=.*SameSite=None/ get new_user_session_path, headers: { 'User-Agent' => win_chrome_80 } expect(response.headers['Set-Cookie']).to match /_your_app_session=.*SameSite=None/ end it 'SameSite=Noneの扱いにバグがある iOS12 Safari では SameSite=None がつかない' do iphone_ios12_user_agent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1' get new_user_session_path, headers: { 'User-Agent' => iphone_ios12_user_agent } expect(response.headers['Set-Cookie']).to include '_your_app_session=' expect(response.headers['Set-Cookie']).not_to include 'SameSite' end end end参考文献
本記事を書くにあたって、下記記事を参考にさせてもらいました。
どうもありがとうございました。
- 投稿日:2020-02-05T15:13:06+09:00
JavaScript上でObjectをRailsで取得できる形のFormDataへ変換する
概要
TypeScript上で、
File
を含んだObjectをRails APIにputやpostしたい。
→ そのままだとFile
がうまく渡らないのでFormData
にする必要がある。
→File
以外のパラメータも含んだObject
をFormData
に変換したい。コード
/** * Convert object to FormData which rails can use. * This function is useful for uploading files. * * ex) * { id: 1, hero: { id: 1, name: 'NewHero' }, items: [1, 2] } * -> FormData with following parameters * id: 1 * hero[id]: 1 * hero[name]: NewHero * items[]: 1 * items[]: 2 * * @param params * @return FormData */ export const convertParamsToForm = (params: object): FormData => { const formData = new FormData(); const appendParamsToForm = (variable, prefix = '') => { if (typeof variable !== 'object' || variable instanceof File) { formData.append(prefix, variable); return; } if (Array.isArray(variable)) { variable.forEach(value => appendParamsToForm(value, `${prefix}[]`)); return; } Object.keys(variable).forEach(key => { appendParamsToForm( variable[key] || '', prefix ? `${prefix}[${key}]` : key ); }); }; appendParamsToForm(params); return formData; };
- 投稿日:2020-02-05T15:07:52+09:00
【Rails】ActiveRecordの`find_by`で大文字と小文字を区別しないで取得する方法
はじめに
find_by
メソッドで値を取得する際にハマったので解決方法を探してみました。Rails : 6.0
Ruby: 2.7
SQLite3以上の環境しか確認していません。
検索対象と検索したい文字列を大文字に変換
保存されたタグを取得する際、大文字と小文字の違いで期待した値を取得することができない。
$ rails console # 大文字と小文字を混ぜた状態で保存します > Tag.create(tag_name: "RuBy") > # 小文字で先程作成したタグ名を検索してみます > Tag.find_by(tag_name: "ruby") #=> nilTags テーブルに保存された値は
"RuBy"
と保存しているためfind_by
メソッドで"ruby"
と検索しても取得することができません。ユーザーがタグを検索したい場合、
"ruby"
や"Ruby"
、"RUBY"
など様々な入力で検索する可能性があるため、大文字と小文字で区別されてしまうのは不便です。
大文字と小文字を区別せず
find_by
メソッドで取得するためには、SQL のupper()
関数を使いカラムに含まれる文字列を大文字に変換して、検索したい文字列も Ruby のupcase
メソッドで大文字に変換して取得します。$ rails console # 大文字と小文字を混ぜた状態で保存します > Tag.create(tag_name: "RuBy") > # 検索対象のカラムと検索したい文字列をそれぞれ大文字に変換 > Tag.find_by('UPPER(tag_name) = ?', "ruby".upcase) #=> tag_name: "RuBy"これで Tags テーブルの値を大文字と小文字を区別することなく取得することができました。
'UPPER()'
と大文字にしているのは SQL 的な記述のためなので、特に意味はありませんupper()
としても動作します。
- 投稿日:2020-02-05T13:18:21+09:00
factory_botでモデルのenum別のtraitを一発で書く小ネタ
今回はRailsでテストデータを作成する”factroy_bot”に関する小ネタです。
TL DR;
こんな感じでイケちゃう
User.account_type.values.each do |type| trait :"#{type}" do account_type { type } end end動作環境
- Rails: 5.2.3
- Ruby: 2.6.5
- factory_bot: 5.0.2
- factory_bot_rails: 5.0.1
※今回はRubyの記法に依る部分が大きいので、上記バージョンはあまり気にしなくても良いです
コード例
想定するモデル
この記事では以下のような
User
モデルを例として考えます。プロダクトコードによくある「複数のユーザー種類をenumのカラム(今回は例としてaccount_type
とする)で持ち判別する」モデルです。app/models/user.rbclass User < ApplicationRecord validates :name, presence: true # 中略 extend Enumerize enumerize :account_type, in: { normal: 0, admin: 1, client: 2, development: 3 }, scope: true endどうでもいい話ですが、色々な種類のユーザーが存在し、しかも同じユーザーが複数の種類を持つといった、ユーザー周りが複雑になるのはあるあるですが、本当にツラいですよね。AdminかEndUserかの2択ぐらいで収まれば、それぞれのユーザーから見える画面もきれいに分割できて丁度いいのですが...。
普通にfactoryを書く場合
さて、このようなenumカラムを持つUserモデルを素直にfacrotyで表現すると、このようになります。ああめんどくさい。モデルが複雑になれば、factoryが複雑になるのは当然のことですが...
spec/factories/user.rbFactoryBot.define do factory :user do name { 'test' } # 中略 trait :normal do account_type { normal } end trait :admin do account_type { admin } end trait :client do account_type { client } end trait :development do account_type { development } end end endやりたいこと
こんな意味のないコードをチマチマ全部書くのはやりたくない。いやでも書くしか無いし、一旦Pushするか...。いや、なんかそれらしいカッコいいやり方があるはずだ。多分。ほんの数行で全部のenumのtraitを生み出すやり方が。ついでに、カラムのenum定義が増えたときにも勝手に増えるようにしてほしい。忘れそうだし。
小技
そこで小技を使うと、こんな感じで書けます。「まさか動かないだろう」と思い、冗談で書いたら動きました。Rubyってすごい。
spec/factories/user.rbUser.account_type.values.each do |type| trait :"#{type}" do account_type { type } end end
User.account_type.values
と、enumのカラムから直接traitを作っているので、enumの定義が増えたときにテストデータを作り忘れることもありません。ユーザーの氏名やアドレスを表すカラムがあれば、そこに同様にtype
変数を突っ込めば、RSpecのテスタビリティも向上しそうです。ちなみに、
User.account_type.values
の部分はこんな感じで動作しています。ハッシュでenumを取り出して、そのvalueをvalues
メソッドで配列化し、その配列の値でtraitを定義しているわけです。もちろん必要であれば、keyとvalueの両方を取り出して使うこともできます。[1] pry(main)> User.account_type.values => ["normal", "admin", "client", "development"] [2] pry(main)> User.account_type => #<Enumerize::Attribute:0x0000558ff649f058 @i18n_scopes=["enumerize.user.account_type"], @klass=User (call 'User.connection' to establish a connection), @name=:account_type, @skip_validations_value=false, @value_hash= {"0"=>"normal", "1"=>"admin", "2"=>"client", "3"=>"development", "normal"=>"normal", "admin"=>"admin", "client"=>"client", "development"=>"development"}, @values=["normal", "admin", "client", "development"]>余談...
まあ、実際のプロダクトコードでは、各enumごとに紐付くアソシエーションも変更する必要があったりするので、なかなかこれ一つで完璧にtraitを表現することは難しいです。とはいえ、必要であれば切り出して書けばよいですし、アソシエーションが複雑になる前にスピーディーにテストデータを作りたい場合はぜひ。
- 投稿日:2020-02-05T13:13:35+09:00
Railsでbundle installができない
問題
bundle install
をするとInstalling mysql2 0.5.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
(略)
An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue.
Make sure thatgem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'
succeeds before bundling.と出る
指示通り
gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'
を走らせても解決しない解決策
bundle config
を実行するとbuild.mysql2
Set for your local app (/Users/ユーザー名/アプリケーション名/.bundle/config): "--with-cppflags=-I/usr/local/opt/openssl@1.1/include"
と出るそこで
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib"
を実行した
bundle config
で確認すると
build.mysql2
Set for your local app (/Users/GO/source_code/clubru/.bundle/config): "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib"
となっていた再度
bundle install
を実行すると無事mysqlをインストールできた調べて出てきた結果と違ったこと
自分の場合は
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib"
で解決したが、調べて出てきた解決策は
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib --with-cppflags=-I/usr/local/opt/openssl@1.1/include"
や
bundle config --local build.mysql2 "--with-cppflags=-I/usr/local/opt/openssl@1.1/include"
datta
- 投稿日:2020-02-05T11:50:02+09:00
【RSpec】重複のバリデーションエラーを回避するFactoryBotの書き方
ユーザー登録でemailを重複させないようにバリデーションをかけましが、テストのときにでFactoryBotで複数ユーザを予め生成する必要があったので方法を調べました。シーケンスを使ってユニークなデータを生成するやり方です。備忘録として残します。
問題点
ファクトリーで複数のユーザをセットアップする際に、emailをバリデーションでユニークなデータとして設定している場合、下記のようにするとテストコードが走る前に例外が発生します。
spec/factories/users.rbFactoryBot.define do factory :user do user_name { "tester" } email { "tester@example.com" } password { "password" } end endspec/models/user_spec.rbit "複数のユーザー登録" do user1 = FactoryBot.create(:user) user2 = FactoryBot.create(:user) endこれでテストを実行すると、当然ですが次のようなバリデーションエラーが発生します。
ターミナルFailures: 1) 複数のユーザー登録 Failure/Error: user2 = FactoryBot.create(:user) ActiveRecord::RecordInvalid: バリデーションに失敗しました: メールアドレスはすでに存在します解決策
シーケンスを使います。シーケンスはファクトリから新しいオブジェクトを作成するたびにカウンタの値を1づつ増やしながら値を設定します。
spec/factories/users.rbFactoryBot.define do factory :user do user_name { "tester" } sequence(:email) { |n| "tester#{n}@example.com" } password { "password" } end end
email { "tester@example.com" }
をsequence(:email) { |n| "tester#{n}@example.com" }
と書き換えることで、userが生成されるたびにn
が1づつ増えていき、tester1@example.com
tester2@example.com
のようにユニークで連続したemailが設定されます。ターミナル#見やすいように加工してあります user1 <User id: 13, user_name: "tester", email: "tester1@example.com", password: "password", created_at: "2020-02-05 01:56:36", updated_at: "2020-02-05 01:56:36">ターミナル#見やすいように加工してあります user2 <User id: 14, user_name: "tester", email: "tester2@example.com", password: "password", created_at: "2020-02-05 01:57:21", updated_at: "2020-02-05 01:57:21">
- 投稿日:2020-02-05T10:52:54+09:00
【Rails6】ActiveRecordで与えられた配列順にorderする
やりたいこと
ActiveRecordを与えられた配列順でorderしたい。
ids配列にユーザのidが格納されていて、このidの格納順に従って、Userモデルに対してorderしたい。ids = [6,2,24,5,3,7]問題
Rails5.1までは以下の書き方で配列ids順にuserをorderすることができました。
User.where(id: ids).order(['field(id, ?)', ids])しかし、Rails5.2以降(Rails 6も)ではこのような書き方をすると
エラーが発生します。DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "FIELD(id, ?)". Non-attribute arguments will be disallowed in Rails 6.1. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql().Rails5.2以降は、SQLインジェクションを防ぐためにorderの引数に属性以外の文字列を取れなくなりました。今回でいうところの
field
が属性以外の文字列に当たってしまうと考えられます。解決方法
Arel.sql()で囲めば良いので以下の書き方に変更します。
User.where(id: ids).order([Arel.sql('field(id, ?)'), ids])また、機械的に
Arel.sql()
で囲むのではなく、引数が安全な値であることを確認した上でArel.sql()
を使いましょう。
https://qiita.com/jnchito/items/5f2f00c93c0ba68e4d31ちなみに、この書き方どうするんだっけ?って思ってググっても出てこない時は、
Railsプロジェクトのテストコードを見ると解決することが多い。今回の件に関してはRails6のテストコードで以下の書き方をされている。
def test_finding_with_sanitized_order query = Tag.order([Arel.sql("field(id, ?)"), [1, 3, 2]]).to_sql assert_match(/field\(id, 1,3,2\)/, query) query = Tag.order([Arel.sql("field(id, ?)"), []]).to_sql assert_match(/field\(id, NULL\)/, query) query = Tag.order([Arel.sql("field(id, ?)"), nil]).to_sql assert_match(/field\(id, NULL\)/, query) end
- 投稿日:2020-02-05T09:56:09+09:00
uninitialized constant ActionDispatch::Session::RedisStore (NameError)エラーを解消する
エラーの内容
Rails 5.2からはredisがビルドインされるようになりました。
それに伴いredis-rails
gemが不要になったとのことでGemfileから削除しましたが、以下のエラーが発生しました。
https://railsguides.jp/5_2_release_notes.html#redis-cache-store
NameError: uninitialized constant ActionDispatch::Session::RedisStore
と言われているので、Redis関連の設定に関係していることがわかります。NameError: uninitialized constant ActionDispatch::Session::RedisStore /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/configuration.rb:282:in `const_get' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/configuration.rb:282:in `session_store' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/default_middleware_stack.rb:61:in `block in /usr/local/bundle/gems/actionpack-6.0.2.1/lib/action_dispatch/middleware/stack.rb:72:in `initialize' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/default_middleware_stack.rb:15:in `new' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/default_middleware_stack.rb:15:in `build_stack' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application.rb:571:in `default_middleware_stack' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/engine.rb:510:in `block in app' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/engine.rb:508:in `synchronize' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/engine.rb:508:in `app' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/finisher.rb:97:in `block in <module:Finisher>' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/initializable.rb:32:in `instance_exec' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/initializable.rb:32:in `run' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/initializable.rb:61:in `block in run_initializers' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/initializable.rb:60:in `run_initializers' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application.rb:363:in `initialize!' /app/config/environment.rb:5:in `<main>' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block _bootsnap_lfi' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in ootsnap_lfi' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' /usr/local/bundle/gems/zeitwerk-2.2.2/lib/zeitwerk/kernel.rb:23:in `require' /usr/local/bundle/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in `block in require' /usr/local/bundle/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:291:in `load_dependency' /usr/local/bundle/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in `require' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application.rb:339:in `require_environment!' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application.rb:515:in `block in run_tasks_blocks' /usr/local/bundle/gems/rake-12.3.3/exe/rake:27:in `<top (required)>' /usr/local/bundle/bin/bundle:23:in `load' /usr/local/bundle/bin/bundle:23:in `<main>' Tasks: TOP => db:migrate => db:load_config => environment (See full trace by running task with --trace) DEPRECATION WARNING: SourceAnnotationExtractor is deprecated! Use Rails::SourceAnnotationExtractor instead. (called from <main> at /app/config/application.rb:7)解決方法
redis-rails
gemのissueを読んでいると、どうやらSessionをredisで管理するにはredis-actionpackというgemが必要みたいです。there's no need to use redis-rails if you're using Rails 6, since it ships with its own cache store, :redis_cache_store. if you want to use the session management capabilities, you can just use gem 'redis-actionpack'. this gem was made to make it a bit easier to include redis-store into the app
さっそく
redis-actionpack
をbundle installします。gem 'redis-actionpack'$bundle installこれでエラーが解消できました。
- 投稿日:2020-02-05T09:56:09+09:00
uninitialized constant ActionDispatch::Session::RedisStore (NameError)
エラーの内容
Rails 5.2からはredisがビルドインされるようになりました。
それに伴いredis-rails
gemが不要になったとのことでGemfileから削除しましたが、以下のエラーが発生しました。
https://railsguides.jp/5_2_release_notes.html#redis-cache-store
NameError: uninitialized constant ActionDispatch::Session::RedisStore
と言われているので、Redis関連の設定に関係していることがわかります。NameError: uninitialized constant ActionDispatch::Session::RedisStore /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/configuration.rb:282:in `const_get' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/configuration.rb:282:in `session_store' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/default_middleware_stack.rb:61:in `block in /usr/local/bundle/gems/actionpack-6.0.2.1/lib/action_dispatch/middleware/stack.rb:72:in `initialize' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/default_middleware_stack.rb:15:in `new' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/default_middleware_stack.rb:15:in `build_stack' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application.rb:571:in `default_middleware_stack' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/engine.rb:510:in `block in app' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/engine.rb:508:in `synchronize' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/engine.rb:508:in `app' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application/finisher.rb:97:in `block in <module:Finisher>' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/initializable.rb:32:in `instance_exec' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/initializable.rb:32:in `run' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/initializable.rb:61:in `block in run_initializers' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/initializable.rb:60:in `run_initializers' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application.rb:363:in `initialize!' /app/config/environment.rb:5:in `<main>' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block _bootsnap_lfi' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in ootsnap_lfi' /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' /usr/local/bundle/gems/zeitwerk-2.2.2/lib/zeitwerk/kernel.rb:23:in `require' /usr/local/bundle/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in `block in require' /usr/local/bundle/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:291:in `load_dependency' /usr/local/bundle/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in `require' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application.rb:339:in `require_environment!' /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/application.rb:515:in `block in run_tasks_blocks' /usr/local/bundle/gems/rake-12.3.3/exe/rake:27:in `<top (required)>' /usr/local/bundle/bin/bundle:23:in `load' /usr/local/bundle/bin/bundle:23:in `<main>' Tasks: TOP => db:migrate => db:load_config => environment (See full trace by running task with --trace) DEPRECATION WARNING: SourceAnnotationExtractor is deprecated! Use Rails::SourceAnnotationExtractor instead. (called from <main> at /app/config/application.rb:7)解決方法
redis-rails
gemのissueを読んでいると、どうやらSessionをredisで管理するにはredis-actionpackというgemが必要みたいです。there's no need to use redis-rails if you're using Rails 6, since it ships with its own cache store, :redis_cache_store. if you want to use the session management capabilities, you can just use gem 'redis-actionpack'. this gem was made to make it a bit easier to include redis-store into the app
さっそく
redis-actionpack
をbundle installします。gem 'redis-actionpack'$bundle installこれでエラーが解消できました。
- 投稿日:2020-02-05T01:09:06+09:00
Rails の Credentials を Webpacker で管理するフロント側に共有したい
賛否ありますが、Railsにベッタリの開発をしていると、なるべくRailsに寄せて考えたくなることがあります。
そんな
- Webpacker 使ってるプロジェクト
- 環境によって変わる値を環境変数ではなく Credentials にまとめたい。分散させたくない。
- フロントエンドでも使いたい。たとえば Firebase の Project ID や API Key のようなDev,Stg,Prod環境ごとに違って、かつフロントエンドコードに含めて問題ないもの。
そんなときの話です。
- webpack 4.41.5
- webpack-dev-server 3.10.2
- webpacker 4.2.2
- Rails 6.0.1
Webpacker::Compiler.env は bin/webpack-dev-server を使うとうまくいかない
こんな Credentials があったとき
# bundle exec rails credentials:edit --environment=development firebase: project_id: FIREBASE_PROJECT_ID api_key: FIREBASE_API_KEY auth_domain: FIREBASE_PROJECT_ID.firebaseapp.comRails から Webpacker に環境変数を渡すには
Webpacker::Compiler.env
が使えます。
Pass custom environment variables to the compiler #691config/initializers/webpacker.rbWebpacker::Compiler.env["FIREBASE_API_KEY"] = Rails.application.credentials.dig(:firebase, :api_key) Webpacker::Compiler.env["FIREBASE_AUTH_DOMAIN"] = Rails.application.credentials.dig(:firebase, :auth_domain) Webpacker::Compiler.env["FIREBASE_PROJECT_ID"] = Rails.application.credentials.dig(:firebase, :project_id)app/javascript/src/firebase.jsimport * as firebase from "firebase/app"; import "firebase/auth"; // "FIREBASE_PROJECT_ID: FIREBASE_PROJECT_ID" console.log(`FIREBASE_PROJECT_ID: ${process.env.FIREBASE_PROJECT_ID}`); const config = { apiKey: process.env.FIREBASE_API_KEY, authDomain: process.env.FIREBASE_AUTH_DOMAIN, projectId: process.env.FIREBASE_PROJECT_ID }; firebase.initializeApp(config); export default firebase;これは、Rails Server にアクセスした際にビルドする場合や、
assets:precompile
でビルドする場合には動くのですが、bin/webpack-dev-server
では動作しません。困ったことに
bin/webpack-dev-server
を使ったHMRの快適さに慣れると、いちいちF5なんてやってられません。$ bin/webpack-dev-serverapp/javascript/src/firebase.jsimport * as firebase from "firebase/app"; import "firebase/auth"; // "FIREBASE_PROJECT_ID: undefined" console.log(`FIREBASE_PROJECT_ID: ${process.env.FIREBASE_PROJECT_ID}`); const config = { apiKey: process.env.FIREBASE_API_KEY, authDomain: process.env.FIREBASE_AUTH_DOMAIN, projectId: process.env.FIREBASE_PROJECT_ID }; firebase.initializeApp(config); export default firebase;Webpacker::Compiler.env はどう使われるか?
Webpacker::Compiler.compile
rails assets:precompile
を実行したり、ビュー中でjavascript_pack_tag
ヘルパーを実行したりすると、Webpacker::Compiler.compile
が呼ばれます。(javascript_pack_tag
はwebpack-dev-server
を実行していないときのみ。このへんのコードによる )
Webpacker::Compiler.compile
はWebpacker::Compiler.env
の値を環境変数に設定した上でbin/webpack
を実行します。bin/webpack-dev-server
bin/webpack-dev-server
を実行したときには、Webpacker::Compiler.compile
は呼ばれません。
config/webpacker.yml
から設定を読み出すなどした後、直接node_modules/.bin/webpack-dev-server
を実行します。このとき環境変数としてWebpacker::Compiler.env
を渡します。https://github.com/rails/webpacker/blob/master/lib/webpacker/dev_server_runner.rb#L64
Webpacker と環境変数
通常、Webpack では、JavaScriptモジュール中の
process.env.HOGE
の値は未定義値となります。Webpacker では標準で Webpack の EnvironmentPlugin を使って、これができるようになっています。
Webpacker しか知らないと参照できて当たり前のように感じてしまいますが、これは Webpacker が気を回してくれてたからなんですね。config/webpack/environment.jsconst { environment } = require("@rails/webpacker"); // この environment // こうすると EnvironmentPlugin があることがわかる console.log(environment.plugins); module.exports = environment;この2つの仕組みにより
Webpacker::Compiler.env
に設定した値を JavaScript モジュール内で参照できるようになっています。bin/webpack-dev-server ではなぜ Webpacker::Compiler.env が機能しないか
上記
bin/webpack-dev-server
を実行したときには、Webpacker::Compiler.compile
は呼ばれません。
config/webpacker.yml
から設定を読み出すなどした後、直接node_modules/.bin/webpack-dev-server
を実行します。このとき環境変数としてWebpacker::Compiler.env
を渡します。の通り、
bin/webpack-dev-server
でもWebpacker::Compiler.env
は使っています。
しかしながら、assets:precompile
やjavascript_pack_tag
と違い、機能しません。これは、
bin/webpack-dev-server
では、Railsを起動しないためconfig/initializers/webpacker.rb
に書いたコードは実行されないためです。bin/webpack-dev-server でも Webpacker::Compiler.env を使う
A.
config/initializers/webpacker.rb
を実行する
bin/webpack-dev-server
に次の2行を追加すると、Railsの初期化が走り、 initializers でWebpacker::Compiler.env
を設定できます。
しかし「Rails.application.credentials
にアクセスしたい」だけなのに、これはやり過ぎです。require_relative '../config/application' Rails.application.initialize!B.
config/initializers/webpacker.rb
とbin/webpack-dev-server
でコードを共有する
Rails.application.credentials
はRailsの初期化処理なしでもアクセスできます。たとえば次のようにして共有できます。
config/webpacker_env.rbWebpacker::Compiler.env["FIREBASE_API_KEY"] = Rails.application.credentials.dig(:firebase, :api_key) Webpacker::Compiler.env["FIREBASE_AUTH_DOMAIN"] = Rails.application.credentials.dig(:firebase, :auth_domain) Webpacker::Compiler.env["FIREBASE_PROJECT_ID"] = Rails.application.credentials.dig(:firebase, :project_id)config/initializers/webpacker.rbrequire_relative "../webpacker_env"# 追加 require_relative '../config/application' require_relative "../config/webpacker_env"あとがき
がんばって Rails / Webpacker でなんとかするために Webpacker のコード読むぐらいなら Webpacker 捨てて Webpackの流儀でやれ、という気持ちになりましたが、一応動かすことはできました。
設定情報の二重管理をせず、手間をかけず、もっと自然に共有する方法はないものだろうか?