温馨提示:本文翻译自stackoverflow.com,查看原文请点击:ruby - Rails: It is strange to call module in module as Enum
ruby ruby-on-rails

ruby - Rails:将模块中的模块称为Enum很奇怪

发布于 2020-03-27 15:42:56

对不起,我的英语不好。

我在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

查看更多

查看更多

提问者
mackeee
被浏览
123
max 2020-01-31 18:40

这真的很简单。rails autoloader不知道app/services/leader_board/fetch_board_members_service.rb声明该常量LeaderBoard::BoardType,怎么可能?

它与“ Enum”在Ruby中并不是真正的事实无关。多数民众赞成在只是一个模块,它声明了一些常量,因此与任何其他模块没有什么不同,这仅仅是一种模式,与其他语言(如C ++和Java)中的枚举类型相似。

查找常量时,自动加载器会根据文件位置进行假设,并期望文件位于自动加载路径之一中。一般Rails应用程序中的authload路径是的每个子目录/app因此,当您引用LeaderBoard::BoardTypeRails期望在中定义它时/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将“向上”嵌套模块并首先自动加载“外部模块”。这不仅使它可以正确自动加载,而且还可以帮助其他开发人员查找代码,因为如果未在自己的文件中定义它,这是一个逻辑上的地方。