gpt4 book ai didi

ruby-on-rails - rails 中的 Controller 构造函数参数?

转载 作者:行者123 更新时间:2023-12-04 16:00:04 24 4
gpt4 key购买 nike

我们如何在 Controller 的构造函数中注入(inject)参数或者 Rails 中依赖注入(inject)的原理是什么?

假设我需要将支付服务注入(inject) Controller 。在 .NET 世界中,我会使用 DI 框架,将其配置为为 IPaymentService 依赖项注入(inject) CreditPaymentService 实例。

在 rails 中,我们如何实现这一点?特别是对于测试和模拟?

我读到多个来源表明我们不需要任何 DI 框架来在 ruby​​ 中完成 DI 但我不知道如何为 Controller 做这件事?

谢谢!

// .NET
public class OrderController : Controller
{
IPaymentService _paymentService;

public OrderController(IPaymentService paymentService)
{
_paymentService = paymentService;
}

public object Pay(Order order)
{
_paymentService.process(order.GetTotal());
}
}

# Rails
class order_controller < ApplicationController

def initialize(payment_service)
@payment_service = payment_service
end

def pay
order = request.parameters(:order)
@payment_service.process(order)
end
end

最佳答案

试一试:

class OrdersController < ApplicationController

def pay
# you'll need to define payment_params elsewhere in the controller
PaymentService.call(payment_params)
end

end

PaymentService 只是一个普通的旧 ruby​​ 对象:

class PaymentService

attr_accessor *%w(
options
).freeze

class << self

def call(options={})
new(options).call
end

end # Class Methods

#==========================================================================
# Instance Methods
#==========================================================================

def intialize(options={})
@options = options
end

def call
# do stuff
# return something
end

end

我个人喜欢让 call 成为一个类方法,这样我就不必做:

PaymentService.new(payment_params).call

这对我来说看起来不太干净。但是,这纯粹是个人喜好问题。

你可以把它放在:

app
|- ...
|- services
| |- payment_service.rb
|- ...

这将导致服务自动加载,您将不必使用 config.autoload_paths

测试服务很简单(这就是重点,不是吗?)。这是一个 rspec 示例:

require 'rails_helper'

RSpec.describe PaymentService do
before(:all) do
@method_name = "call"
end
describe "#call" do
it "responds" do
expect(described_class.respond_to?(@method_name)).to be_truthy
end
context "when using good params" do
before(:each){ @params = good_params }
it "does something" do
expect(calling_the_service).to do_something
end
end
end
end

def calling_the_service
described_class.send method_name, params
end

def good_params
{some: :arguments}
end

def params
@params
end

def method_name
@method_name
end

事实上,我做的更像是:

class ApplicationController < ActionController::Base
# I have a custom module that lets me make this call. Among other things,
# it creates the call_service method on all controllers.
acts_as calling: :services
end

OrdersController 现在知道如何call_service:

class OrdersController < ApplicationController

def pay
# Given the acts_as calling: :services call, above, the OrdersController
# knows how to inspect the SERVICE_DETAIL constant on PaymentService
# and construct the appropriate arguments. In this case, passing in
# something like {current_user: 1}
call_service PaymentService
end

end

我将一些东西移动到 ServiceBase 中:

class ServiceBase 

attr_accessor *%w(
options
).freeze

class << self

def call(options={})
new(options).call
end

end # Class Methods

#======================================================================
# Instance Methods
#======================================================================

def intialize(options={})
@options = options
end

private

# This method reads the REQUIRED_ARGS AND REQUIRED_VALUES constants
# and determines whether a valid service call was made. It also logs
# errors so that I can go back and see failures.
def good_to_go?
# some stuff
end

def decorated_options
@decorated_options ||= OptionsDecorator.new(options)
end

end

现在我以常量形式在服务上声明一些元数据。它们本质上定义了服务的接口(interface):

class PaymentService < ServiceBase

SERVICE_DETAILS = [
{current_user: [:id]}
].freeze

REQUIRED_ARGS = %w(
current_user
).freeze

REQUIRED_VALUES = %w(
current_user_id
).freeze

delegate *%w(
current_user_id
), to: :decorated_options

#======================================================================
# Instance Methods
#======================================================================

def call
raise unless good_to_go?
# do stuff
# return something
end

end

关于ruby-on-rails - rails 中的 Controller 构造函数参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50767403/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com