15

Railsアプリケーションの起動時にクラス属性を設定したいとします。いくつかのルートを調べる必要があるので、カスタムコードを実行する前にルートをロードする必要があります。* after *ルートを実行するRailsイニシャライザはロードされていますか?

config.after_initialize do 
    Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}" 
end 

しかし、それはは、「開発」環境で仕事(ルートをしません。私は、これは「テスト」環境で完璧に動作し

トラブルにフックする信頼できる場所を見つけるのを持っています空である)

今のところ、すべてのリクエストの前に私が理解するconfig.to_prepareで同じコードを実行することで開発モードで作業しているようです。残念なことに、to_prepareだけを使用すると、テストモードで動作しないように見えます。そのため、重複しています。

なぜテストモードでは、after_initializeの前にルートがロードされているのですが、開発モードではロードされていないのが不思議です。そして、本当に、これのための最良のフックは何ですか?すべての環境で動作する単一のフックがありますか?

*ルートをリロードするEDIT *

ムーの提案は素晴らしかったです。それは、すべての環境でafter_initialize内のルートへの一貫したアクセスを私に与えました。しかし、私の場合、to_prepareからコードを実行する必要があると思います。なぜなら、モデルにクラス属性を設定していて、各要求の前にモデルがリロードされているからです。

ここで私は何をしたのですか。

[:after_initialize, :to_prepare].each do |hook| 
    config.send(hook) do 
    User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq 
    end 
end 

これはちょっとわかりにくいようです。私はというような何かと思う:

config.after_initialize do 
    User.exclude_routes_from_usernames! 
end 

config.to_prepare do 
    User.exclude_routes_from_usernames! 
end 

をしかしUserRails.application.routesを検討するための適切な場所であれば、私はよく分かりません。私はlib /でコードと同じことをすることができると思うが、それが正しいかどうかは分かりません。

もう1つの方法は、muの提案をto_prepareに適用することです。それは動作しますが、私の開発環境ではすべての要求に対してルートが再ロードされるという顕著な遅れがあるようですので、少なくとも良いとは言えませんが、少なくともDRYです。

config.to_prepare do 
    Rails.application.reload_routes! 
    User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq 
end 

答えて

22

あなたはこれでRails.application.routesを見る前にロードするルートを強制することができます。

Rails.application.reload_routes! 

だからあなたconfig/application.rbでこれを試してみてください。

config.after_initialize do 
    Rails.application.reload_routes! 
    Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}" 
end 

私は同様のことをやりました(/:slugルートとの衝突のために)ルートをチェックするために必要とし、私はreload_routes!とチェックを入れて終わったあなたのように

+0

素晴らしいアイデアを!私たちは実際に同じことをしています( 'validate_exclusion_of'で除外リストとして使われる' User.invalid_usernames'という 'class_attribute'を更新しています)。私はまだ開発モードのためにto_prepareが必要だと思う。それがなければ、最初のリクエストでうまくいきます(今は私があなたの提案を使っています)。しかし、その後、私の 'User.invalid_usernames = Set.new'はそれを壊していると思います。あなたがafter_initializeだけを使用しているように聞こえるので、周りに巧妙な方法があるのでしょうか? – poochenza

+0

この回答は多くの助けになりましたので、私はそれを使用して終了しませんでしたが、私はそれを受け入れています(あなたは私が思うならば批判に開放!)ここで私の完全な解決策は、 //stackoverflow.com/a/8713207/1126857 – poochenza

+0

@poochenza: 'after_initialize'を使用してリリース間に新しい競合がないことを確認しました:'/pancakes'ルートを追加して2週間後に公開すると、if誰かが生産システム上で「パンケーキ」ユーザーを作成しました。次に、ユーザー名が作成または更新されると、新しいユーザー名とルートを比較します。 –

2

あなたはルートがロードした後、あなたがafter:オプションを使用して試すことができます初期化子でコードを実行しようとしている場合:

initializer "name_of_initializer", after: :add_routing_paths do |app| 
    # do custom logic here 
end 

あなたはここで、初期化イベントを見つけることができます。http://guides.rubyonrails.org/configuring.html#initialization-events

+0

このイニシャライザは、レール4.1.14.1で私のために決して実行されません – nolith

関連する問題