Gemfileの有無で変わる読み込まれる.rubocop.ymlの優先順位

最初に

予期せぬ~/.rubocop.ymlが読み込まれいてトラブっているのを見たので、
.rubocop.ymlがどういう順序で読み込まれたりするのかについて調査した。

説明するのが難しいけれど、書いて公開しておかないとせっかく調査したのに忘れてしまいそうなので、書いてみる。

複数の.rubocop.yml設定ファイルを読み込むRuboCop

ここで前提として、rubocopコマンドのコマンド引数で、親ディレクトリなどの祖先は指定しないものとする。
なお、rubocop.yml ..みたいな形で、親を指定するとエラーが起きたりした。

ルールによっては、優先順位などが変わることもあるようだけど、基本的には以下のような感じ。

  • Rubyファイルから見て、同じ位置か上位にある.rubocop.ymlのルール適用される。
  • 複数の.rubocop.ymlが見られる場合に、同じCopルールがあれば下にある.rubocop.ymlの方が優先順位が高い。

プロジェクトルートディレクトリというのは、Gemfileかgems.rbという名前のファイルがディレクトリ。
(GemfileはBundlerでよく使うけど、gems.rbは知らない)

コマンド実行位置が、ホームディレクトリでもプロジェクトルートディレクトリでもない場合は、
上位にあるプロジェクトルートディレクトリかホームディレクトリを見られる。

ホームディレクトリのrubocop.ymlでrubocop-railsを読み込むべきではない。

gem install rubocop-railsで、RuboCop本家で開発されているRails用のgemをインストールできる。

これで、(書くべきではないが実験のため)ホームディレクトリの.rubocop.ymlで、 rubocop-railsを適用させる。

AllCops:
  NewCops: enable
require:
  - rubocop-rails

通常RailsアプリにはGemfileがあり、Railsアプリのプロジェクトルートでない位置でrubocopコマンドを打っても、
Railsアプリのプロジェクトルートにある.rubocop.ymlが読み込まれる。

しかし、Gemfileのない普通のRubyコードに対してrubocopコマンドを打つと、
ホームディレクトリの.rubocop.ymlも読み込まれる。
だから、もしこのホームの.rubocop.ymlRails用のルールを適用させるルールがあれば、
RailsのコードじゃないのにRailsのルールを適用してきてしまう。

だから、「ホームディレクトリに便利かも」みたいに思ってRails用のルールを適用させてしまうのはよくない。

ドキュメントも読んで確かめてみる

Configuration :: RuboCop Docs

As an example, if RuboCop is invoked from inside /path/to/project/lib/utils, then RuboCop will use the config as specified inside the first of the following files:
-  /path/to/project/lib/utils/.rubocop.yml
-  /path/to/project/lib/.rubocop.yml
- /path/to/project/.rubocop.yml
- /.rubocop.yml
- ~/.rubocop.yml
- ~/.config/rubocop/config.yml
- RuboCop’s default configuration

公式ドキュメントに書いてある英語の細かいニュアンスなどがわかりにくいが、優先順位が書いてある。
よく見ると、ホームディレクトリよりルートディレクトリの方が優先順位が高かったりして、必ずしも子の方が優先されるというわけでもないらしい。
ただ、普通はPCのルートディレクトリに.rubocop.ymlを書いたりしないだろうし、気にすることではないだろう。

しかし、公式ドキュメントのどのあたりを読めば、ホームディレクトリかGemfileのあるプロジェクトルートディレクトリの.rubocop.ymlも読み込まれるのかはわからなかった。

最後に

読み込まれる.rubocop.ymlが1つだけなのか複数あるのかとか、どういう順番なのかとか、そういうのを一切知らずになんとなく使ってきていたので、読み込まれる順番がわかってよかった。

【ドキュメンタリ映画】「まったく同じ3人の他人」を見た

最初に

実際にあった生き別れの三つ子のドキュメンタリ映画。
原題は「Three Identical Strangers」。 いっしーさんがオススメしてたので知って見ました。

昨日観たドキュメンタリー映画で感動…ではなく心底震え上がりましたので超オススメです。 あと数日でNetflix配信終了してしまいますが…

(フィヨルドブートキャンプのDiscordの映画チャンネルより)

1961年7月12日誕生し、19歳で再開

1961年7月12日誕生のアメリカで三つ子が生まれ生き別れ、19歳の頃に偶然に再開。
三つ子が生き別れる。そんなことが現実にあるんですね。
再開したあとは、チヤホヤされ時の人となり、TV番組にでたり、映画にもちょい役ででたそうです。
なお、映画名について調べたら、『マドンナのスーザンを探して』(原題:Desperately Seeking Susan) でした。

それにしても、現実で生き別れることなんてどうしたら起こるんでしょうか。
それぞれの三つ子は、各家庭で養子として引き受けられますが、どの親も三つ子であることは知らずに育てました。
実は三つ子であるとした各家庭の育ての親は、当然のように養子縁組機関に怒ったようです。

【ネタバレ】なぜ生き別れたのか

以下、ネタバレを含みます。

事実は小説より奇なり。
なぜ三つ子が生き別れたのか。
それは、別々の家庭で育てられたら、性格などにどういう影響がでるのかを知る壮大な実験だったとのことです。
他にも生き別れになった双子がいて、それを知らないままの双子もいるとのことです。
そんな実験ができちゃうなんて、すごいですね。

三つ子は、同じ年齢差の姉がいて、それぞれ異なる経済環境の家庭に育ててもらって、比較実験されていたようです。

実験の結果

実験の結果は2066年に全てを明らかにする予定はあるのだとか。
そしたら、他にも実験のモルモットにされた双子が明らかになる。
ずっと1人で生まれたとして育った方が、実は生き別れた双子だったと知ったときってどんな気持ちになるんでしょう。
このドキュメンタリの三つ子は、比較的若いときに再開できて結構楽しそうでしたけど、 今だったらそれぞれ別の家庭をもって孫もいそうで、2人とも全く異なる人生を送ってそうだし、別の雰囲気になりそうですね。
それぞれの性格によっても、その事実を受け入れられるかどうかも大きく変わりそうです。

エディと映画の結論について

最後の方、ドキュメンタリー映画側で、遺伝よりも環境が大事みたいな結論にもって行きすぎな感じがしました。
特にエディの自死について、厳格な父親の家庭で育ったから自殺したと責めている風で、エディの育ての父が可哀想になりました。

最後に

現実ってすごいなって思いました。
最近はドキュメンタリー映画って見てなかったんですけど、比較的好みのジャンルだし、ドキュメンタリー映画をもっと見ていきたいなと思いました。

参考

Wikipedia: まったく同じ3人の他人

【Rails+Devise】ArgumentError: SMTP From address may not be blank: nil

最初に

開発環境では動くけれど、テストや本番環境では動かず原因がなかなかわからず大変だった。
色々原因はあったけれど、環境変数の乱用が1番よくなかった気がする。
あと、Mailgunの導入でそっち関係のエラーだと勘違いして、実際はDevise側の設定で、問題を正常に切り分けられていなかった。

謎のエラー

「ユーザー登録」のボタンをクリックすると、メールアドレス確認用のメールを送る。
この際に、ローカルではエラーが起きなかったが、CI環境と本番環境でエラーが起きていた。

ArgumentError: SMTP From address may not be blank: nil
エラー文はこのように書かれている。何らかの原因でどこかでnilになってしまい、エラーになっているようだ。
SMTP From address ?

テスト環境でのエラー

rails test:allコマンドを打って、システムテストをしているときに生じたエラー

Rack app ("POST /users" - (127.0.0.1)): #<ArgumentError: SMTP From address may not be blank: nil>
E

Error:
SignUpTest#test_sign_up:
ArgumentError: SMTP From address may not be blank: nil

本番環境(Heroku)でのエラー

heroku logs -t

2021-07-23 app[web.1]: I, [2021-07-23 #4]  INFO -- : Rendered devise/mailer/confirmation_instructions.html.erb (Duration: 2.0ms | Allocations: 351)
2021-07-23 app[web.1]: I, [2021-07-23 #4]  INFO -- : Delivered mail asdfghjkl1234567890@asdfghjkl1234567890.mail (753.9ms)
2021-07-23app[web.1]: I, [2021-07-23 #4]  INFO -- : Completed 500 Internal Server Error in 801ms (ActiveRecord: 8.1ms | Allocations: 7800)
2021-07-23 app[web.1]: F, [2021-07-23 #4] FATAL -- :
2021-07-23 app[web.1]:  ArgumentError (SMTP From address may not be blank: nil):
2021-07-23 app[web.1]:
2021-07-230 app[web.1]:  mail (2.7.1) lib/mail/check_delivery_params.rb:13:in `check_from'

原因

config/initializers/devise.rb

config.mailer_sender = ENV['SMTP_MAIL_ADRESS']

開発環境・本番環境でメールの設定が別々だからとか、そんな理由で適当に環境変数を設定した。
(まぁ、Deviseの設定ファイルについてもちゃんとした理解をしていなかったし、そんな設定をしたことも忘れていた)
で、ローカルでは環境変数をセットしていたが、CI環境や本番環境では環境変数がセットされておらず、ENV['SMTP_MAIL_ADRESS']nilを返してしまい、Rails内でnilが渡されていた。

勘違い

最初は、Deviseの初期設定だと思っておらず、Mailgunの設定やRailsのmailerの基本設定を疑っていた。

app/mailers/application_mailer.rb

class ApplicationMailer < ActionMailer::Base
  default from: 'foo@bar.com'
  layout 'mailer'
end

対策

環境変数を使ってもいいと思うが使ったとしても、環境変数というキーがなかったエラーを起こしてあげれば、どこが問題でエラーが起きているのか浅いところでわかるので、問題の切り分けがわかりやすくなったように思う。

ENV.fetch('SMTP_MAIL_ADRESS')

上記のような感じで、fetchメソッドを使ったりしたらいいように思う。

【余談】開発環境で環境変数が更新されないバグ?

バグを解決する際に、本番環境でしかエラーが起きずMailgun絡みの問題だと思っていた。
(このとき、CIで同じエラーが起きることに気づいていなかった)
とりあえず、開発環境でエラーを起こした方が楽そうなので、開発環境でもMailgunを使ってみることにした。
その際に、dotenv-railsというgemを使って、.envファイルに環境変数を書き込んでいたが、Railsを立ち上げ直しても環境変数が更新されないことがあった。

これについては、spring stopコマンドを打つと、環境変数が更新された。
Railsで持っているcredentialsの機能を使った方がいいかもしれない。

【参考】 Qiita: Railsで環境変数の変更が反映されないときはspring stopを試す

最後に

とりえあえず解決してよかった。

藤本タツキ『ルックバック』を読んで

ルックバックの雑感

ちょうど2年前、京アニの放火事件があった7月18日が終わる24時に公開された読み切り。
ファイアパンチ』『チェンソーマン』の藤本タツキ先生の読み切り。

shonenjumpplus.com

何度も読んだり、他の人の呟きなども目にして、咀嚼したので感想として残してみる。

みんな絶賛しているけれど、正直1読目はよくわからなかった

読み急いでしまったこともあり、 あまりにも鮮やかなに「京本が部屋からでなかった話」がシームレスにインサートされ、 正直どういう風に話を受け止めればいいのかよくわからなかった。
なんかこの殺人事件の男の「元々オレのをパクったんだろ!?」の発言、既視感があるような……?
この「京本が部屋からでなかった話」は何なのか。

2読目をしてガクンと味わった衝撃

2読目で、この殺人事件は京アニの放火事件なのだ、と気がつく。
昨日は「京アニの放火事件から2年目なのか」と知ってたのに、鈍くさい自分。 ここで、何もかも紐解かれていく。 これは、まさしく藤本タツキ先生なりの京アニへの追悼なのだと。

Don't look back in anger

最初のコマの黒板の右上に書かれた「Don't」 最後のコマの左下の表紙に書かれた「In Anger」 そして、タイトルの「Look Back」

これらを繋ぎ合わせた一文は「Don't look back in anger」で、
翻訳すれば「怒りで振り返るな」「後ろ向きに過去を見るな」といった具合でしょうか。

これは、藤本タツキ先生の考え方であり、メッセージなのだ。 - 振り返ってもいい。でも、前向きに。 - 怒ってもいい。でも、未来へ進むために。

怒りで漫画にぶつける藤本タツキ先生

2017年のファイアパンチ5巻発売記念のインタビューで「怒りを漫画にぶつけている」と言ってた藤本タツキ先生。

藤本タツキ×沙村広明奇跡の対談

僕は読み切りを描く時は大体怒りで…。例えば、今ネット上で怒っている人が多いじゃないですか。そういう人たちって、Twitterとかで発散できていると思うんですけど、僕は自分の怒りなどをTwitterとかに書く気が知れなくて。漫画にぶつけているんですね。

事件が起きたのは2019年で今は2021年だけれど、この読み切りを書いたときもやっぱり怒っていたのかもしれない。
京アニで働くクリエイターとしての同士が理不尽な理由で命を奪われたことに怒っていたのかもしれない。
もしかしたら、京アニで働いていた友人の命を奪われたことに怒っていたのかもしれない。
それを漫画という形で昇華させた藤本タツキ先生。

タイトルのルックバックって

Weblio英和辞書: look backの意味・使い方・読み方

振り返って見る、(…を)回顧する、追憶する、しりごみする、うまくいかなくなる、後退する

(1) 振り返って見る.
(2) 〔…を〕回顧する, 追憶する 〔on, upon, to, at〕《★受身可》.
He looked back fondly on his school days. 彼は学生時代を懐かしく追憶した.
(3) [しばしば never, not を伴って] しりごみする; うまくいかなくなる, 後退する.
You must not look back at this stage. ここまできて後に引いてはいけない.

いい意味もあれば、悪い意味もある。 京アニへの「追悼」であり「回顧」だけれども、だからといって「後退」してもいけない。 そして、backには背中という意味もあり、物語で「背中」は重要なキーアイテムとなっている。

  • 自分より上手い絵を書く京本の背中を追う藤野
  • 京本の服の背中にサインしてあげる藤野
  • 「京本も私の背中を見て成長するんだなー」と鼓舞する藤野
  • 京本の描いた「背中を見て」という4コマ漫画を見る藤野
  • 京本に書いた背中のサインを見る藤野

京本も藤野の漫画が好きで尊敬して、背中を見ていたかもしれない。
しかし、同時に、藤野もまた京本の圧倒的な努力と画力を知り、京本の背中を見ていたといえる。
美術の大学でも頑張っていた親友の京本の努力を知っているからこそ、藤野は悔しく悲しかっただろうし、
一方でそんな京本から尊敬されてたからこそ藤野は立ち直って「天国でも私の背中を見てろよ」と背中で語っているようだった。

参考

24時頃に公開された模様

【Ruby】gem / bundle, それぞれのコマンドの違い

最初に

gemコマンド、bundleコマンドの違いを説明できるように覚書き。
いつも何となく使っていたが、本質的な違いは、グローバルなのか、ローカルなのかだと思う。

Bundler

gemの名前がBundlerないしbundler(名詞)で、コマンド名がbundle(動詞)。
意味合い的に、品詞を使い分けている模様。

2.5.9までは完全に外部のgemだったが、2.6.0からはDefault GemとしてRuby本体に取り込まれたらしい。
昔はgem install bundlerでbundlerを取り込まなければならなかったが、今はRubyをインストールすればついてくるので楽。

GitHubではrubygems/rubygemsで管理されている模様。
あと、昔はRubyコア外で管理されていたせいか、Bundler専用のドキュメントページbundler.ioがある。

プロジェクトでの管理以外に、gemを作るときの雛形を作るコマンドも提供している。

gemコマンドとbundleコマンドの違い

  • gemコマンドでは、Rubyのバージョン毎にgemが結びつくので、プロジェクトごとに管理できない。
  • Bundlerは、RubyのプロジェクトにGemfileを置いて、プロジェクトごとにgemを管理できる。
    Gemfile&Gemfile.lockを共有することで、プロジェクト参加者が使うgemのバージョンを共有できる。

色々違いがあるとは思うのですが、プロジェクトで使いたいものか、プロジェクトに限らずどこでも使いたいかになると思う。 プロジェクトで使う = 特定ディレクトリ配下に適用 = ローカルで使う。

npmコマンドとの関係性

npmのグローバルインストールがgemコマンドで、npmのローカルインストールがbundleコマンドに相当している、といえる。

npmのpackage.json, package-lock.jsonが、BundlerのGemfile, Gemfile.lockである。

参考

Rails 6 + Vue.js 3の初期設定

最初に

まだ巷で「Rails Vue」で検索すると、Vue.js 3ではなく、Vue.js 2系の話がでてきてしまう。

そんなわけで、Vue.js 3のインストール方法を簡単にメモしておく。

参考

Qiita: Vue.js チュートリアル for Rails エンジニア(Vue3 version)
この記事を基本的には参考にした。

Railsアプリを作る

$ ruby -v
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin20]

$ rails -v
Rails 6.1.4

Ruby 3.0.0p0 と Rails 6.1.4 の組み合わせで詰まっている方を見たので、
Rubyのパッチバージョンは上げてた方がよさそう。

$ rails new vue3_sample -d postgresql
Railsの初期化

自分はPostgreSQLを使うので、rails newするときに-d postgresqlを指定した。
PostgreSQLを設定してなくてVue.js 3.0を試したいだけの方は、このオプションは外した方がよいだろう。

ここでrails newする際に注意が必要。
巷には--webpack=vueをつける話があるが、これはVue.js 2をインストールしてしまう。
少なくとも、今のRailsは、そうであった。 これはこれで参考になると思うが、Vue.js 3をインストールする際は別なので注意。

Rails

初期化

$ rails db:create
DBを作成する。SQLite3だと不要だったと思うが、PostgreSQLなどでは必要なはず。

$ rails s
ここまで出来たら、rails sでRailsが立ち上がるのを確かめる。
ここまではVue.js関係ないので、詰まったら他のところを見るのがよさそう。

ビューを作成

ルーティング、コントローラ、ビューを作る。
なんでもよいが、適当にBooksビューを作る。

config/routes.rb

Rails.application.routes.draw do
  root "books#index"
end

app/controllers/books_controller.rb

class BooksController < ApplicationController
  # def index
  # end
end

app/views/books/index.html.erb

<h1>Books#index</h1>
<div id="js-hello-vue"></div>

ここのid="js-hello-vue"がJSファイルを載せる起点となる。 ここめがけて、Vueを載せるイメージ。
js始まりのidなのは、そういう慣行である。

Vueインストール

ここから、ちゃんとVue.js

$ yarn -v
1.22.10

$ yarn add vue@next vue-loader@next @vue/compiler-sfc

巷では$ rails webpacker:install:vueでインストールする方法が説明されることがあるが、これはVue.js 2.0系の話なので気をつけよう。 Railsコマンドでは、Vue.jsのインストールに対応してないと捉えると良さそう。 対応する予定があるのか等は調べていない。

ちゃんと、コマンドが実行されていれば、package.jsonの中身で"vue"のバージョンが3以上になっているはず。 指定する際は@nextをつけると、Vue.js 3系が入る模様。

だいぶ省略していますが、package.jsonは以下のようになります。

{
  "dependencies": {
    "@vue/compiler-sfc": "^3.1.4",
    "vue": "^3.1.4",
    "vue-loader": "^16.2.0",
  }
}

config/webpack/environment.jsファイルを以下のように書き換える。

const { environment } = require('@rails/webpacker')

const { VueLoaderPlugin } = require('vue-loader')
 environment.plugins.prepend(
     'VueLoaderPlugin',
     new VueLoaderPlugin()
)

environment.loaders.prepend('vue', {
    test: /\.vue$/,
    use: [{
        loader: 'vue-loader'
    }]
})

module.exports = environment

また、config/webpacker.ymlextensions:.vueを追加する。

  extensions:
    - .vue
    - .mjs
    - .js
    - 

ここまでで、Vue.js 3を使う環境は整った。

Vue.js 3を使う

app/javascript/application.jsに下記の行を追加する。

require('./hello_vue.js')

そして、同ディレクトapp/javascriptに、今回は以下のファイルを作っていく。

  • app/javascript/hello_vue.js
  • app/javascript/hello.vue

hello_vue.jsapplication.jsから呼ばれ、hello.vuehello_vue.jsから呼ばれる。

app/javascript/hello_vue.js

import { createApp } from 'vue'
import App from './hello.vue'

document.addEventListener('DOMContentLoaded', () => {
  const selector = '#js-hello-vue';
  if(document.querySelector(selector)){
    createApp(App).mount(selector);
  }
})

const selector = '#js-hello-vue';は、文字列を入れている。Vueに置き換えたいHTMLのIDの文字列だ。
if文でこのIDがあるかどうか確かめて、このIDのタグがあればVueをマウントする。

マウントするVueは何かというと、import App from './hello.vue'の部分。

app/javascript/hello.vue

<template>
  <div>
  {{ hello }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      hello: "Hello, Vue.js 3.0"
    }
  }
}
</script>

<style scoped>
</style>

スクリプトの部分で、Vue.jsの雛形を作っている感じ。 ここから、さっきのimport App from './hello.vue'Appとして渡される。

これでVue.js 3.0が使えているはず。

最後に

未来の自分向けに書いたわけですが、未来の自分は参考になりましたか?

macでherokuに初回pushするときに起こるエラー、herokuのプラットフォームを指定する

最初に

Linux以外でherokuにRailsアプリをpushすると、おそらく起こるエラーがある。
それについて、説明していく。
(もしかしたら、nokogiri等を使ってないとエラーにならないかも)

実際のエラー

$ git push heroku main
(中略)
remote: -----> Ruby app detected
remote: -----> Installing bundler 2.2.21
remote: -----> Removing BUNDLED WITH version in the Gemfile.lock
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-3.0.2
remote: -----> Installing dependencies using bundler 2.2.21
remote:        Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4
remote:        Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.
remote:        Bundler Output: Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.
remote: 
remote:  !
remote:  !     Failed to install gems via Bundler.
remote:  !

エラーでない部分

まず、本題から逸れて、エラーでない部分について説明する。

remote: -----> Ruby app detected
remote: -----> Installing bundler 2.2.21
remote: -----> Removing BUNDLED WITH version in the Gemfile.lock
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-3.0.2
remote: -----> Installing dependencies using bundler 2.2.21

Rubyで作られたアプリだと検知して、bundler 2.2.21をインストールし始める。
herokuの標準環境では、bundler 2.2.21を使うようだ。
Gemfile.lockに書かれたBundlerのバージョンを削除する。
で、2.2.21 bundlerを使って、Gemfile.lockから依存gemをインストールしてる。

エラーが起こる部分

依存gemをインストールする際にエラーになる。
微妙なところで改行されてて読みにくいので、わかりやすい文単位で改行する。

Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform is x86_64-linux. 
Add the current platform to the lockfile with `bundle lock --add-platform x86_64-linux` and try again.

このエラーを説明する。 "x86_64-darwin-20"ってのがmacOSの1つで、x86_64-linuxが書かれているようにLinux。 (Gemfile.lockからわかることで)bundlerによる依存関係の前提としては["x86_64-darwin-20"]しかサポートしてないけど、Heroku環境(local platform)がLinuxだからx86_64-linuxも使われることをGemfile.lockに指定しろという話の模様。
nokogiriとかは、環境によってちょっと異なるバージョンが入るらしい。環境ごとにバージョンがあるという感じだろうか。 bundle lock --add-platform x86_64-linuxというコマンドを使えばいいことを教えてくれてるので、それをそのまま実行する。 そうすると、Gemfile.lockに使われる環境(プラットフォーム)の情報にx86_64-linuxが追加される。 追加されることで、bundle installする際に、Linux用(x86_64-linux)のnokogiri gemが入るようになる。 これで、改めて、git push heroku mainとすると、このエラーは消えて、他にエラーがなければデプロイできる。

最後に

ちょっと慣れてないと、色々表示されて読みにくい気がするが、紐解ければ単純。