重构-基于Rails:Engine的Rails网站系统拆分

网站做着做着就会发现整个系统越来越庞大,如电商网站你需要有电商系统和后台管理系统,甚至还有仓储系统或者API系统,把这些系统都放在一个网站应用里就会发现网站代码异常庞大,而且每个系统的更新频率会被限制成一样,后台系统无法实现快速开发,所以也就想到了网站的系统服务。现在比较流行网站系统拆分是微服务架构,但是这是比较复杂的拆分,一般网站还到达不了这个地步,这篇介绍基于Rails:Engine的Rails网站系统拆分。

个人原创,版权所有,转载请注明原文出处,并保留原文链接:

https://www.embbnux.com/2016/03/15/rails_system_refactor_with_rails_engine

参考: Getting Started with Engines  Breaking Up a Monolithic Rails App Without MicroService

一、Rails:Engine介绍

Engine可以看成一个简洁版的rails, Rails::Application 就是继承自 Rails::Engine, engine也可以嵌入到rails中,现在的很多gem就是利用engine的特性,实现rails功能的快速扩展,比如很出名devise用户系统就是基于engine,装上系统包后就自动拥有了用户系统,包括登录注册等功能。

Rails:Engine还分为两种,一种是需要附属于rails的engine,需要在routes.rb里面配置 mount App::Engine => ‘/app’这样的语句,这种属于mountable类型的engine,还有一种不需要mount的直接gemfile包含就可以正常使用的叫做full类型的engine,他有自己的routes.rb.

基于Rails:Engine的系统拆分,就是把各个系统共用的代码以及逻辑放在engine里,整合成一个gem包,比如model层的代码以及用户系统,就可以完全放在engine的包里,这里把这个engine包成为core,即核心代码所在处,然后每个系统都是单独的rails工程,可以独立开发,独立部署,但都继承了core的核心代码,方便了代码维护以及降低了部署风险,各个系统互不影响,可以部署在不同的服务器上,只要连着相同的数据库即可。

二、基于Rails:Engine的系统拆分

这里讲怎么构建core engine,这里是用full模式的engine,只要在子系统的gemfile里添加该engine即可使用。

生成core engine gem包:


rails plugin new core --full

会生成和rails工程很像的工程目录,一样有自己的app目录和config/routes.rb文件,只是没有config/application.rb这个,而多了以下文件:

# engine 根目录
|__ lib
|__ |__ core.rb
|__ ___ core
|       |__ engine.rb
|       |__ version.rb

主要核心是lib/core/engine.rb这里决定这个gem干什么。app目录下同样有models,controllers等目录, rails会自动加载这些标准目录的文件,所以之前代码的model层就可以移动过来了。
如果其它文件夹也要放到core里,就是在lib/core/engine.rb里配置加载选项,比如要把db/migrate的文件放到core里就可以这么配置

require 'rails/all'
require 'pg'

module Core
  class Engine < ::Rails::Engine
    # 下面这句话可以为engine包指定命名空间,防止以底层冲突,由于是自维护gem,暂不启用
    # isolate_namespace Core

    # 共享migrate文件
    initializer 'append_migrations' do |app|
      unless app.root.to_s == root.to_s
        config.paths['db/migrate'].expanded.each do |path|
          app.config.paths['db/migrate'] << path
        end
      end
    end
    
    # 指定自动加载目录
    config.autoload_paths += %W(
      #{config.root}/app/uploads
    )
    config.eager_load_paths += %W(
      #{config.root}/app/uploads
    )
  end
end

这样在子系统跑migrate也会找到core的migrate跑

活着还想把initializers也放到core里面,可以这么搞:

initializer 'append_initializer' do |app|
  app.config.paths['config/initializers'] << 'config/initializers'
end

这样启动子系统的rails也会加载core的初始化文件。

三、子系统加载engine

在子系统加载engine直接在gemfile里配置即可以,首先把core的工程和你的子系统的工程放在同一目录下:

|__ projects
|__ |___ core
|       |__ Gemfile
|__ |___ web
|       |__ Gemfile
|__ |___ admin
|       |__ Gemfile

web的Gemfile:

gem 'core', path: '../core'

admin的Gemfile也一样
这里对于已经成熟稳定的core,可以直接从git安装加载,指定版本就可以更新core了,就完全和gem包一样了。
在core添加的routes也会自动出现在下一层。

代码怎么拆分,就仁者见仁了,下一层的代码也可以用猴子补丁的方法为core添加代码,这里建议model层就放在core了,下层只有controller和view

四、部署

部署的时候就得注意目录结构,比较复杂,推荐用capistrano配置完就可以很简单的一键部署了,下篇博客介绍。
完!

本博客要开始启用公众订阅号了,欢迎关注,及时获取最新博客信息:

weixin_xiao

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Time limit is exhausted. Please reload the CAPTCHA.