网站做着做着就会发现整个系统越来越庞大,如电商网站你需要有电商系统和后台管理系统,甚至还有仓储系统或者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配置完就可以很简单的一键部署了,下篇博客介绍。
完!
本博客要开始启用公众订阅号了,欢迎关注,及时获取最新博客信息:
哇,我们很有共同点啊,我大学也做的嵌入式,avr stm32 s3c2440 树莓派,现在也是rails后端,?
哈哈,很高兴认识你