`
icekiller110
  • 浏览: 69450 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于rails的services层

阅读更多
    由于ROR已经限定了MVC的三层架构,这样也就失去了service层,在做项目的时候会吧service层的业务逻辑写在controller层的action中,从逻辑上显得很乱,如果service层的业务逻辑简单的话还可以凑合,如果太复杂的业务逻辑就会增加代码的复杂度,减弱清晰度,增加维护的难度,处于种种原因想把service层抽象出来。
   
    我们的大体思路是在app下面创建一个服务层(例如service)的目录,然后在里面编写相应的service层的代码,把这个目录引入rails的加载路径,并且require此目录下所有的文件。

    按照这个思路,创建目录和编写service层代码都不是问题,rails的加载路径是什么,并且要在加载项目文件之前放入rails的加载路径。查看boot.rb其中
   
      def run
        load_initializer
        Rails::Initializer.run(:set_load_path)
      end
    

    从这段代码可以得知rails调用run的时候加载的项目路径,现在有了时机,所以可以在这个方法只有添加service层的路径。rails的加载路径的全局变量时“$:”,所以只要使用
$:.push("project_path/app/service")即可,然后再require此目录下面的所有文件
   
      Dir.foreach("project_path/app/service") do |filename|
        require filename if filename.match(/\.rb$/)
      end
    

然后可以启动项目测试了。

    最后我又查了version=2.3.5的rails源码的Initializer.rb,其中Configuration类的方法
   
      def initialize
        set_root_path!

        self.frameworks                   = default_frameworks        
        self.load_paths                   = default_load_paths
        self.load_once_paths              = default_load_once_paths
        self.eager_load_paths             = default_eager_load_paths
        self.log_path                     = default_log_path
        self.log_level                    = default_log_level
        self.view_path                    = default_view_path
        self.controller_paths             = default_controller_paths
        self.preload_frameworks           = default_preload_frameworks
        self.cache_classes                = default_cache_classes
        self.dependency_loading           = default_dependency_loading
        self.whiny_nils                   = default_whiny_nils
        self.plugins                      = default_plugins
        self.plugin_paths                 = default_plugin_paths
        self.plugin_locators              = default_plugin_locators
        self.plugin_loader                = default_plugin_loader
        self.database_configuration_file  = default_database_configuration_file
        self.routes_configuration_file    = default_routes_configuration_file
        self.gems                         = default_gems
        self.i18n                         = default_i18n

        for framework in default_frameworks
          self.send("#{framework}=", Rails::OrderedOptions.new)
        end
        self.active_support = Rails::OrderedOptions.new
      end

      ......

      def default_load_paths
        paths = []

        # Add the old mock paths only if the directories exists
        paths.concat(Dir["#{root_path}/test/mocks/#{environment}"]) if File.exists?("#{root_path}/test/mocks/#{environment}")

        # Add the app's controller directory
        paths.concat(Dir["#{root_path}/app/controllers/"])

        # Followed by the standard includes.
        paths.concat %w(
          app
          app/metal
          app/models
          app/controllers
          app/helpers
          app/services
          lib
          vendor
        ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
        paths.concat builtin_directories
      end
    


    可以看到方法default_load_paths里面已经添加了app/services的路径,但是下面
File.directory?(dir) 如果存在的话即添加,这样的话就很简单了,我们直接在app下面
添加services,添加对应的service层的代码运行,当然可以了,而且路径加载以后,还做了require处理,郁闷。。。。。。。。

    绕了一大圈rails已经提供了添加services层的功能。

    希望像给你的项目添加service层的朋友不要像我一样走这么多弯路。
  • initializer.rar (10.3 KB)
  • 描述: rails的Initializer.rb源码
  • 下载次数: 4
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics