ActiveRecord异常不会丢弃在服务对象

时间:2018-05-09 16:32:52

标签: ruby-on-rails ruby

在构建服务对象时,应该没有抛出RecordInvalid异常。相反,每次都会运行else块中的代码。

# services/new_registration_service.rb
class NewRegistrationService

  ...  

  def perform    
    begin
      account_create
    rescue ActiveRecord::RecordInvalid => exception
      OpenStruct.new(success?: false, user: user, account: account, error: exception.message)
    else
      # this is running every time
      OpenStruct.new(success?: true, user: user, account: account, error: nil)
    end
  end

  private

    ...

    def account_create
      # this is NOT saving, which I believe should
      # throw the exception in the perform method
      post_account_setup if account.save
    end

    ...

end

这就是我在我的规范中运行的内容,其中需要account: name

post :create, params: { account: FactoryBot.attributes_for(:account, { name: nil }) }

即使我puts返回了account.name值,它也是nil ...这应该是RecordInvalid例外的原因。

# models/account.rb
class Account < ApplicationRecord
  resourcify
  has_many :users
  validates :name, presence: true
end

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

def account_create
  # Instead of this:
  post_account_setup if account.save

  # Do this:
  account.save!
  post_account_setup
end

调用save代替save!不会引发异常;它只会返回false

或者,有人会争辩说使用异常来控制这样的流程是不好的做法。所以相反,你可以这样做:

def perform
  # ...
  if account.valid?
    account.save! # This should never fail!
    post_account_create
    OpenStruct.new(success?: true, user: user, account: account, error: nil)
  else
    OpenStruct.new(success?: false, user: user, account: account, error: account.errors)
  end
end

或者,类似地:

def perform
  # ...
  if account.save
    post_account_create
    OpenStruct.new(success?: true, user: user, account: account, error: nil)
  else
    OpenStruct.new(success?: false, user: user, account: account, error: account.errors)
  end
end

答案 1 :(得分:1)

你可以简单地在一行中处理这个(为了便于阅读,这里分为两个):

def perform   
  OpenStruct.new(success?: account.save, user: user, 
                 account: account, error: account.errors)
end

IF post_account_create可以转移到模型中,我建议它是more natural home for it,即

<强> account.rb

after_create :post_account_create

有关生命周期的更多信息here

如果没有任何内容,

account.errors将返回一个空数组,根据其空虚或响应的成功情况,其他地方难以处理。

希望这很有用。