在这种Rails情况下使用的最佳Ruby模式是什么?

时间:2009-07-28 08:52:28

标签: ruby-on-rails ruby design-patterns

网站的互动基于用户的输入。例如,如果用户选择“VISA”作为支付方式,他将被重定向到另一个要求信用卡号的控制器/动作。如果用户选择“Paypal”,则他/她将被重定向到外部网站。

为了可扩展性,我不是将所有逻辑放在动作本身中,而是考虑在对象中抽象它。实施例。

class Payment < ActiveRecord::Base; end
class VisaPayment < Payment
  def process
    ... 
  end
end
class PaypalPayment < Payment
  def process(controller)
    ...
    controller.redirect_to "http://paypal.com"
  end
end


class OrdersController < ApplicationController
  def accept
    params[:select].constantize.new.process(self)
  end
end

这不起作用,因为像“redirect_to”这样的方法受到保护。这种代表团有成语或共同模式吗?

P.S。上面的代码是真正的想象力,而不是任何实际编码的摘录

3 个答案:

答案 0 :(得分:1)

将控制器和模型逻辑分开。你以后会感谢我。

class OrdersController < ApplicationController
  def accept
    payment_path = case params[:select]
      when 'visa': credit_card_controller_path(payment_type)
      when 'paypal': 'http://www.paypal.com'
    end

    redirect_to payment_path
  end
end

我喜欢这种方法的是它具有可读性和表现力。你确切知道发生了什么。代码并不比必要的更聪明。

答案 1 :(得分:0)

我会把它放到一个模块中并通过case-switch执行正确的方法:

case credit_card_system:
when "VISA" then: VisaToolbox::ExecuteTransaction(params)
when "MasterCard" then: MasterCardToolbox::ExecuteTransaction(params)
else
...
end

我会将其他东西放在一个控制器中......

答案 2 :(得分:0)

我不喜欢使用调用控制器代码的ActiveRecord代码。但是,如果你必须这样做,我会在付款中创建一个类方法,我将定义你的“过程部分”,然后在控制器中将instance_eval定义为:

class Foo
  def self.define_process(&block)
    @process = block
  end

  def self.apply_to(controller)
    controller.instance_eval(&@process)
  end
end

class SpecificFoo < Foo
  define_process do
    puts self.bar
  end
end

class Something
  attr_accessor :bar
end

something = Something.new
something.bar = 42

SpecificFoo.apply_to(something)

请注意,define_process'slock / iterator / coroutine中的代码是通过自我指向某个东西(在你的情况下是控制器)执行的,你可以访问受保护的和私有的东西。