0

最初のセグメントがプロファイルのエイリアスまたは ID であるルートを実装しようとしています。

resources :profiles, :path => '' do
    ...
end

そして、エイリアスが他の(より高い)ルートの最初のセグメントによってまだ使用されていないことを検証する必要があります。私が今持っているものは次のとおりです。

validates :alias, :exclusion => {:in => Rails.application.routes.routes.map{|r| r.path.spec.to_s.split('(').first.split('/').second}.compact.uniq },
                  ....

開発中はすべて問題ありません。本番Rails.application.routes.routes.map...環境では空の配列を返します。ただし、モデルの検証内でのみ、テストするためだけにビューのどこかに配置すると、期待どおりにすべてのルートの最初のセグメントの配列が返されます。私は何が間違っているのですか、それとももっと良い解決策がありますか?

4

1 に答える 1

1

タイミングの問題があると思います。Rails.application.routesモデルが本番モードでロードされたとき、ルーティング テーブルはおそらく構築されていません。ただし、開発モードでは、モデルはおそらくリクエストごとに再ロードされるためRails.application.routes、モデルがロードされてvalidates呼び出しが行われると、データが取り込まれます。

validates :alias, :exclusion => { :in => Rails.application.routes.routes.map { ... } }

実行されます。

簡単な解決策は、検証方法に切り替えることです。

class Model < ActiveRecord::Base
    validate :alias_isnt_a_route, :if => :alias_changed?

private

    def alias_isnt_a_route
        routes = Rails.application.routes.routes.map { ... }
        if(routes.include?(alias))
            errors.add(:alias, "Alias #{alias} is already used for a route")
    end
end

Rails.application.routesこの方法では、エイリアスを確認する必要があるまでは確認しません。その時点までに、ルートは読み込まれています。もちろん、必要に応じてルート プレフィックス リストをキャッシュすることもできます。

また、アプリケーションの初期化フェーズにサニティ チェックを追加することもできます。開発中にルートを追加するときに、実稼働環境の誰かが'pancakes'エイリアスとして追加する可能/pancakes性があります。検証では、この新しい競合が見逃されます。このような単純なもの:

config.after_initialize do
    Rails.application.reload_routes! # Make sure the routes have been loaded.
    # Compare all the existing aliases against the route prefixes and raise an
    # exception if there is a conflict.
end

あなたconfig/application.rbで十分でしょう。

于 2012-06-04T17:23:36.517 に答える