我最近有一个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
的错误?我从根本上误解了什么吗?
谢谢!
答案 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
方法中出现错误。