如何访问 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!
由 InfoController
和 MailersController
在 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/
文件夹里有ActionController
和ApiController
(我建议你这样做+第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/
时它会起作用
我有一个 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!
由 InfoController
和 MailersController
在 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/
文件夹里有ActionController
和ApiController
(我建议你这样做+第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/