コガミツlog

福岡在住エンジニアのブログ

ActiveSupportのinquiryに初めて触れた

ActiveSupportのinquiryに初めて触れた

質問を受けたのですが知らなくて自分でも調べてみたやつ。

ActiveSupportのinquiryという機能

Railsガイドにも載っていて 以下のような記載があります。

inquiryは、文字列をStringInquirerオブジェクトに変換します。このオブジェクトを使うと、等しいかどうかをよりスマートにチェックできます。

https://railsguides.jp/active_support_core_extensions.html#inquiry

"production".inquiry.production? # => true
"active".inquiry.inactive?       # => false

となります。

手元で動かすと、説明通りStringInquirer のオブジェクトでした。

"foo".inquiry.class
# => ActiveSupport::StringInquirer

ちなみに定義まで見ていきます。

https://github.com/rails/rails/blob/7-1-stable/activesupport/lib/active_support/core_ext/string/inquiry.rb

def inquiry
  ActiveSupport::StringInquirer.new(self)
end

selfをwrapしているだけでした。

出来るだけ英語の意味も調べるようにしているのですが、inquiryは尋ねること・問い合わせ という意味みたいです。

ちなみにRuboCop

https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsinquiry

リンク先見てもらえラバわかりますが、inquiry メソッドを使用していないことを強制するルールもあります。

ActiveSupportの機能で使ったことないやつ結構あるみたいなので今度時間取って触ろうかな。

prepend_before_action を連続で定義した時の実行順番

結論

複数ある場合は、下から順番にprepend_before_actionが実行される

きっかけ

controllerでbefore_actionを複数個書くと当然ファイルの上から実行されます。

prepend_before_action を複数個定義する要件がありbefore_actionと同じ感覚で実行されて欲しい順に記載したのですが、意図した順番とは逆の結果になってしまいました。

調査

少なくとも自分が調べた限り直接的なドキュメントはなかったのでソースコード読みました。

prepend_before_actionの定義は以下のソースコードです。

github.com

...途中省く

[:before, :after, :around].each do |callback|
  define_method "#{callback}_action" do |*names, &blk|
    _insert_callbacks(names, blk) do |name, options|
      set_callback(:process_action, callback, name, options)
    end
  end

  define_method "prepend_#{callback}_action" do |*names, &blk|
    _insert_callbacks(names, blk) do |name, options|
      set_callback(:process_action, callback, name, options.merge(prepend: true))
    end
  end

  define_method "skip_#{callback}_action" do |*names|
    _insert_callbacks(names) do |name, options|
      skip_callback(:process_action, callback, name, options)
    end
  end

定義のところだけ抜き出します。

define_method "prepend_#{callback}_action" do |*names, &blk|
  _insert_callbacks(names, blk) do |name, options|
    set_callback(:process_action, callback, name, options.merge(prepend: true))
  end
end

prependの時はset_callbackメソッドのオプションとして、prepend: trueを追加しているみたいです。

続いてset_callbackメソッドのドキュメントを見てみます。

api.rubyonrails.org

:prepend - If true, the callback will be prepended to the existing chain rather than appended.

の記載があります。

既にあるcallbackチェーンの後ろに追加するのではなく先頭に付ける、と書いてありました。

つまり、prepend_before_action を複数個定義すると、 ファイルの上からcallbackチェーンの先頭に追加されていくので、実行時は一番先頭である最後のprepend_before_actionが実行されるようです。

つまりこんな感じになります。

class SomeController < ApplicationController
  prepend_before_action :first_prepend
  prepend_before_action :second_prepend

  def hoge_action
    # ...
  end

  private

  def first_prepend
    puts "First"
  end

  def second_prepend
    puts "Second"
  end
end

この場合結果としては、こうなりました。

Second
First

iterm2で特定のタブだけ背景色を変える

デフォルトの色の変換に関してはsettingsから変更できると思いますが、特定のタブだけ色を変えたい場合です。

やり方

左上だけのタブだけ色を変えたい

  1. 背景色を変えたいタブ上で右クリック

  2. Edit Session.. をクリックすると

でPreferencesのウインドウが開くので背景色だったりなんでも変更できます。

こんな感じで背景色変えれる

使い所

いろいろなサーバーだったりを別のタブで開いて起動させたりしていて場合に、視認性が悪いとたまに操作ミスをしてしまう対策として使ってます。

Radix Dialog に自前コンポーネントを使うと Function components cannot be given refs. が出る

起きていた事象

詳細をちょっと書くと Radix UIを使用してDialogを実装していて、その子コンポーネントに自作コンポーネントを使用していた場合

Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

のエラーが発生していました。

関数コンポーネントにrefsを渡せないということと、React.ForwardRefを使ってエラーを回避する方法が検索でヒットします。

検索でヒットした通り修正しようかと思い色々確認していたのですが、肝心のrefを関数コンポーネントに渡している記述がありませんでした🤔

修正

色々ググっていくと最終的には、Radix UIの公式サイト見るとヒントになる記述がありました。

www.radix-ui.com

Additionally, Radix will sometimes need to attach a ref to your component (for example to measure its size). If your component doesn't accept a ref, then it will break.

  • Radixは、コンポーネントにrefを添付する必要がある。
  • コンポーネントがrefを受け付けない場合、それは壊れる。

と書いてあります。

自作の関数コンポーネントは、そもそもrefを渡していなかったので渡す様に変更して、かつReact.ForwardRef を使って修正したところエラーは消えました。

Radix UIでWarning: validateDOMNesting(...): <button> cannot appear as a descendant of <button>.

起きていた事象

Radix UI を使ってUIを作っていて、ある画面でconsoleにwarningが表示されていた。

Warning: validateDOMNesting(...): <button> cannot appear as a descendant of <button>.

言い換えると<button>タグは<button>タグの子孫タグに出来なってことです。

Reactのソースコードにはもちろんそんな記述ないのですが、Chromeで検証してみると確かに<button>タグの中に<button>タグが出来ていた。

修正

調査してみるとRadix UI のtooltipの中にbuttonを配置しているのが原因だった。 www.radix-ui.com Tooltip – Radix UI

公式docどおりですが一応コード書きます。

const TooltipDemo = () => {
  return (
    <Tooltip.Provider>
      <Tooltip.Root>
        <Tooltip.Trigger>
          <button>
            hoge
          </button>
        </Tooltip.Trigger>
      </Tooltip.Root>
    </Tooltip.Provider>
  );
};

↑こんな感じに書いていたのだがTooltip.Triggerが内部的に<button>を使っている様で結果的に<button>タグの中に<button>タグとなってしまっていた。

回避するには、TriggerにasChildを付与する。

<Tooltip.Trigger asChild>
  <button>
    hoge
  </button>
</Tooltip.Trigger>

https://www.radix-ui.com/primitives/docs/components/tooltip#trigger リンク先に書いている通り、propsとしてasChildを渡せる。

asChildの詳細についてはこちら。

www.radix-ui.com