Динамический URL -> Отображение контроллера для маршрутов в Rails - PullRequest
14 голосов
/ 08 апреля 2010

Я хотел бы иметь возможность динамически сопоставлять URL-адреса с контроллерами на основе информации в моей базе данных.

Я хочу сделать что-то функционально эквивалентное этому (предполагая модель View):

map.route '/:view_name',
    :controller => lambda { View.find_by_name(params[:view_name]).controller }

Другие предложили динамически перестраивать маршруты , но это не сработает для меня, поскольку может иметь тысячи видов, которые отображаются на один и тот же контроллер

Ответы [ 4 ]

13 голосов
/ 11 июля 2013

Этот вопрос старый, но мне он показался интересным. Полностью работающее решение может быть создано в Rails 3 с использованием возможности маршрутизатора для маршрутизации к конечной точке Rack.

Создайте следующий класс стойки:

    class MyRouter
      def call(env)
        # Matched from routes, you can access all matched parameters
        view_name= env['action_dispatch.request.path_parameters'][:view_name]

        # Compute these the way you like, possibly using view_name
        controller= 'post' 
        my_action= 'show'

        controller_class= (controller + '_controller').camelize.constantize
        controller_class.action(my_action.to_sym).call(env)
      end
    end

В маршрутах

    match '/:view_name', :to => MyRouter.new, :via => :get

Подсказка взята из http://guides.rubyonrails.org/routing.html#routing-to-rack-applications, в которой говорится: «Для любопытных« posts # index »фактически расширяется до PostsController.action (: index), который возвращает действительное приложение Rack».

Вариант, протестированный в Rails 3.2.13.

0 голосов
/ 30 марта 2012

Вот отличное решение для Rack Routing для SEO, предоставленное zetetic и Steve ross

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

В нем показано, как написать собственный диспетчер (где вы можете выполнить поиск в БД, если необходимо), а также с ограничениями и тестированием.

0 голосов
/ 04 февраля 2013

Как предлагается в вопросе Маршрутизация Rails для обработки нескольких доменов в одном приложении , я думаю, вы могли бы использовать Маршрутизация Rails - Расширенные ограничения для создания того, что вам нужно.

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

Предполагая, что у вас есть пространство из 2 контроллеров (PostController и CommentController), вы можете добавить в ваш route.rb следующее:

match "*path" => "post#show", :constraints => PostConstraint.new
match "*path" => "comment#show", :constraints => CommentConstraint.new

Затем создайте lib / post_constraint.rb:

class PostConstraint     
  def matches?(request)
    'post' == Rails.cache.fetch("/view_controller_map/#{request.params[:view_name]}") { View.find_by_name(request.params[:view_name]).controller }
  end
end

Наконец, создайте lib / comment_constraint.rb:

class CommentConstraint     
  def matches?(request)
    'comment' == Rails.cache.fetch("/view_controller_map/#{request.params[:view_name]}") { View.find_by_name(request.params[:view_name]).controller }
  end
end

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

0 голосов
/ 08 апреля 2010

Так что я думаю, что вы спрашиваете, есть ли у вас таблица Views и модель View для нее, где таблица выглядит как

id | name | model
===================
1  | aaa  | Post
2  | bbb  | Post
3  | ccc  | Comment

Вы хотите, чтобы URL-адрес / aaa указывал на Post.controller - это правильно?

Если нет, то то, что вы предлагаете, кажется нормальным, если предположить, что оно работает.

Вы можете отправить его в действие catch all и посмотреть действие по URL, запустить find_by_name и затем вызвать правильный контроллер оттуда.

def catch_all
  View.find_by_name('aaa').controller.action
end

Обновление

Вы можете использовать redirect_to и даже отправлять параметры. В приведенном ниже примере вы отправляете параметры поиска

def catch_all
  new_controller = View.find_by_name('aaa').controller
  redirect_to :controller => new_controller, :action => :index, 
      :search => params[:search] 
end
...