Rails服务对象,向新模型添加错误

时间:2014-09-12 20:01:42

标签: ruby-on-rails ruby web-services ruby-on-rails-4 refactoring

我最近有一个rails模型,它有几个回调就像这样:

class Model < ActiveRecord::Base

  before_validation :fetch_posts
  after_create :build_posts

  def fetch_posts
    fetch_collection
  rescue MyException => e
    self.errors.add(:post, e.message)
  end

  def build_posts
    fetch_collection.each do |item|
      DifferentModel.build(item)
    end
  end

  def fetch_collection
    @collection ||= method_that_fetches_collection_from_external_source
  end
end

这工作得很好,但是编写测试非常困难,因为每当我想创建一个Model时,我就必须将所有回调都存根。输入服务对象:

class ModelFetcher

  attr_reader :model

  def initialize(model)
    @model = model
  end

   def save
     model.fetch_posts
     if model.save
       model.build_posts
       return true
     else
       return false
     end
  end
end

我现在看到的问题,在模型确实包含错误的情况下(来自fetch posts方法),它不会被转移到model.save来电SO。也就是说,Model.new有错误,但是当我在.save上调用Model.new时,它不会保留错误并且模型会正确保存。

我考虑添加validate :fetch_posts,但后来我回到了以前的状态,因为这实际上是一个回调。

关于如何更好地构建这个的任何建议?是否可以保持Model.new.save的错误?我从根本上误解了什么吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

这是一个替代解决方案,即覆盖run_validations!,因为你没有。

class Model < ActiveRecord::Base
  after_create :build_posts

  def fetch_posts
    fetch_collection
    rescue MyException => e
      self.errors.add(:post, e.message)
  end

  def build_posts
    fetch_collection.each do |item|
      DifferentModel.build(item)
    end
  end

  def fetch_collection
    @collection ||= method_that_fetches_collection_from_external_source
  end
private
  def run_validations!
    fetch_posts
    errors.empty?
  end
end

通常这种方法看起来像

def run_validations! 
  run_callbacks :validate
  errors.empty?
end

但由于您没有经过验证,因此应在#save上提供类似用途。

或者,正如我在评论中建议的那样,您可以将save替换为model.errors.any?,因为save会清除fetch_posts设置的原始错误,但errors.any?会检查如果在fecth_posts方法中出现错误。