Swift: Class 外から Inner class な enum value にアクセスしたい時
ClassName.EnumType.EnumValue
みたいに EnumType を経由した識別子でアクセスできる
import Foundation class A { enum Color { case Red case Blue } } let color = A.Color.Red // ダメ //let color3 = .Red // Color 型であることがわかる時はコンパイラが名前空間を考慮してくれる switch color { case .Red: print("red") case .Blue: print("blue") // => "blue\n" }
(要約記事) Varnish と Microservices: Zipnish の紹介
元記事: Varnish and Microservices: Introducing zipnish
[update] スライドへのリンクが変わっていたので更新: https://www.slideshare.net/Varnish_software/microservices-20-61197134
Amedia が Microservices パターンを適用した時の事例を元に Zipnish というソフトウェアの紹介記事
元記事には無い前提情報
Microservices アーキテクチャを apply する時に Varnish を活用する手法があるようだ。
今まではそれぞれのサービス間はそれぞれ通信するので、接続先のサービスを探す "Service Discovery" の問題を解決しなければいけなかった。具体的には、各サービスのインスタンス情報の格納のために Service Direcotry (元記事では Service Catalog と呼んでいる)の運用、サービスのインスタンス情報の更新(health check も含む)など。
(画像は http://www.slideshare.net/Varnish_software/microservices-20-55572848 から引用)
Varnish を中央に設置して、サービス間の通信は全て中央の Varnish を通り、Serivce Discovery やキャッシングは Varnish に任せる手法。
参考リンク: http://www.slideshare.net/Varnish_software/microservices-20-55572848
(Microservices Varnish の手法の)良かったこと
- Service Discovery の問題を Varnish で解決できる
- サービスの接続先の管理や取得を Varnish がやるので他の仕組みを用意しなくて良い。
- Service Direcotry を用意しなくて良い (Zookeeper や etcd を使った仕組み)。
- それぞれのサービスをステートレスにしたことで中央で一括でキャッシュできた。
- 中央で一括してキャッシングしてるので cache invalidation が簡単。それぞれのサービスがキャッシュレイヤーを持っている場合だと、キャッシュが散らばってるしレイヤーも複数あったりするので cache invalidation が難しい。
(2) については「どうやってステートレスにするんだ」という疑問があってよくわからない....
Zipnish の紹介
- Zipkin が解決しようとしている Microservices の monitoring 問題がある。例えば、依存サービスのモニタリング、どのサービスに問題があるのか、どのリクエストが遅いのか、などを可視化したい。
- Zipkin は JVM 前提で使いづらい。heavy。
- Microservices Varnish の手法では中央の Varnish を必ず通るのでそこで Zipkin がするようなロギングを行うアイディア
- Varnish Cache 4.0 から導入された logging API を使うっぽい(?)
- 今はビュー周りは Zipkin を再利用している。Python で書かれたものに置き換える予定。
Rails request spec の header name の変遷
たまに request spec とかで「HTTP_
いるっけ?」となった時に思い出したいので自分宛てメモ
before Rails 4.0.0
get '/path', params, { 'X-Name' => 1 }
は X-Name
のままだった。
after Rails 4.0.0
get '/path', params, { 'X-Name' => 1 }
と書くと HTTP_X_NAME
という header name に変換されるので、controller とかからアクセスできるようになる。
https://github.com/rails/rails/commit/9af59b2468e4ad6c3c2ca89f90968fdcaa417aba
「X がモナドである」はなにが嬉しいのか
この記事はぼくの考えを雑に文章化したものであって、不正確な可能性が特に高いので気をつけてくださいね。
ごくたまに「X はモナドだったんだ」のような発言をすることがある。これは自分が理解しようとしている対象 X が、自分がすでに理解している概念であるモナドの性質を持っていることがわかったことで対象 X への理解が進んだ時に主に発していると思う。これは別にモナドにかぎらず、「あ、Strategy パターンだ」とか他にもある。
さて、「X がモナドである」とわかった時になにが嬉しいのかいまいち言語化できてなかったのだけど、今日 関数型プログラマのための Rx 入門(後編) を読んでいて不意に Applicative Functor について調べた時に、自分が 「X がモナドである」とわかった時の嬉しさが明瞭になった。
インターネット上でもたまに「X がモナドである」という発言を目にすることがある。「X がモナドである」とわかるとなにが嬉しいのかわからない人がこの記事を読んで、なるほどと腑に落ちることを目指してこの記事を書いてみる。
「X がモナドである」がわかると、X が次のような性質を持っていることがわかる(はず)
- X はふつう世界の型をラップするような型であること (Functor の性質)
- ふつうの世界の関数を X の世界の関数に写すことができること (Functor の性質)
- X の世界の関数を X の世界の値に適用できること (Applicative Functor の性質)
- X の世界の型をさらにラップした X(X) な世界の型を X の世界の型に写すことができる (Monad の性質)
ここでいう "世界" というぼうが勝手に作った一般的でない用語は、パラレルワールドものの世界線を超えて同時に存在(しているように見える)世界とかを想像してもらえるといいかもしれない。
「X がモナドである」ことがわかるとこれだけのことがわかって便利。もちろんこれだけしかわからないから「X がモナドである」ことがわかっても X についての理解はそこまで進んでない。それでも「X がモナドである」という発言が実際の理解以上の喜びを含んでいるのは、慣れ親しんだモナドをこれから学ぼうとする新しい領域にも見つけた喜びのせいに違いない、きっとそうだ。
Redis cluster
Redis 初心者が Redis 3.0 から追加された cluster 機能を使ってみました。勘違いや憶測が多分に含まれます、ご注意を><
セットアップ
現時点では 3.0 がパッケージマネージャでインストールできなかったので、Redis 公式ページから latest stable をダウンロードして、make
, make test
した。
大体 http://redis.io/topics/cluster-tutorial を見てセットアップする。今回はまずは 4 master node で動かしてみる。後でノードを追加したいので余分に設定を作っておく。
❯ mkdir 7000 7001 7002 7003 7004 7005 ❯ cat <<EOS > redis.conf port 7000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOS ❯ for i in {0..5}; do cp -av redis.conf "700$i/"; sed -i -e "s/port 7000/port 700$i/g" "700$i/redis.conf"; done
cluster-config-file
は redis を起動させたディレクトリにできる。この config ファイルは cluster enabled な Redis サーバーが自動で生成するもので各インスタンス固有にしなければならない。なので redis-server 起動時は各インスタンスの CWD が重ならないようにする。そこに気をつけてそれぞれのディレクトリに cd しながら各 config ファイルで4つの Redis インスタンスを起動する。redis-server redis.conf
。
原始的な方法だと、それぞれの Redis インスタンスを cluster enable モードで立ち上げておいて、redis/src/redis-trib.rb スクリプトを使ってクラスタを作成する。今回は replica なしで 4 master でセットアップした。(--replicate 0
を指定)
~/Downloads/redis-3.0.0/src ❯ ./redis-trib.rb create --replicas 0 \ 127.0.0.1:7000 \ 127.0.0.1:7001 \ 127.0.0.1:7002 \ 127.0.0.1:7003
クラスタを作成すると各インスタンスのログに 1925:M 04 Apr 15:04:55.489 # Cluster state changed: ok
とか出た。
~/Downloads/redis-3.0.0/src ❯ redis-cli -p 7000 cluster nodes f368ccf3ca85a5007a34e8e3b93f3e37797055f6 127.0.0.1:7003 master - 0 1428129180876 4 connected 12288-16383 2b4114a2b99ba696950ad919196223eb25c9ede2 127.0.0.1:7000 myself,master - 0 0 1 connected 0-4095 0e1301d83a174b598c6315167b868be93003e4c4 127.0.0.1:7002 master - 0 1428129182430 3 connected 8192-12287 968d6f7c12ae4c6c70239c59aafd89c302dfd427 127.0.0.1:7001 master - 0 1428129181397 2 connected 4096-8191
うん、動いている。
redis-cluster は hash slot という概念でシャーディングしている。キーの集合からなる hash slot があり、クラスタ内の1ノードが複数の hash slot を担当する方式だ。
- Node A contains hash slots from 0 to 5500.
- Node B contains hash slots from 5501 to 11000.
- Node C contains hash slots from 11001 to 16384.
ある割合の hash slot をノードからノードへ移動することで、master ノードの追加や削除に対応する。
コマンドオプションから察せれるように、ノードの replication にも対応していて、3 master - 6 slave 構成とかを取ることもできるらしい。
ノード間の通信は次のことを通信している。(画像は link のスライドから)
コマンド操作
redis-cli を使えば透過的にクラスタ内のノードにコマンドを発行できるが、試しにクラスタ機能に対応してなさそうなクライアントでコマンド発行してみた。
# gem i pry redis # pry -r redis [15] pry(main)> redis = Redis.new(port: 7000) => #<Redis client v3.2.1 for redis://127.0.0.1:7000/0> [16] pry(main)> redis.get('my_key') Redis::CommandError: MOVED 13711 127.0.0.1:7003 from /Users/taiki45/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis/client.rb:113:in `call' [17] pry(main)> redis = Redis.new(port: 7003) => #<Redis client v3.2.1 for redis://127.0.0.1:7003/0> [18] pry(main)> redis.get('my_key') => nil [19] pry(main)> redis.set('my_key', 123) => "OK" [20] pry(main)> redis.get('my_key') => "123" [21] pry(main)> redis = Redis.new(port: 7000) => #<Redis client v3.2.1 for redis://127.0.0.1:7000/0> [22] pry(main)> redis.get('my_key') Redis::CommandError: MOVED 13711 127.0.0.1:7003 from /Users/taiki45/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis/client.rb:113:in `call'
キーによってクラスタ内のノードが決定されていて、キーから決定されるノードと違うノードにコマンドを発行すると MOVED
とレスポンスされた。レスポンスされたノードへ繋ぐといつも通りにコマンド発行ができるっぽい。プロキシーを用意しない方式は初めてみたがシンプルでなんとなく Redis っぽいさを感じる。(画像は link のスライドから)
クラスタ機能に対応する実装ではこのエラーレスポンスをパースして自動的に接続するノードを切り替えることで透過的な操作を可能にしている。
if errv[0] == "MOVED" || errv[0] == "ASK" (...) newslot = errv[1].to_i node_ip,node_port = errv[2].split(":") (...) else
このあたりの話はまだ読んでない Redis Cluster Specification に書いてありそう。
ノードの追加と re-shard
試しに1台ノードを追加してみる。コマンドは add-node new_host:new_port existing_host:existing_port
だ。
~/Downloads/redis-3.0.0/src ❯ ./redis-trib.rb add-node 127.0.0.1:7004 127.0.0.1:7000 >>> Adding node 127.0.0.1:7004 to cluster 127.0.0.1:7000 (...) [OK] New node added correctly. ~/Downloads/redis-3.0.0/src ❯ redis-cli -p 7000 cluster nodes 2b4114a2b99ba696950ad919196223eb25c9ede2 127.0.0.1:7000 myself,master - 0 0 1 connected 0-4095 968d6f7c12ae4c6c70239c59aafd89c302dfd427 127.0.0.1:7001 master - 0 1428129717741 2 connected 4096-8191 f368ccf3ca85a5007a34e8e3b93f3e37797055f6 127.0.0.1:7003 master - 0 1428129718766 4 connected 12288-16383 48da16af4dc5a15b844f2977eefb490ea7b9720e 127.0.0.1:7004 master - 0 1428129719281 0 connected 0e1301d83a174b598c6315167b868be93003e4c4 127.0.0.1:7002 master - 0 1428129718766 3 connected 8192-12287
クラスタに参加できだ。クラスタに参加しただけだとまだ hash slot は割り当てられない。割り当てられないだけでクライアントからのリクエストには応答できるようだ。
[23] pry(main)> redis = Redis.new(port: 7004) => #<Redis client v3.2.1 for redis://127.0.0.1:7004/0> [24] pry(main)> redis.get('my_key') Redis::CommandError: MOVED 13711 127.0.0.1:7003
新しく追加した port 7004 で listen しているノードに hash slot を割り当てる。コマンドの出力が長いのと対話的なやりとりがあるのでログに直接コメントを書いた。#
で始まる行が加工したコメントで、別途見やすいように改行を追加してある。
# クラスタ内のノード。左がノードID。一番右が担当している hash slot 番号。 ~/Downloads/redis-3.0.0/src ❯ redis-cli -p 7000 cluster nodes 2b4114a2b99ba696950ad919196223eb25c9ede2 127.0.0.1:7000 myself,master - 0 0 1 connected 0-4095 968d6f7c12ae4c6c70239c59aafd89c302dfd427 127.0.0.1:7001 master - 0 1428131195055 2 connected 4096-8191 f368ccf3ca85a5007a34e8e3b93f3e37797055f6 127.0.0.1:7003 master - 0 1428131194539 4 connected 12288-16383 48da16af4dc5a15b844f2977eefb490ea7b9720e 127.0.0.1:7004 master - 0 1428131193501 0 connected 0e1301d83a174b598c6315167b868be93003e4c4 127.0.0.1:7002 master - 0 1428131195561 3 connected 8192-12287 ~/Downloads/redis-3.0.0/src ❯ ./redis-trib.rb reshard 127.0.0.1:7004 # (1) クラスタ内ノードのチェック Connecting to node 127.0.0.1:7004: OK Connecting to node 127.0.0.1:7003: OK Connecting to node 127.0.0.1:7000: OK Connecting to node 127.0.0.1:7002: OK Connecting to node 127.0.0.1:7001: OK >>> Performing Cluster Check (using node 127.0.0.1:7004) M: 48da16af4dc5a15b844f2977eefb490ea7b9720e 127.0.0.1:7004 slots: (0 slots) master 0 additional replica(s) M: f368ccf3ca85a5007a34e8e3b93f3e37797055f6 127.0.0.1:7003 slots:12288-16383 (4096 slots) master 0 additional replica(s) M: 2b4114a2b99ba696950ad919196223eb25c9ede2 127.0.0.1:7000 slots:0-4095 (4096 slots) master 0 additional replica(s) M: 0e1301d83a174b598c6315167b868be93003e4c4 127.0.0.1:7002 slots:8192-12287 (4096 slots) master 0 additional replica(s) M: 968d6f7c12ae4c6c70239c59aafd89c302dfd427 127.0.0.1:7001 slots:4096-8191 (4096 slots) master 0 additional replica(s) [OK] All nodes agree about slots configuration. # (2) いくつ hash slot 動かすか質問される。 # re-shard 前は 16384 slot が各ノードへ4096ずつ割り当てられていた。 # 16384 / 5 がだいたい 3276 なので3276個を動かすことにする。 >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. How many slots do you want to move (from 1 to 16384)? 3276 # (3) どのノードが今回動かす hash slot を受け取るか質問される。 # 新ノードのIDを指定する。 What is the receiving node ID? 48da16af4dc5a15b844f2977eefb490ea7b9720e # (4) どのノードから hash slot を動かすか質問される。 # 今回はすべてのノードから平等に新ノードへ hash slot を動かしたいので `all` を指定する。 # ノードごとの性能が違ったりして、あるノードの負担を減らしたいときなどに個別指定が便利なのかもしれない。 Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. Source node #1:all # (5) Resharding plan が表示されるので眺めてから同意する。 eady to move 3276 slots. Source nodes: M: f368ccf3ca85a5007a34e8e3b93f3e37797055f6 127.0.0.1:7003 slots:12288-16383 (4096 slots) master 0 additional replica(s) M: 2b4114a2b99ba696950ad919196223eb25c9ede2 127.0.0.1:7000 slots:0-4095 (4096 slots) master 0 additional replica(s) M: 0e1301d83a174b598c6315167b868be93003e4c4 127.0.0.1:7002 slots:8192-12287 (4096 slots) master 0 additional replica(s) M: 968d6f7c12ae4c6c70239c59aafd89c302dfd427 127.0.0.1:7001 slots:4096-8191 (4096 slots) master 0 additional replica(s) Destination node: M: 48da16af4dc5a15b844f2977eefb490ea7b9720e 127.0.0.1:7004 slots: (0 slots) master 0 additional replica(s) Resharding plan: Moving slot 12288 from f368ccf3ca85a5007a34e8e3b93f3e37797055f6 Moving slot 12289 from f368ccf3ca85a5007a34e8e3b93f3e37797055f6 (...) Do you want to proceed with the proposed reshard plan (yes/no)? yes # (6) あとはひたすら Resharding の様子が眺められる。
特に計測してないが、MBP (13, Early 2015) のマシンで30秒くらいで Resharding が終わった模様。実環境だとどれくらいだろうか...
cluster コマンドで各ノードを確認してみる。
~/Downloads/redis-3.0.0/src ❯ redis-cli -p 7000 cluster nodes 2b4114a2b99ba696950ad919196223eb25c9ede2 127.0.0.1:7000 myself,master - 0 0 1 connected 819-4095 968d6f7c12ae4c6c70239c59aafd89c302dfd427 127.0.0.1:7001 master - 0 1428131461381 2 connected 4915-8191 f368ccf3ca85a5007a34e8e3b93f3e37797055f6 127.0.0.1:7003 master - 0 1428131463435 4 connected 13107-16383 48da16af4dc5a15b844f2977eefb490ea7b9720e 127.0.0.1:7004 master - 0 1428131462415 5 connected 0-818 4096-4914 8192-9010 12288-13106 0e1301d83a174b598c6315167b868be93003e4c4 127.0.0.1:7002 master - 0 1428131462415 3 connected 9011-12287
後から追加した ID 48da16af4dc5a15b844f2977eefb490ea7b9720e
のノードに無事新しく hash slot が割り当てられた。
まとめ
- Redis cluster についてざっくり説明
- クラスタのセットアップ
- No proxies, redirection を確かめた
- ノードの追加と Resharding を試した
次は master-slave 構成にしてみてノードのダウン時にどうするかやってみたい。
参考にしたリスト
vimfiler 使いはじめた & 設定キメた
NERD Tree を一時期使ってたのだけど、なんかちがうなぁ... と思ってずっと unite.vim の file を使ってファイルを開いてたのだけどやっぱツリー構造で表示したいなぁって思ってて、MBP の環境構築に合わせて vim 周りをちょっといじったので vimfiler を導入してみた。これがよかった。
vimfiler 自体はデフォルトで起動すると vim 標準の filer + α なイメージで、コマンドオプションを使うと NERD Tree みたいな IDE のファイルツリーみたいなのも表示できる、みたいなやつです。
vimfiler のなにがよかったか考えてみたんだけど、デフォルトの key binding が自分の思考に合ってたからな気がする。なにも見ずにとりあえず o
押した時にツリーがパカって開いたので「おっよさそう」って思った。他の binding も気に入ってる。あと help が読みやすかった。
:h vimfiler とググってでてきた記事いくつかを参考にして設定キメた。
autocmd FileType vimfiler nmap <buffer> <CR> <Plug>(vimfiler_expand_or_edit)
- デフォルトだと Enter でディレクトリに入ってしまって好みと合わないので、Enter は単にツリーを開くだけにした。
h
とl
で "親ディレクトリに移動" と "子ディレクトリに移動" がデフォルトでできて対称性あるので、こっちの設定のが好み。
- デフォルトだと Enter でディレクトリに入ってしまって好みと合わないので、Enter は単にツリーを開くだけにした。
let g:vimfiler_as_default_explorer = 1
- vim 標準のファイラを置き換える。
noremap <C-X><C-T> :VimFiler -split -simple -winwidth=45 -no-quit<ENTER>
C-X
C-T
で IDE みたいなファイルツリーを開く。width の値を適当に変えると大きさが変わる。
autocmd VimEnter * VimFilerExplorer
- vim 開いたら vimfiler が表示される。けど、git commit message でもでてきて、たぶん filetype とかで分岐すればいいんだろうけど、とりあえず無効にしている。気が向いたら filetype 判定やりたい。
参考にしたリスト
設定ファイル
NeoBundle 'Shougo/vimfiler' " Use vimfiler instead of default filer. let g:vimfiler_as_default_explorer = 1 " Open filer noremap <silent> :tree :VimFiler -split -simple -winwidth=45 -no-quit noremap <C-X><C-T> :VimFiler -split -simple -winwidth=45 -no-quit<ENTER> " Don't let <CR> enter the directory but let it open the directory autocmd FileType vimfiler nmap <buffer> <CR> <Plug>(vimfiler_expand_or_edit) " Automatically open vimfiler on start "autocmd VimEnter * VimFilerExplorer " If no files are specified, open vimfiler "autocmd VimEnter * if !argc() | VimFiler | endif
Rails application の起動と実行メモ
rails コマンド
- bin/rails
- require "rails/cli"
- rails/cli: require 'rails/app_rails_loader'
- Rails::AppRailsLoader.exec_app_rails:
- bundler のチェック
- APP_PATH = Dir.pwd + config/application.rb
- require File.expand_path('../boot', APP_PATH)
- require 'rails/commands'
- rails/commands: ARGVの操作と alias の設定
- require 'rails/commands/commands_tasks'
- help message の定義
- command の dispatch
- require APP_PATH: gem の require, Rails.application
- Rails::CommandsTasks.new(ARGV).run_command!(command):
runner
とかの実体を呼んで実行する - exec_app_rails: 正常に command が終了したら rails/cli まで戻る
- if ARGV.first == 'plugin': require 'rails/commands/plugin' - plugin generate
- else: require 'rails/commands/application' - application generate
Rails.application#call は実際にどうやってなにが呼ばれるのか
ActionController::Base#action(action).call(env) が呼ばれるまでを追ってみた。
雑にまとめると、通常の routing では
Rails::Application#call
ActionDispatch::MiddlewareStack#call
ActionDispatch::Routing::RouteSet#cal
ActionDispatch::Journey::Router#call
ActionDispatch::Jouney::Route#app.call
Routing::RouteSet::Dispatcher#call
SomeController.action(action).call
となる。以下乱雑なメモ
- Rails::Application#call: super
- Rails::Engine#call: #app.call(env)
- Rails::Engine#app:
- config.middleware = config.middleware.merge_into(default_middleware_stack)
- config.middleware.build(endpoint)
#config
: Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) &config=
もある- Rails::Application#config: #app_middleware
- Rails:::Railtie#app_middleware: @@app_middleware ||= Rails::Configuration::MiddlewareStackProxy.new
MiddlewareStackProxy#merge_into
:#default_middleware_stack
- Rails::Application#default_middleware_stack: DefaultMiddlewareStack.new, #buidl_stack
#build_stack
: ActionDispatch::MiddlewareStack.new.tap {}
- ActionDispatch::MiddlewareStack#build(endpoint):
- Rails::Engine#endpoint: self.class.endpoint || routes
- Rails::Engine#routes: ActionDispatch::Routing::RouteSet.new
#build(app = ActionDispatch::Routing::RouteSet.new)
no block: middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }ActionDispatch::MiddlewareStack::Middleware#build
: klass.new(app, *args, &block)Middleware#klass
: 各 middleware で.new(app, *args, &block)
する。args, block はuse
orinsert
とかのargs
,block
が来る。- 返り値は全ての rack middleware をチェーンした ActionDispatch::Routing::RouteSet (=
Rails::Application.endpoint
)。endpoint を任意の rack interface 互換のものにどこかで差し替えれば Raisl の routing を差し替えれるかもしれない。
- ActionDispatch::Routing::RouteSet#call: @router.call(env)
@router
: Journey::Router.new(Journey::Routes.new)
- Journey::Router#call: find_routes(env).each {|route| status, headers, body = route.app.call(env) }
- route: filter_routes
- Journey::Router#filter_routes: routes#simulator
- Journey::Routes#simulator: GTG::Simulator.new(GTG::Builder.new(ast).transition_table)
- Simulater.new(string):
- string: Gtg#transition_table
- Simulater#simulate: state
- state: TODO
- ActionDispatch::Jouney::Route#app.call(env):
#app
: Set by Mapper- Mapper#app: Constraints.new(endpoint, blocks, @set.request_class)
- endpoint: (:to option (
get '/', to: 'users#index'
) which responsd_to? :call) or (dispatcher) - Mapping#dispatcher: Routing::RouteSet::Dispatcher.new(:defaults => defaults)
- defaults:
defaults: { format: 'jpg' }
otion
- defaults:
- Routing::RouteSet::Dispatcher#call(env): rack app とかが指定されない場合これが呼ばれる
- params: env['action_dispatch.request.path_parameters']
- params['controller], params['action']: すでにセットされている
- Dispatcher#dispatch(controller):
- controller: controller_reference(controller_params)
- const_name:
@controller_class_names[controller_param] ||= "#{controller_param.camelize}Controller"
- ActiveSupport::Dependencies.constantize(const_name)
- const_name:
- controller: controller_reference(controller_params)
- controller#action(action).call(env)
journey、やらなきゃいけないことが複雑でコードも複雑でめっちゃ疲れた追い切れない... JourneyHackingGuides ほしい...
次は named routes がどこの routes がどう呼ばれてるのか調べたい...