假设你有一个
ServiceBase
看起来像这样:
# services/service_base.rb
class ServiceBase
attr_accessor :args,
:controller
class << self
def call(args={})
new(args).call
end
end # Class Methods
#======================================================================
# Instance Methods
#======================================================================
def initialize(args)
@args = args
end
private
def params
controller.params
end
def assign_args
args.each do |k,v|
class_eval do
attr_accessor k
end
send("#{k}=",v)
end
end
end
Tasks::NewService
# services/tasks/new_service.rb
class Tasks::NewService < ServiceBase
def call
assign_args
@haser = haser_klass.find(haser_id)
@haser.tasks.new
end
private
def haser_klass
haser_base.constantize
end
def haser_instance_name
haser_base.downcase
end
def haser_base
controller.class.name.split("::")[0].singularize
end
def haser_id
params["#{haser_instance_name}_id".to_sym]
end
end
然后,在控制器中,您应该能够执行以下操作:
# milestones/tasks_controller.rb
Milestones::TasksController < ApplicationController
def new
@task = Tasks::NewService.call(controller: self)
end
end
# projects/tasks_controller.rb
Projects::TasksController < ApplicationController
def new
@task = Tasks::NewService.call(controller: self)
end
end
如果你有
Tasks::CreateService
这看起来像:
# services/tasks/create_service.rb
class Tasks::CreateService < ServiceBase
delegate :render,
to: :controller
def call
assign_args
@haser = haser_klass.find(haser_id)
@task = @haser.tasks.new(task_params)
if @task.save
# create.js.erb
else
render js: "alert('error');" # example...
end
end
private
def task_params
send("#{haser_instance_name}_params")
end
def milestone_params
params.require(:milestone).permit(:foo)
end
end
然后,在控制器中,您应该能够执行以下操作:
# milestones/tasks_controller.rb
Milestones::TasksController < ApplicationController
def new
@task = Tasks::NewService.call(controller: self)
end
def create
Tasks::CreateService.call(controller: self)
end
end
# projects/tasks_controller.rb
Projects::TasksController < ApplicationController
def new
@task = Tasks::NewService.call(controller: self)
end
def new
Tasks::CreateService.call(controller: self)
end
end
如果在抽象之后,你的控制器有相同的方法,那么你可以开始做其他有趣的事情,比如have
Milestones::TasksController
和
Projects::TasksController
两者都继承自公共控制器,而不是
ApplicationController
TasksController
. 然后,您的控制器可能看起来像:
# tasks_controller.rb
TasksController < ApplicationController
def new
@task = Tasks::NewService.call(controller: self)
end
def create
Tasks::CreateService.call(controller: self)
end
end
# milestones/tasks_controller.rb
Milestones::TasksController < TasksController; end
# projects/tasks_controller.rb
Projects::TasksController < TasksController; end
现在,您只需要在一个地方进行更改:在您的服务中。当然,如果您不想使用这些服务,您总是可以重写控制器方法。