Подтвердить что ты не робот

Управление порядком загрузки маршрутов с двигателей

Итак, в Rails3 Двигатели поставляются со своими собственными моделями/контроллерами/видами и конечно маршрутами. Теперь возникает вопрос: как вы гарантируете, что маршруты двигателя будут загружены до (или после) маршрутов приложений и всех других двигателей, которые присутствуют?

Вот пример моих маршрутов приложений Rails:

match '*(path)', :to => 'foo_controller#bar_action'

И мой движок:

match '/news', :to => 'bar_controller#foo_action'

Таким образом, по умолчанию маршруты двигателей будут загружаться после приложений. Это означает, что маршруты Маршрута недоступны из-за этого маршрута для всех в моем приложении. Как заставить загружать маршруты двигателя сначала (или последним)?

4b9b3361

Ответ 1

То, что вы пытаетесь сделать, довольно сложно. Как уже упоминалось, маршруты двигателей загружаются после того, как маршруты приложений и переопределение этого поведения могут быть проблематичными. Я могу придумать несколько вещей, которые вы можете попробовать.

Использовать инициализатор после инициализации путей маршрутизации

В источнике rails есть инициализатор в engine.rb, один из способов выполнить то, что вам нужно, - попытаться подключиться к функциональности, с которой он имеет дело. Инициализатор по умолчанию выглядит так:

initializer :add_routing_paths do |app|
  paths.config.routes.to_a.each do |route|
    app.routes_reloader.paths.unshift(route) if File.exists?(route)
  end
end

По существу, это должно идти по пути ко всем файлам маршрутов, о которых знает Rails, и пытаться их добавить в перегружатель маршрутов (то, что автоматически перезагружает файл маршрутов для вас, если оно изменено). Вы можете определить другой инициализатор, который будет запущен сразу после этого, затем вы проверите пути, хранящиеся в перегружателе маршрутов, вытащите путь, принадлежащий вашему движку, удалите его из массива путей и вставьте его обратно, но в конце массива путей. Итак, в config/application.rb:

class Application < Rails::Application
  initializer :munge_routing_paths, :after => :add_routing_paths do |app|
    engine_routes_path = app.routes_reloader.paths.select{|path| path =~ /<regex that matches path to my engine>/}.first
    app.routes_reloader.paths.delete(engine_routes_path)
    app.routes_reloader.paths << engine_routes_path
  end
end

Это может быть или не работать, в любом случае, я не рекомендую его, он не особенно изящный (например, уродливый хак, играющий с кишками рельсов).

Использовать Rails 3.1

Это может быть не вариант, но если это так, я, вероятно, поеду с этим. В Rails 3.1 у вас может быть 2 разных типа двигателей, полный и монтируемый (здесь вопрос SO, говорящий о некоторых различиях). Но по существу вы изменили бы ваш движок на монтируемый движок, маршруты в монтируемом двигателе будут заменены на имена, и вы можете явно включить их в файл маршрутов вашего основного приложения, например:

Rails.application.routes.draw do
  mount MyEngine::Engine => "/news"
end

Вы также можете использовать свои смонтированные маршруты двигателей и делать всевозможные другие причудливые вещи (подробнее здесь). Короче говоря, если вы можете перейти к 3.1, то это подход к использованию.

Динамическая вставка маршрутов из вашего движка в основное приложение

В настоящее время одним из самых известных двигателей Rails является Devise. Теперь, devise - это движок, который потенциально добавит довольно много маршрутов в ваше приложение, но если вы посмотрите на источник разработки, вы увидите, что на самом деле у него нет файла config/routes.rb! Это связано с тем, что приложение динамически добавляет свою правку маршрутизации в основной файл приложения routes.rb.

Когда вы запустите генератор модели, который поставляется с программой, одна из вещей, которую сделает генератор, это добавить строку, такую ​​как devise_for :model вверху вашего файла route.rb, сразу после строки Rails.application.routes.draw do. Таким образом, ваш route.rb выглядит аналогично этому после того, как вы выполните генератор для создания модели User:

Rails.application.routes.draw do
  devise_for :users
  ...
end

Теперь, devise_for - магический метод, который приходит как часть разработки (в lib/devise/rails/routes.rb), но по существу он создаст кучу регулярных маршрутов, которые все мы знаем на основе созданной вами модели.

То, что нам нужно знать, - это то, как разработчик вставляет эту строку в файл приложений routes.rb, тогда мы можем написать генератор в нашем движке, который вставляет любой из наших маршрутов в верхней части основных приложений routes.rb файл. Для этого рассмотрим lib/generators/devise/devise_generator.rb. В методе add_devise_routes последняя строка route devise_route. Route - это действие Thor, которое вставляет строку, переданную в основное приложение routes.rb. Поэтому мы можем написать собственный генератор и сделать что-то подобное, например:

class MyCrazyGenerator < Rails::Generators::NamedBase
  ...
  def add_my_crazy_routes
    my_route  = "match '/news', :to => 'bar_controller#foo_action'"
    route my_route
  end
end

Конечно, вам нужно будет убедиться, что вся инфраструктура генератора находится на своем месте, но суть. Разработчик написан некоторыми очень умными рельсовыми чуваками и используется довольно многими людьми, имитируя то, что они делают, вероятно, довольно хороший путь. Из 3 вещей, которые я предложил, это было бы так, как я бы справился с вашей проблемой (учитывая, что переход к рельсам 3.1, вероятно, не вариант).

Ответ 2

Имея ту же проблему прямо сейчас. Еще одно не очень элегантное, но безопасное решение, с которым я столкнулся, добавляет еще один жемчужину двигателя в конце вашего файла драгоценных камней, просто содержащий улов всего маршрута, больше ничего.

Изменить. Напротив, контринтетично, для того, чтобы его маршруты были загружены последним, необходимо, чтобы камень маршрутизации был указан до.

Ответ 3

Я не эксперт, но вчера я играл с sferik/rails_admin, когда я столкнулся с их решением маршрутизации. С их задачей rails_admin:install rake они непосредственно изменяют ваш файл config/routes.rb, добавляя mount RailsAdmin::Engine => '/admin', :as => 'rails_admin' в начале файла, чтобы они были уверены, что их маршруты всегда имеют наивысший приоритет. Этот метод mount относится к собственным маршрутам. Rb:

RailsAdmin::Engine.routes.draw do
  # Prefix route urls with "admin" and route names with "rails_admin_"
  scope "history", :as => "history" do
    controller "history" do
      [...]
    end
  end
end

Может ли это быть вашим решением?