開発中のプロジェクトでrails6 -> rails7にした

基本は

https://railsguides.jp/upgrading_ruby_on_rails.html

の手順を守ればOKですがdocker 環境のせいかbundle updateが一晩かけても終わらなかったので、Gemfile.lockを削除してGemfilerailsのバージョンを書き換えてbundle installしました。

変更点はこれだけです。

gem 'rails', '~> 6.1.4', '>= 6.1.4.1'
gem 'rails', '~> 7.0.2', '>= 7.0.2.2'

gem 'rails-i18n', '~> 6.0.0'
gem 'rails-i18n', '~> 7.0.0'

webpackerはとりあえず使い続ける選択をしたので大きな問題はありませんでした。

ただ、rspecでsessionをmockしているところが動かなくなってました

allow_any_instance_of(ActionDispatch::Request)
  .to receive(:session)
  .and_return({id: 1})

理由はちゃんとわかってないですが、下記のようなヘルパーを作って対処しました

  def initialize_mock_session
    mock_session = allow_any_instance_of(ActionDispatch::Request::Session)
    # おまじない。↓のエラーの対策
    # Please stub a default value first if message might be received with other args as well.
    mock_session.to receive(:[]).and_call_original
    mock_session
  end

# 利用方法
mock_session.to receive(:[]).with(:id).and_return(1)

Docker Desktopへのメモリの割り当てが少なかったせいか起動で失敗

環境:m1 mac

failed to solve: rpc error: code = Unknown desc = executor failed running

こんなエラーが出てapk adddocker-php-ext-installあたりのコマンドで落ちてたんですが、毎回必ず同じ場所で落ちるわけじゃなかったので、もしやと思ったらメモリの割り当てを8GBにしたらdocker compose upが最後まで通るようになりました。

m1 macを使ってると、インストールしようとしているパッケージが対応してないんじゃないかと疑いたくなりますが、今回は違いました。

rails seedを冪等性にする。sanitizeがデフォルトで許可しているタグ

rails 6.1 ruby 3.0

seedを冪等性にする

docker compose upなどでbin/rails db:seedを実行する環境などで何度実行されても同じ結果にしたいと思いました。

ActiveRecord::Base.connection.disable_referential_integrity do
  ActiveRecord::Base.connection.execute("TRUNCATE users")
  User.create(name: "user1")
end

TRUNCATEでidも元に戻るので、create時に指定しなくても大丈夫です。

プロジェクトのみんなからはそんなに好意的な意見は聞かれなかったので、とりあえずではあります。

docker起動時のコマンドを改善した方がいい気はする。

find_or_create_byは?

db:seedの後で、どこかのカラムを変更し、もう一度db:seedするときに、idを指定するとduplicateになり、指定しないと似たようなレコードがもう1レコードできてしまいます。

sanitizeがデフォルトで許可しているタグ

多分この辺です。ガイドにも書いてない。

github.com

htmlをそのまま表示しなければいけない時にscriptタグとかは許可したくない時に使えます。

rawよりは安全です。

BUFFALOのルータWSR-5400AX6でVPN(L2TP/IPsec)に繋がるようになった

昔に買ったWZR-450HP(発売時期: 2012年6月)は繋がったんですが、逆に新しい方がつながりませんでした。

結果としては、二つの設定を見比べると古い方はPPPoEでインターネットに接続していて、 新しい方はそうじゃないようでした。 じゃあ何で繋がってたかはよくわかってないです。IPoEですかね?

色々試した結果それがわかったので、新しい方のルータでも無理やりPPPoEで繋いで見たところ つながりました。

これがその設定です。 f:id:ta_watanabe:20220119074643p:plain

最初は「インターネット@スタートを行う」にチェックが入ってるんですが、それを上記のように変えました。

古いルータでは「PPPoEクライアント機能を使用する」の項目はありますが、「インターネット@スタートを行う」にチェックが入っていても VPNは繋がりました。

f:id:ta_watanabe:20220119075326p:plain
古いルータ

後、新しい方のルータでやったことは、ルータモードみたいなのをautoから常にONみたいなのにしました。

Android Firestore: grpc-javaのバグ

FlutterのプロジェクトでGoogle Playが入ってないエミュレータかつAndroid11で例外が発生するということをメンバーが見つけてくれました。

こんな感じのスタックトレースになってます。

W/GooglePlayServicesUtil( 3931): com.example.debug requires the Google Play Store, but it is missing.
E/GooglePlayServicesUtil( 3931): GooglePlayServices not available due to error 9
W/Firestore( 3931): (23.0.3) [GrpcCallProvider]: Failed to update ssl context: com.google.android.gms.common.GooglePlayServicesNotAvailableException
I/.learning.debu( 3931): NativeAlloc concurrent copying GC freed 68025(3478KB) AllocSpace objects, 17(532KB) LOS objects, 49% free, 3278KB/6556KB, paused 2.569ms total 126.063ms
W/.learning.debu( 3931): Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B (greylist-max-q,core-platform-api, reflection, denied)
W/.learning.debu( 3931): Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->getAlpnSelectedProtocol()[B (greylist-max-q, reflection, denied)
E/AndroidRuntime( 3931): FATAL EXCEPTION: grpc-okhttp-0
E/AndroidRuntime( 3931): Process: com.example.debug, PID: 3931
E/AndroidRuntime( 3931): java.lang.AssertionError: Method getAlpnSelectedProtocol not supported for object SSL socket over Socket[address=firestore.googleapis.com/172.217.31.138,port=443,localPort=53942]
E/AndroidRuntime( 3931):    at io.grpc.okhttp.internal.OptionalMethod.invoke(OptionalMethod.java:114)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.internal.OptionalMethod.invokeWithoutCheckedException(OptionalMethod.java:135)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.OkHttpProtocolNegotiator$AndroidNegotiator.getSelectedProtocol(OkHttpProtocolNegotiator.java:183)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.OkHttpProtocolNegotiator$AndroidNegotiator.negotiate(OkHttpProtocolNegotiator.java:145)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.OkHttpTlsUpgrader.upgrade(OkHttpTlsUpgrader.java:63)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.OkHttpClientTransport$4.run(OkHttpClientTransport.java:571)
E/AndroidRuntime( 3931):    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
E/AndroidRuntime( 3931):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime( 3931):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime( 3931):    at java.lang.Thread.run(Thread.java:923)
I/Process ( 3931): Sending signal. PID: 3931 SIG: 9
Lost connection to device.
Exited (sigterm)

playの入ってないエミュレータでもAndroid10なら例外は発生しませんでした。

リリースの必須要件にplayの定期購入があるので、気にしなくても大丈夫だと思いますが、 念の為調べました。

getAlpnSelectedProtocolはAndroid 11 からブロック対象

https://developer.android.com/about/versions/11/non-sdk-11?hl=ja

このメソッドがio.grpc.okhttpというパッケージで呼び出されているのが主な原因のようです。

該当箇所はここですね
https://github.com/grpc/grpc-java/blob/v1.28.x/okhttp/src/main/java/io/grpc/okhttp/OkHttpProtocolNegotiator.java#L183

ただ、playが入っているAndroid11でも例外が発生してもよさそう。

ログに出ているGrpcCallProviderとは

どうやらこの辺りの処理のようです。
firebase-android-sdk/GrpcCallProvider.java at ac3276ce7d5f5181b1c419731495eb88a98537af · firebase/firebase-android-sdk · GitHub

ここで呼び出されているinstallIfNeededというメソッドは下記で説明があります。
セキュリティ プロバイダを更新して SSL エクスプロイトから保護する  |  Android デベロッパー  |  Android Developers

ここだけ読んでも良くわかりませんが、どうやらSSLの強度を上げてくれるものっぽいですね。

grpc-java側でもOkHttpTlsUpgraderというクラスがありますが、 firebase sdk側の処理が失敗した時だけ動くんだと予想できます。

その辺りの詳細は調べ切れてませんが、下記のissueを辿っていけば grpc-javaの新しいバージョンで 新しいメソッドのgetApplicationProtocolが呼ばれるような修正が入っていることがわかります。 Crash due to use of getAlpnSelectedProtocol on Android 11 · Issue #7519 · grpc/grpc-java · GitHub

これに伴って、firebase sdk側もアップデートされてますので、 それを利用するようにすればOKなはずです。

reduxの学習と気づいたこと

https://github.com/na8esin/react-redux-practice

今日の時点では、下記が終わったところ

https://redux.js.org/tutorials/essentials/part-7-rtk-query-basics

最近は、 reduxの評判もあまり良くないので、学習に一旦区切りをつけます。

また、typescriptで書かれてないので、書き換えながらやってますが下記のサイトが便利
https://react-typescript-cheatsheet.netlify.app/

noImplicitAnyにしている人は上を見ながら型指定ができます。

それとチュートリアルをやってる時に気になったことがあります。

ソースを動かすときにapiはmswを使うんですが、それを呼び出すときのコードがこんな感じです。 https://github.com/reduxjs/redux-essentials-example-app/blob/master/src/api/client.js

このソースのコメントで下記のリンクが載っています。
Replace axios with a simple custom fetch wrapper

これを読むとaxiosもなるべく使わない方向で行こうかなという気持ちになりました。