如何访问 rails 中的嵌套控制器?

How to access nested controllers in rails?

我有一个 Web 应用程序,我想将它扩展到 Web API。我已将我的控制器分成 2 个文件夹 Web 和 Api。我在 Web 文件夹中有我的 ApplicationController,并希望在 api 文件夹中有一个 ApiController。

我知道ActionController只能继承自ApplicationController。有没有一种方法可以让我使用 2 个独立的控制器,这样我就可以在每个控制器中有不同的行为?

我想要 2 的一个例子是这样我可以用不同的方式和 protect_from_forgery 以不同的方式处理 CanCan 异常。

更新

当我尝试 运行 我的测试时,出现以下错误

api_sessions_controller.rb:1:in `': uninitialized constant ApiController (NameError)

我的 Api 会话控制器是

class ApiSessionsController < ApiController
    def create
        user_password = params[:session][:password]
        user_email = params[:session][:email]
        user = user_email.present? && User.find_by(email: user_email)

        if user.valid_password? user_password
          sign_in user, store: false
          user.generate_authentication_token!
          user.save
          render json: user, status: 200, location: [:api, user]
        else
          render json: { errors: "Invalid email or password" }, status: 422
        end
    end
end

而 Api 控制器是

class ApiController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :null_session

  # include SessionsHelper

  rescue_from CanCan::AccessDenied do |exception|
        if user_signed_in?
            flash[:error] = "Access denied!"
            redirect_to root_url
        else
            flash[:error] = "Please Sign in"
            redirect_to new_user_session_path
        end
    end
end

我不知道是什么原因造成的,我看不出这两个控制器有什么问题,这就是为什么我认为我正在做的事情可能与 rails 框架

谁说只有ApplicationController can/should继承自ActionController? ApplicationController 设置查看文件的路径(与 APIs 无关)并定义 require_local!local_request?。如果您不使用这些方法(require_local!InfoControllerMailersController 在 Rails 代码库中调用),那么您不会丢失任何东西。

如果您有仅适用于您的 API 的逻辑,您当然可以直接将 ActionController 子类化,但有必要吗?如果您将 ApplicationController 子类化但重写相关方法,这不会涵盖您的用例吗?

我同意 ABMagil,没有人说你必须继承 ApplicationController。在您的情况下,您特别提到您想要不同的访问控制 + CSRF 保护,因此完全有理由拥有另一个继承自 ActionControlle::Base

的应用程序控制器

无论如何,一切都会发生在你的路线上:

namespace :api do
  # Stuff here will automatically look inside controllers/api/ folder, 
  # URL prefixed with /api/ 
  # View url/path helpers with prefix api_
end
# your_domain.com/api/my_resource/

scope module: 'web' do
  # Stuff here will look for controllers in controllers/web/ 
  # NO URL prefix
  # NO url/path prefix for View helpers
end
# your_domain.com/my_resource

编辑:关于你的错误

命名空间时,这意味着您将 类 包装在一个模块中,因此您必须为每个子控制器指定它。即

  • 你可以在/controller/文件夹里有ActionControllerApiController(我建议你这样做+第3点,感觉更清楚)

    controllers/api_controller.rb, 
    controllers/application_controller.rb
    
    class ApiController, class ApplicationController
    
  • 如果你想将它们移动到 api/web 子文件夹,你必须在文件中反映出来

    controllers/api/api_controller.rb, 
    controllers/web/application_controller.rb
    
    class Api::ApiController, class Web::ApplicationController
    
  • 显然,对于您的其他控制器也要尊重这一点

    controllers/api/session_controller.rb
    
    class Api::SessionController
    

另请注意,如果您想保留 API(仅大写字母),我认为当您使用文件夹名称 /API/

时它会起作用