Anonymous controllerは独自のroutesを使用する

まず、RSpec3でのAnonymous controller変更点について触れる。
従来Anonymous controllerはBaseClassを指定しない状態で定義すると必ずApplicationControllerのSubClassとして定義されていた。
RSpec3以降指定しない状態だとdescribe_classをBaseClassとして用いるようになった。

describe HogesController do
  controller do
  end
end

この場合controllerはHogesControllerのSubClassとして定義される。
設定によってこの挙動を従来の挙動に戻すことも可能。詳しくは下記参照。
rspec-rails/anonymous_controller.feature at master · rspec/rspec-rails · GitHub

で、何があったかというとroutes.rbの設定でhogesのroutingを少々変更していた。

resources :hoges, param: :homu

単一のリソースに対しての処理を行う際通常:idをパラメータとして受け取り処理するが:homuに変更していた。
実際に遭遇していたのがupdateなのでupdateで書くと生成されるroutingは下記。

  • PATCH /hoges/:homu

RSpecでリクエストをする時はこんなように書けば良い。

patch :update, homu: 1

でこの部分のテストにAnonymous controllerを使ったテストを書いた。

describe HogesController do
  controller do
    def update
      # なんか処理!
    end
  end

  describe 'PATCH#update' do
    before do
      patch :update, homu: 1
    end
    it { expect(response.status).to eq(200) }
  end
end

なんかリクエスト成功した!みたいな比較的どうでもいいことをしたかったのだが、これがno route matchになって混乱した。

{controller: :hoges, action: :update, homu: 1}

ってなってるし正しそうだけどno route match。

アプリ側の動作は問題ないのでRSpec側のみ起きてることは分かった。
homuをidに変えてみるとリクエストすることができたのでroutesの変更が効いてない?
homuに戻してAnonymous controllerの記述を消してみるとリクエストに成功した。

Anonymous controllerがroutes.rbの変更による影響を受けないroutesを使用しているという推測を立ててそれっぽい話題を探す。

To clarify the application routes are available to the controller when it runs. It is the custom anonymous controller routes which are not.

Anonymous controller can't access application routes · Issue #1321 · rspec/rspec-rails · GitHub

application routesというのがアプリ側のroutingのことだと思うがanonymous controllerはそうではないと言っている(と思うんだけど英語わかんねえこれ

動作がそうなっていてそれっぽい情報も得たけど気持ち悪いのであとでもう少し調べる。