我目前的申请结构如下:
示例控制器如下所示:
class Api::V1::RegisterController < Api::V1::ApiController
def create
@user = ::V1::User.new(user_params)
@user.email_address = params[:email_address]
@user.age_verification = params[:age_verification]
@user.remote_addr = request.env['REMOTE_ADDR']
@user.web_browser = browser.name.to_s + "(" + browser.version.to_s + ")"
@user.operating_system = browser.platform.to_s
if @user.save
head status: 201
else
render_bad_request(@user.errors.messages)
end
end
private
def user_params
params.permit(:email_address, :remote_addr, :web_browser, :operating_system, :age_verification)
end
end
示例模型如下所示:
class V1::User < ActiveRecord::Base
validates_presence_of :remote_addr, :web_browser,
:operating_system, :age_verification, :email_address
validates :email_address, uniqueness: { case_sensitive: false },
email_format: { check_mx: true }
end
我的主要问题这就是为什么我被迫在模特面前使用::V1
的原因?有没有更好的解决方法或我错过了什么?
答案 0 :(得分:3)
常量查找搜索当前模块范围,然后向上移动模块嵌套树。如果您只使用V1::User
,那么RegisterController
中的代码将Api::V1::RegisterController
中的V1
首先显示Api::V1
,然后找不到代码,将向上移动到Api
,然后最多V1
,它找到V1
,因此它已成功找到常量Api::V1
。但是User
并不包含名为::
的常量(或者至少不是您正在考虑的常量)。将V1
置于前面使得常量搜索从模块名称空间的顶部开始,或多或少。
至于是否有更好的方式...也许您想要将Api
的级别与V1::Api::WhateverController
交换?然后会有一个顶级版本控制模块,User
可以找到{{1}}而无需指定版本。如果那是你想要实现的目标......
答案 1 :(得分:1)
在此示例中,::V1
和::Api::V1
是单独的模块对象。当您从V1::User
内部引用Api::V1::ApiController
时,ruby会在最近的 V1
模块中查找User
。由于您已经在API::V1
内,因此ruby会尝试引用::Api::V1::User
。当它找不到它时,ActiveSupport的自动加载器启动并在加载路径中的某处查找api/v1/user.rb
。由于不存在此类文件,因此自动加载器无法找到User
模型,并且会抛出NameError
。