对不起,我的英语不好。
我在Rails项目中使用服务层。
服务类由模块包装以用于名称空间。
一个模块具有一个名为Enum的模块。
我尝试调用该枚举模块,但rails StandardError exception: uninitialized constant
正常地说。
app/helpers/application_helper.rb
def no_problem_method
logger.debug LeaderBoard::FetchBoardMembersService.new.call
end
def problem_method
logger.debug LeaderBoard::BoardType::TOTAL # uninitialized constant LeaderBoard::BoardType
end
app/services/leader_board/fetch_board_members_service.rb
module LeaderBoard
module BoardType
TOTAL = 'total'
IN_SESSION = 'in_session'
GROUP = 'group'
end.freeze
class FetchBoardMembersService < BaseService
但是,更改调用顺序不会引起错误。
app/helpers/application_helper.rb
def problem_method
logger.debug LeaderBoard::BoardType::FetchBoardMembersService
logger.debug LeaderBoard::BoardType::TOTAL # SUCCESS!
end
为什么会这样?
我完全不知道。请帮助...另外,我放置了一些代码和日志,以帮助您理解这些奇怪的事情。
def problem_method
logger.info LeaderBoard
logger.info LeaderBoard.constants
logger.info LeaderBoard::FetchBoardMembersService
logger.info LeaderBoard.constants
logger.info LeaderBoard::BoardType
logger.info LeaderBoard::BoardType::TOTAL
end
和日志
rails_1 | LeaderBoard
rails_1 | []
rails_1 | LeaderBoard::FetchBoardMembersService
rails_1 | [:BoardType, :FetchBoardMembersService]
rails_1 | LeaderBoard::BoardType
rails_1 | total
这真的很简单。rails autoloader不知道app/services/leader_board/fetch_board_members_service.rb
声明该常量LeaderBoard::BoardType
,怎么可能?
它与“ Enum”在Ruby中并不是真正的事实无关。多数民众赞成在只是一个模块,它声明了一些常量,因此与任何其他模块没有什么不同,这仅仅是一种模式,与其他语言(如C ++和Java)中的枚举类型相似。
查找常量时,自动加载器会根据文件位置进行假设,并期望文件位于自动加载路径之一中。一般Rails应用程序中的authload路径是的每个子目录/app
。因此,当您引用LeaderBoard::BoardType
Rails期望在中定义它时/app/**/leader_board/board_type.rb
。
正如您已经知道的那样,如果您已经引用了它,那么就可以使用它,LeaderBoard::BoardType::FetchBoardMembersService
因为app/services/leader_board/fetch_board_members_service.rb
已经需要它了。
解决方案也很简单:正确布置代码。“根模块文件”应声明不在单独文件中的所有常量。
# app/services/leader_board.rb
module LeaderBoard
module BoardType
TOTAL = 'total'.freeze
IN_SESSION = 'in_session'.freeze
GROUP = 'group'.freeze
end.freeze
end
# app/services/leader_board/fetch_board_members_service.rb
module LeaderBoard
class FetchBoardMembersService < BaseService
end
end
这是可行的,因为Rails将“向上”嵌套模块并首先自动加载“外部模块”。这不仅使它可以正确自动加载,而且还可以帮助其他开发人员查找代码,因为如果未在自己的文件中定义它,这是一个逻辑上的地方。