とりあえずコード書けよ

技術的なことの備忘録。

Dry::AutoInjectでinitializeをオーバーライドした時にArgumentError: wrong number of arguments (given 1, expected 0)になる

結論

  • Dry::AutoInjectでincludeしているクラスにネストしたクラスが別ファイルで存在しているとダメだった
  • とりあえずネストしたクラスの構成を変える or includeしているクラスの中にクラスを書く

状況

  • クラスFooServiceでDry::AutoInjectを使って、ContainerからDIをしている
  • クラスFooServiceのinitializeをオーバーライドして、DI以外の処理を挿入していた
  • クラスFooServiceにネストしたクラスを別で定義している(コードの良し悪しは置いといて下記のようなイメージ)
# foo_service.rb
class FooService
  Import = Dry::AutoInject(MyContainer)
  include Import[hoge_repository: 'repositories.hoge']

  def initialize(hoge:, **args)
     super(**args)

     @hoge = hoge
     ...
  end

  def call
     bar = Bar.new
     bar.fuga
     ...
  end
end

# foo_service/bar.rb
class FooService
  class Bar
     def fuga
       # FooServiceで使うなんかの処理とか
     end
  end
end

症状

この状態で次のようにinitializeが実行されるとでエラーが発生する

# foo_service_test.rb
class FooServiceTest < ActiveSupport::TestCase
  test 'なんかのテスト' do
    hoge = "hoge"
    hoge_repository_mock = Minitest::Mock.new
    service = FooService.new(hoge: hoge, hoge_repository: hoge_repository_mock)
  end
end
...
# 実行結果
ArgumentError: wrong number of arguments (given 1, expected 0)
    /Users/xxxxxx/.rbenv/versions/**/lib/ruby/gems/**/gems/dry-auto_inject-1.0.0/lib/dry/auto_inject/strategies/kwargs.rb:45:in `block (2 levels) in define_initialize_with_keywords'
    /Users/xxxxxx/**/foo_service.rb:*:in `initialize'
    /Users/xxxxxx/.rbenv/versions/**/lib/ruby/gems/**/gems/dry-auto_inject-1.0.0/lib/dry/auto_inject/strategies/kwargs.rb:19:in `new'
    /Users/xxxxxx/.rbenv/versions/**/lib/ruby/gems/**/gems/dry-auto_inject-1.0.0/lib/dry/auto_inject/strategies/kwargs.rb:19:in `block (2 levels) in define_new'
    /Users/xxxxxx/**/foo_service_test.rb:**:in `block in <class:FooServiceTest>'

オーバーライドしてもsuper()に、DIする引数を渡せばオーバーライドできるはずなのに、super()で引数を受け付けていないという状態になる

対策

  1. クラスの構成を変える
# foo_service/bar.rb
class Bar
   def fuga
     # FooServiceで使うなんかの処理とか
   end
end
  1. ネスト元のクラスに定義する
# foo_service.rb
class FooService
  Import = Dry::AutoInject(MyContainer)
  include Import[hoge_repository: 'repositories.hoge']  
  
  def initialize(hoge:, **args)
     super(**args)

     @hoge = hoge
     ...
  end

  class Bar
     def fuga
     end
  end
end

他のクラスでオーバーライドできていたのに、これに該当するクラスでなぜかinitializeのオーバーライドが効かず、めちゃくちゃ沼った。 ちゃんとコードを追った上でコントリビュートするべきなのだろうけど、時間の捻出がなかなかできず... 一旦書き置き。

tomcatの名前の由来

learning.oreilly.com

上記の本の「1. Getting Start with Tomcat」内の「Where Did Tomcat Come From ?」でTomcatの製作者の言葉が書かれている。

O'Reilly books have animals on the covers. So what animal would I want on the cover of the O'Reilly book covering the technology?
Furthermore, I wanted the animal to be something that was self-sufficient. Able to take care of itself, even if neglected, etc. Tomcat came out of that thought.

オライリー本では表紙が動物になるが、この技術を扱う本にはどんな動物が良いか?と考えた時に、自給自足で生きる動物が良い。」という理由とのこと。
こういう名前の由来とか地味に気になるタイプなんだけど、他の人はどうなんだろうか。

dockerのtomcatでスタートページとかWebアプリケーションマネージャが404になる場合

結論

webapps.distをwebappsにリネーム

$ mv webapps webapps2
$ mv webapps.dist webapps

環境

  • dockerイメージ
    tomcat:9.0.70-jdk17-corretto-al2

詳細

1.コンテナを起動する

$ docker run -d -p 8080:8080 --name tomcat9 tomcat:9.0.70-jdk17-corretto-al2
Unable to find image 'tomcat:9.0.70-jdk17-corretto-al2' locally
9.0.70-jdk17-corretto-al2: Pulling from library/tomcat
5b4a36b5b78f: Already exists 
583e089287ff: Already exists 
d30e8da53c91: Already exists 
bd78d75dc197: Already exists 
07116e0d2eba: Already exists 
Digest: sha256:c94a52613fb41b81226468bf90226d1b8d9d8e4587daa3db50f49c4bc70c314c
Status: Downloaded newer image for tomcat:9.0.70-jdk17-corretto-al2
68674e39a2244bc1ad5294e92277c7e756c430cbdaac8c54b43d6f1542250c46

2.コンテナの確認

$ docker ps
CONTAINER ID   IMAGE                              COMMAND                  CREATED          STATUS          PORTS                    NAMES
68674e39a224   tomcat:9.0.70-jdk17-corretto-al2   "catalina.sh run"        7 seconds ago    Up 6 seconds    0.0.0.0:8080->8080/tcp                 tomcat9

3.localhost:8080にアクセスすると404になる

tomcat 404

原因は、いちいちRUNで中身消すなりするの面倒だよねという話でスタートページなどの配置が変更されているためな模様 github.com

実際にlsで中身を見てみると下記のような構成になっている。

$ docker exec -it tomcat9 /bin/bash
$ pwd
/usr/local/tomcat
$ ls
BUILDING.txt  CONTRIBUTING.md  LICENSE  NOTICE  README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work

webapps.distがデフォルトのスタートページなどが入っている。

$ ls webapps.dist
ROOT  docs  examples  host-manager  manager

なので、webapps.distをリネームしてやると良い 4.リネームする

$ mv webapps webapps2
$ mv webapps.dist webapps

5.conf/tomcat-users.xmlのログイン情報を設定する ◯変更前

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
<!--
  By default, no user is included in the "manager-gui" role required
  to operate the "/manager/html" web application.  If you wish to use this app,
  you must define such a user - the username and password are arbitrary.

  Built-in Tomcat manager roles:
    - manager-gui    - allows access to the HTML GUI and the status pages
    - manager-script - allows access to the HTTP API and the status pages
    - manager-jmx    - allows access to the JMX proxy and the status pages
    - manager-status - allows access to the status pages only

  The users below are wrapped in a comment and are therefore ignored. If you
  wish to configure one or more of these users for use with the manager web
  application, do not forget to remove the <!.. ..> that surrounds them. You
  will also need to set the passwords to something appropriate.
-->
<!--
  <user username="admin" password="<must-be-changed>" roles="manager-gui"/>
  <user username="robot" password="<must-be-changed>" roles="manager-script"/>
-->
<!--
  The sample user and role entries below are intended for use with the
  examples web application. They are wrapped in a comment and thus are ignored
  when reading this file. If you wish to configure these users for use with the
  examples web application, do not forget to remove the <!.. ..> that surrounds
  them. You will also need to set the passwords to something appropriate.
-->
<!--
  <role rolename="tomcat"/>
  <role rolename="role1"/>
  <user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
  <user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
  <user username="role1" password="<must-be-changed>" roles="role1"/>
-->
</tomcat-users>

◯変更後

<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
  <user username="admin" password="###適当に変更###" roles="manager-gui"/>
</tomcat-users>

6.webapps/manager/META-INF/context.xmlでアクセス制限の修正をする ◯変更前

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<Context antiResourceLocking="false" privileged="true" >
  <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"
                   sameSiteCookies="strict" />
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
  <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>

◯変更後

<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="false" privileged="true" >
  <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"
                   sameSiteCookies="strict" />
<!--
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->
  <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>

所感

やはりだいたい公式に答えは書いてある

macのsedで"extra characters after \ at the end of a command"やら"command i expects \ followed by text"で出る時の対応

結論
内容

シェルスクリプトで先頭の行に文字列の挿入をしたかったが、下記のエラーが出てしまう。

$ sed -i '' '1i\\\encoding UTF-8' sample.sql
sed: 1: "1i\\\encoding UTF-8": extra characters after \ at the end of i command

調べていくとMacsedコマンドはBSD版で、GNU版と仕様が異なる部分がいくつかあるという話らしい。

it-ojisan.tokyo

対処法

GNUsedをhomebrewでインストールする

$ brew install gnu-sed

特に何もしなければgnu-sedを使うコマンドはgsedとなるが、使い勝手がイマイチ。
homebrewでのインストール完了後にも表記が出るが、下記のPATHを通すとsedコマンドを置換できる。

GNU "sed" has been installed as "gsed".
If you need to use it as "sed", you can add a "gnubin" directory
to your PATH from your bashrc like:

    PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
==> Summary
🍺  /usr/local/Cellar/gnu-sed/4.9: 12 files, 628.6KB
==> Running `brew cleanup gnu-sed`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
まとめ

仕様違いとは知らず、時間を無駄に...
先人に感謝。

Minitest::Mock#expectで ArgumentError: mocked method :method_name expects 1 arguments, got [] が出た件

結論

  • minitest5.16.0からキーワード引数の指定方法が変わった
  • 第三引数以降にkey, valueのキーワード引数を書いたらOK

概要

minitestで下記のエラーが出るようになった

ArgumentError: mocked method :method_name expects 1 arguments, got []

理由

元々、minitestにキーワード引数を渡すときは、第三引数にキーワード引数を渡していた。 ※コードは適当 github.com

tax_mock = Minitest::Mock.new
tax_mock.expect(:tax, 8, [{ price: 100, tax_rate: 0.08 }])

が、5.16.0からkwargsに対応している。 github.com github.com

なので、5.16.0以降は、キーワード引数の場合、下記のように記述することになる。

tax_mock = Minitest::Mock.new
tax_mock.expect(:tax, 8, price: 100, tax_rate: 0.08)

RailsでFATAL: Ident authentication failed for user "hoge"が出る

結論

pg_hba.confを変更する必要がある

手順

  1. psqlを起動
  2. show hba_file;を実行
  3. sudo vi /var/lib/pgsql/12/data/pg_hba.conf
  4. IPv4 local connections の部分をidentからtrustに変更
  5. postgresqlを再起動

変更箇所について

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust #identからtrustに
# IPv6 local connections:
host    all             all             ::1/128                 ident
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     peer
host    replication     all             127.0.0.1/32            ident
host    replication     all             ::1/128                 ident

設定内容については公式の下記参照

www.postgresql.jp

RailsTCP SocketでPostgresqlにアクセスするため、hostを変更すること

EC2にswap領域を作る

サーバーのメモリが貧弱だと、webpackのコンパイルとかが厳しい。
この場合、スワップ領域を割り当ててメモリ領域の拡張などの対応をする必要がある。 以下、EC2に反映する際の備忘録

とはいえ、基本これに書いてある通りにやるだけ aws.amazon.com

手順

1 スワップファイルの作成

$sudo dd if=/dev/zero of=/swapfile bs=128M count=32

# レスポンス
xx+0 レコード入力
xx+0 レコード出力
xxxxxxxx バイト (xx GB) コピーされました、 xxx 秒、xxx MB/秒

※xは任意の値が入る

2 アクセス許可

$sudo chmod 600 /swapfile

3 Linux スワップ領域のセットアップ

$sudo mkswap /swapfile

# レスポンス
スワップ空間バージョン 1 を設定します。サイズ = x GiB (xxxxxxxxxxx バイト)
ラベルはありません, UUID=xxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

4 スワップ領域の割り当て

$sudo swapon /swapfile

5 割り当ての確認

$sudo swapon -s

ファイル名             タイプ       サイズ   使用済み    優先順位
/swapfile                               file        xxxxxxxxx   0   -2

6 起動時の有効化

$sudo vi /etc/fstab

# 末尾に追加して保存
/swapfile swap swap defaults 0 0

Swapの推奨サイズ

access.redhat.com

Swapの削除

1.swapの確認

cat /proc/swaps

Filename                Type        Size    Used    Priority
/swapfile                               file        2097148 55880   -2

2.swapの無効化

sudo swapoff /swapfile

cat /proc/swaps
Filename                Type        Size    Used    Priority

3.swapfileの削除

sudo rm /swapfile