从类方法访问实例方法

时间:2015-04-29 15:47:16

标签: ruby-on-rails ruby

我有一个rails 4 app,它有一个警报模型和与每个警报相关的测试。

创建新警报时,我有一个after_create过滤器,它使用实例方法创建一个新测试:

class Alert < ActiveRecord::Base
    has_many :tests
    after_create :create_test

    private

    def create_test

    #bunch of code using external api to get some data  


     Test.create 

    end
end

我还有一个cron作业,我想用它来为每个警报创建一个新的测试。我的计划是有一个类方法来做到这一点:

def self.scheduled_test_creation
        @alerts = Alert.all
        @alerts.each do |a|
          a.create_test        
        end
    end

由于实例方法是私有的,因此无法工作。我知道我可以使用send来解决这个问题。或者我可以公开这些方法。或者我可以在实例方法中重写那一堆api代码。

我不确定最好的方法是什么。我不想两次写相同的代码,我想确保是好的做法。也许在这种情况下,这些方法不一定是私有的 - 我知道公共/私人/受保护之间的区别,但我并不真正理解何时方法应该是私有/受保护的。

非常感谢任何帮助

2 个答案:

答案 0 :(得分:2)

我喜欢多个模型之间交互的服务类。回调可能使逻辑很难遵循。

例如:

class AlertCreator
  def initialize(alert)
    @alert = alert
  end

  def call
    if @alert.save
      alert_test = TestBuilder.new(@alert).call
      alert_test.save
      true
    end
  end
end

class TestBuilder
  def initialize(alert)
    @alert = alert
  end

  def call
    # external API interaction stuff
    # return unsaved test
  end
end

在您的控制器中,您可以拨打AlertCreator.new(@alert).call而不是通常的@alert.save

答案 1 :(得分:0)

我同意@SergioTulentsev:虽然从长远来看,你可以通过将这个逻辑分解为服务类来提供更好的服务,在短期内你只需就不应该将方法设为私有它需要在实例之外调用。

在某些情况下,实际上想要访问私有方法,例如在测试期间验证对象状态时。这很容易做到:

@alert.instance_eval{ create_test }

您甚至可以通过这种方式获取或更改实例变量:

@alert.instance_eval{ @has_code_smells = true }

一般来说,如果你觉得有必要这样做,那就是一种警告气味,你的逻辑需要重新考虑。忽略那种气味是将Ruby从一种美妙的语言变成一种过于强大的语言,让你可以用脚射击自己。但它是可行的。