使用 Meta Generator 打造你的 Rails Admin
按个人理解, Admin Interfaces 的主要作用是减少后台管理界面的 CRUD 开发的重复工作量,并提供登录注销等常见功能的实现.
Admin Interfaces 实现主要分两大块.
- 基于继承和配置.
- 代表: Django Admin(最著名的), ActiveAdmin.
- 优点: 代码量少.
- 缺点: 定制难度高.
- 基于代码生成.
- 代表: Rails Scaffold(自带的太简单了).
- 优点: 代码生成在项目里,定制只要直接修改代码即可,非常灵活.
- 缺点: 写自定义代码生成器有点难度.
- 同时使用代码生成和继承方式.
- 代表: ActiveScaffold
- 优点: 在减少代码的同时也保证了定制的灵活性.
- 缺点: 同上
作为有一个有追求的人,虽然已经 ActiveAdmin 和 ActiveScaffold 这样不错 Rails Admin Interfaces.但为了追求定制的灵活性的最大化,必须得自己造个轮子出来,哪怕是方的轮子.
什么是 Meta Generator?
就是写个 Generator A, Generator A 生成一个 Generator B 到你的项目里, 平常你主要运行 Generator B 生成 CRUD 相关代码. 这里的 Generator A 就是 Meta Generator.
Meta Generator 示例
首先,请认真读完 Creating and Customizing Rails Generators & Templates .
文中的 bin/rails generate generator initializer
的 generator 即是一个 Meta Generator,利用 generator 产生的代码存放在你的 Rails 项目的 lib/generators ,这样我们就可以很方便的修改. 我们只要参考 generator ,写一个类似的 Gem ,把代码生成到 lib/generators 目录即可.
cd your_workspace # 修改成你自己的目录
bundle exec rails plugin new meta_generator_demo # 创建一个 Rails Engine 的 Gem 项目
cd meta_generator_demo
vi meta_generator_demo.gemspec # 把里面的带 TODO 的都改成你准备填写的信息
mkdir -p lib/generators
cd your_rails_project
bundle exec rails g generator meta_generator_demo # 创建一个生成器
mv lib/generators/meta_generator_demo your_workspace/meta_generator_demo/lib/generators/meta_generator_demo # 修改成你自己的目录
cd your_workspace/meta_generator_demo # 修改成你自己的目录
vi lib/generators/meta_generator_demo/meta_generator_demo_generator.rb # 文件内容如下
# lib/generators/meta_generator_demo/meta_generator_demo_generator.rb
class MetaGeneratorDemoGenerator < Rails::Generators::NamedBase
source_root File.expand_path('../templates', __FILE__)
def create_demo_file
create_file 'lib/generators/demo_generator.rb', <<-EOS
class DemoGenerator < Rails::Generators::Base
desc "This generator creates an model file at app/models"
def create_demo_file
create_file "app/models/demo.rb", "class Demo; end"
end
end
EOS
end
end
Meta Generator 已经编写完成,可以测试了.
cd your_rails_project
vi Gemfile # 添加 "gem 'meta_generator_demo', path: 'your_workspace/meta_generator_demo'" 到 Gemfile 里面,不包含 " 符号.
bundle install
bundle exec rails g # 是不是可以看到 meta_generator_demo 这个选项了?
bundle exec rails g meta_generator_demo Demo
bundle exec rails g # 是不是可以看到 demo 这个选项了?
bundle exec rails g demo # 是不是可以看到 demo 这个选项了?
cat app/models/demo.rb # 最终生成的文件, 如果需要改 demo.rb 生成的内容,只需要改 Rails 项目里的 lib/generators/demo_generator.rb 文件即可.
总结
- Gem 的 lib/generators/meta_generator_demo/meta_generator_demo_generator.rb 文件有个 create_demo_file 方法, 此方法在你的 Rails 项目生成 lib/generators/demo_generator.rb 文件.
- 生成的 lib/generators/demo_generator.rb 文件有个 create_demo_file 方法,此方法创建了 app/models.demo.rb 文件.
Rails Admin Generator 示例
示例项目: https://github.com/adminonrails/aor
此项目已经弃坑,作为示例提供参考. 抛砖引玉,希望高手们能定制出更加适合自己的方案
挖了这个坑,后面因为做的项目都是前后端分离,就没有再填了. 另外觉得这个项目也比较鸡肋,对新手不友好,上手和定制有点难度.对高手来说,有自己的一套方式,一般是自己挖个坑.
大部分功能都有写单元测试,项目有在生产环境使用过.
项目介绍:
- bootstrap: bootstrap 的静态资源,无 sass 依赖.
- authentication: 提供登录验证的一些辅助方法,源码就一个文件. 主要提供 logged_in?, current_user 等方法. 参考老版 publify .
- authorization: 基于 cancancan 提供后台权限验证的一些辅助方法. 主要基于 controller_name 和 action_name 来限制. 参考 spree 的后台验证逻辑.
- theme: 代码生成器
使用请参考 test 和 dummy 目录测试代码.
theme 详解:
https://github.com/adminonrails/aor/blob/master/theme/Rakefile
上文件 DummyGenerator 部分,是一个新 rails 项目使用 aor 的主要流程, 这里是用来每次运行 dummy rails 测试项目,先生成最新的 aor 代码.
- 生成 kaminari 的 bootstrap3 模板.
- 添加 cancan 的 AdmAbility 文件.
- 运行 aor:theme
- 生成 admin user model.
https://github.com/adminonrails/aor/blob/master/theme/lib/generators/aor/theme/theme_generator.rb
上文件主要在安装了 aor-theme gem,运行 aor:theme 命令的代码.
- 复制 admin js 和 css 文件.
- 添加公共的头部,侧边,表单验证错误提示文件.
- 添加 base admin controller 和 helper 文件.
- 把 admin.js 和 admin.css 添加到 assets 里,这样编译 js 和 css 会单独生成 admin 文件.
- 生成表单验证错误提示的 bootstrap 样式. 6 复制项目的 admin generator 到当前 rails 的 lib/generators 目录.
https://github.com/adminonrails/aor/tree/master/theme/lib/generators/aor/theme/templates/generator
此目录的文件,主要增强 rails 自带的 scaffold, scaffold_controller . 我们不覆盖 rails scaffold,只是添加一个自己的 admin:scaffold . 使用时运行 rails g admin:scaffold .
里面的 rb 文件逻辑,主要是修改 scaffold 的 source_paths 路径,优先使用我们的 controller 和 views 模板.
子目录 erb 和 rails 即是模板.
总结
此项目混合两种方式,一种是通过代码继承,子类通过重写父类方法来实现自定义.一种是生成代码,再修改生成的生成器代码,来实现自定义.