Rails 4.1:通过调用控制器中的方法创建路由

时间:2014-10-08 16:34:59

标签: ruby-on-rails routes

我想创建一个方法,当从控制器调用时,将添加具有路由到特定控制器的给定名称的嵌套资源路由。例如,这......

class Api::V1::FooController < ApplicationController
  has_users_route
end

......应该相当于......

namespace :api do
  namespace :v1 do
    resources :foo do
      resources :users, controller: 'api_security'
    end
  end
end

...这将允许他们浏览/api/v1/foo/:foo_id/users并向ApiSecurityController发送请求。或者它会转到Api::V1::ApiSecurityController?坦率地说,它们并不重要,因为它们都在同一个命名空间中。我想这样做,因为我想避免这几行:

resources :foo do
  resources :users, controller: 'api_security'
end

resources :bar do
  resources :users, controller: 'api_security'
end

使用方法更容易设置和维护。

只要知道在请求到达控制器后该做什么,我就可以了,但是我自动创建了一些我不太确定的路线。处理此问题的最佳方法是什么?我能找到的最接近的是关于引擎的很多讨论,但这并不合适,因为这不是我要添加到我的应用程序的独立功能,它是只是添加到现有资源的动态路由。

建议表示赞赏!

1 个答案:

答案 0 :(得分:0)

我最终建立在@juanpastas http://codeconnoisseur.org/ramblings/creating-dynamic-routes-at-runtime-in-rails-4建议的博客文章上,并根据我的需要定制它。从控制器调用方法最终成为处理它的坏方法。我在http://blog.subvertallmedia.com/2014/10/08/dynamically-adding-nested-resource-routes-in-rails/的博客中写了关于整件事的文章,但TL; DR:

# First draft, "just-make-it-work" code

# app/controllers/concerns/user_authorization.rb
module UserAuthorization
  extend ActiveSupport::Concern

  module ClassMethods
    def register_new_resource(controller_name)
      AppName::Application.routes.draw do
        puts "Adding #{controller_name}"
        namespace :api do
          namespace :v1 do
            resources controller_name.to_sym do
              resources :users, controller: 'user_security', param: :given_id
            end
          end
        end
      end
    end
  end
end

# application_controller.rb
include UserAuthorization

# in routes.rb
['resource1', 'resource2', 'resource3'].each { |resource| ApplicationController.register_new_resource(resource) }

# app/controllers/api/v1/user_security_controller.rb
class Api::V1::UserSecurityController < ApplicationController
  before_action :authenticate_user!
  before_action :target_id

  def index
  end

  def show
  end

  private
  attr_reader :root_resource

  def target_id
    # to get around `params[:mystery_resource_id_name]`
    @target_id ||= get_target_id
  end

  def get_target_id
    @root_resource = request.fullpath.split('/')[3].singularize
    params["#{root_resource}_id".to_sym]
  end

  def target_model
    @target_model ||= root_resource.capitalize.constantize
  end

  def given_id
    params[:given_id]
  end
end