Trailblazer 简介
Trailblazer 位于Rails顶端,是,thin web 服务器的一个层(layer)。它温和的实施封装,有直观的代码结构,并且提供面向对象的架构。
坚果壳内:trailblazer允许你跟操作数据对象一样编写无逻辑模块,不包含回收,嵌套,验证或域逻辑。它通过提供一些附加层移除bulky controllers和strong_parameters来承载代码并完全取代helpers。
请支持我即将出版的新书 Trailblazer - A new architecture for Rails,免费阅读样章,让我知道你的想法。
书中讨论了demo application工具。
使命
开拓者(Trailblazer)为您在Rails的各个方面提供Ruby抽象层,它不传教你。只要你愿意,你可以回退到“Rails通道”模型,单片控制器,全局佣工等,这是不是一件坏事,但让你分步介绍开拓者的封装在你的应用程序,而无需重写它。
Trailblazer是所有关于结构。它有助于重新组织现有的代码放到哪里不同的关注点在分离类处理更小的组件。形式进入表单对象,视图是面向对象的MVC控制器,业务逻辑发生在通过完全脱钩的持久性对象支持专用的域对象。
同样,你可以选择你想要的图层。开拓者并没有对技术的实现,它提供了经常性在所有类型的Rails应用程序的问题,成熟的解决方案。
Trailblazer没有“对象和间接的复杂的网络。”它解决了已经存在多年了干净的分层架构的许多问题。只使用你喜欢什么。这就是底线。
OOP 概念框架
Trailblazer提供你一个新的,更直观的文件布局在Rails应用程序中,您文件的结构概念 。
app ├── concepts │ ├── comment │ │ ├── cell.rb │ │ ├── views │ │ │ ├── show.haml │ │ │ ├── list.haml │ │ ├── assets │ │ │ ├── comment.css.sass │ │ ├── operation.rb │ │ ├── twin.rb
文件、类和视图逻辑上属于一个 概念 保存在一个地方。 你可以自由使用其他名称空间中的一个概念。 开拓者试图保持尽可能简单,。
体系结构
Trailblazer扩展了传统的MVC Rails堆栈。 记住,添加层并不一定意味着添加更多的代码和复杂性。
相反的情况:控制器、视图和模型成为精益HTTP端点,渲染和持久性。冗余代码被投入很少的应用程序代码消除正确的层。
Routing(路由)
Trailblazer使用Rails的路由URL映射到控制器(我们将添加到简化路由推出)。
Controllers(控制器)
控制器是瘦终端的HTTP。它们分化请求的格式,如HTML或JSON之间并立即派遣一个操作。控制器不包含任何业务逻辑。
Trailblazer提供了四种方法来呈现和调用操作。但在这之前,你需要包括Controllers 模块。
class CommentsController < ApplicationController include Trailblazer::Operation::Controller
Rendering the form object(喧染表对象)
操作可以填充,并展示他们的表单对象,因此它可以与simple_form和其他形式的助手使用。
def new form Comment::Createend
这将运行操作,但不是它的validate验证码。它在控制器然后设置@form实例变量,因此它可以被渲染。
= form_for @form do |f| = f.input f.body
#form 是指对象#new和#edit,只有HTML有动作。
运行操作
如果你不打算保留不同要求的格式,最简单的就是用#run来操作处理输入数据。
def create run Comment::Createend
这只需运行Comment::Create[params].
你也可以传递你自己的参数。
def create run Comment::Create, params.merge({current_user: current_user})end
一个额外的块将被执行仅当操作结果是有效的。
def create run Comment::Create do |op| return redirect_to(comments_path, notice: op.message) endend
注意该动作的实例是产生的块。
一个无效的响应的情况下可以在块之后进行处理。
def create run Comment::Create do |op| # valid code.. return end render action: :newend
不要忘了,从有效块return,否则既有效块和无效的通话之后将被调用。
Responding(响应)
另外,您也可以使用Rails的出色#respond_with让一个响应处理所要渲染的。操作可以传递到respond_with。发生这种情况自动#respond,让Trailblazer调用操作的第三个方法。
def create respond Comment::Createend
这将只需运行操作和Chuck的情况下进入应答让后者梳理呈现了什么或者重定向。操作代表各自的调用其内部model。
你还可以在该块处理不同的格式。这是完全细做,在控制,因为这是端点的逻辑是HTTP特有的,而不是business。
def create respond Comment::Create do |op, formats| formats.html { redirect_to(op.model, :notice => op.valid? ? "All good!" : "Fail!") } formats.json { render nothing: true } endend
传递给#respond块总是执行,无论操作结果的有效性。目标是让响应处理操作的有效性。
formats对象只是传递到#respond_with。
Presenting(介绍)
对于#show模式行为,单纯使用HTML页面或JSON或XML文档的,#present方法就派上用场了。
def show present Comment::Createend
同样,这将只运行操作的设置,并提供了模型@model。然后,您可以使用cell或控制器视图HTML呈现模型。
对于基于文档的API和非HTTP请求类型的操作将被告知渲染操作使用申述的JSON或XML文档。
需要注意的是#present还将代替#form(允许它也在#new和#edit使用)作为响应将不会触发任何渲染。
Controller API(控制器API)
在这三种情况下的实例变量分配:@operation,@form,@model.
Operation(操作)
操作封装业务逻辑。每高一级域名的功能之一操作使用。不同的格式或环境的子类进行处理。操作对于HTTP无感知的。
class Comment < ActiveRecord::Base class Create < Trailblazer::Operation def process(params) # do whatever you feel like. self end endend
操作只需要执行#process从调用接收参数。
Call style(调用样式)
最简单运行的操作是调用样式。
op = Comment::Create[params]
使用Operation#[]将会返回该操作的实例,在无效操作的情况下,这将引发异常。
注意如何可以容易用于测试工厂。
let(:comment) { Comment::Create[valid_comment_params].model }
使用操作作为测试工厂是Trailblazer的基本概念,以消除冗余的buggy(越野车)在测试和手动工厂。
Run style(运行样式)
您可以手动运行的操作,并使用相同的块语义在控制器中。
Comment::Create.run(params) do |op| # only run when valid.end
当然,这并不抛出异常,而只是当操作无效时跳过该块。
Validations(验证)
操作通常有一个表单对象,它仅仅是一个Reform:: Form类。所有记录在Reform的API可以应用和使用。
该操作利用表单对象来使用#validate方法。
class Comment < ActiveRecord::Base class Create < Trailblazer::Operation contract do property :body, validates: {presence: true} end def process(params) @model = Comment.new validate(params[:comment], @model) do |f| f.save end end endend
该contract(又名表单)在::contract块中定义。可以实现嵌套形式,默认值,验证,以及其他一切Reform提供的。
该情况下的一个有效的形式为#validate块被调用。它接收填充表单对象。您可以使用表单来保存数据或写你自己的逻辑。
从技术上来说,真正发生在Operation#validate如下。
contract_class.new(@model).validate(params[:comment])
从Reform而言,这是一个熟悉的工作流程。验证与模型无关。
Models(模块)
模块的持久性可以用你喜欢的任何ORM来实现,比如ActiveRecord的或DataMapper的。
在Trailblaze,模块是完全空的,仅配置数据库相关指令和协议。没有业务逻辑是允许在车型。只有操作,视图和组件可以直接访问模块。
Views(视图)
查看渲染可以使用从Rails的知名控制器发生。这绝对是简单的视图。
更复杂的UI逻辑发生在视图模型的cells中发现的。视图模型替换助手。
1.HTTP API消费和渲染API文档(如JSON或XML)是通过轰鸣声和表示的完成。他们通常继承合同的模式。
2.测试待测试主要是操作和查看模型,因为它们封装你的应用程序的终结点行为。作为一个好的副作用,工厂通过简单的操作要求更换。
Controller API (控制器API)
Normalizing params
覆盖#process_params!添加或操作运行之前删除值PARAMS。这就是所谓的在#run,#respond和#present。
class CommentsController < ApplicationController # ..private def process_params!(params) params.merge!(current_user: current_user) endend
这集中PARAMS正常化,在每一个动作里,并不需要你手动。
Different Request Formats(不同的请求形式)
控制器的帮手#present和#respond自动通过request body(请求主体)进行操作并经由参数hash。由操作的建立者决定哪个类要实例化。
class Create < Trailblazer::Operation builds do |params| JSON if params[:format] == "json" endend
[注意,它很快就会提供一个模块。]
Operation API(操作API)
CRUD Semantics(增删改查语义)
你可以作为Trailblazer(先驱者)为你所使用的CRUD模型去查找和创建模型。
require 'trailblazer/operation/crud'class Comment < ActiveRecord::Base class Create < Trailblazer::Operation include CRUD model Comment, :create contract do # .. end def process(params) validate(params[:comment]) do |f| f.save end end endend
你必须告诉CRUD模型类,什么行为能实现使用::model。
注意你不必通过@modelto验证有效性。 而且, @model的被创建是自动化的并通过Operation#model访问。
在继承操作上,你可以重载方法, 并只要使用::action就好。
class Update < Create action :updateend
另一个操作是:find(它目前的做法和:update一样) 通过params[:id]这种方式找到模型。
后台处理
在Sidekiq (ActiveJob即将支持)中进行操作,你只需要包含Worker模块:
require 'trailblazer/operation/worker'class Comment::Image::Crop < Trailblazer::Operation include Worker def process(params)# 将会异步方式运行 endend
渲染操作表单
你可以通过::present来访问操作表单
Comment::Create.present(params)
上面代码,运行操作的#process方法,而不包含验证代码块,也不用返回约定(return the contract?)。
标记操作为无效
有时你不需要一个表单对象,但是需要操作的有效行为。
def process(params) return invalid! unless params[:id] Comment.find(params[:id]).destroy selfend
#invalid!在默认失效时返回自身,但是可以接受任意结果。
Worker::FileMarshaller: needs representable 2.1.1 (.schema)
测试操作
自动加载
如果不喜欢显式地require,你可以使用自动加载。
只需要将
require 'trailblazer/autoloading'
添加到config/initializers/trailblazer.rb,这样文件就会自动加载。
为何?
-
通过概念来组合代码、视图、资源,能提高应用的可维护性。直观的文件布局可以使开发者快速地了解应用的组织结构。
-
分层封装将测试组件完全隔离,这样调试起来不会那么烦恼了。一旦你确定表单和视图都是OK的,那问题肯定在解析的代码里。
-
Trailblazer慢慢地推动你进行封装,这促使代码的可重用性不断提升。不再有冗余的helper,取而代之的是简洁的继承。
-
(使用Trailblazer)从此再也不怕被ActiveRecord的大量API惊吓住。持久性和领域的分离自然地使模型的API更小、更非破坏性。