多次创建调用before_save

时间:2017-02-26 07:11:25

标签: ruby-on-rails ruby-on-rails-4 rails-activerecord

我的模型中有一个before_save回调函数,它在将2个字段保存到数据库之前对其进行加密。

aggregate(V2 ~V1, rbind(df1, df2), FUN = sum)
#       V1 V2
#1    Anna 30
#2 Charlie 30
#3   Julia 60
#4     Tom 80

情况与Devise models run before_save multiple times?非常相似。当我调用Model.create!(...) - 其中包含需要加密的2个字段时,before_save会被调用两次,最后会被加密两次。

class Account < ActiveRecord::Base
  before_save :encrypt_credentials, if: "!username.blank? && !password.blank?"

  def encrypt_credentials
    crypt = ActiveSupport::MessageEncryptor.new(ENV['KEY'])
    self.username = crypt.encrypt_and_sign(username)
    self.password = crypt.encrypt_and_sign(password)
  end

  def decrypted_username
    crypt = ActiveSupport::MessageEncryptor.new(ENV['KEY'])
    crypt.decrypt_and_verify(username)
  end

  def decrypted_password
    crypt = ActiveSupport::MessageEncryptor.new(ENV['KEY'])
    crypt.decrypt_and_verify(password)
  end
end

为什么before_save被多次调用?我不喜欢上面链接的帖子的解决方案,我不想做新的/ build然后保存。

2 个答案:

答案 0 :(得分:1)

这是用户错误:(在调用account = Account.create!之后,我有其他代码,名为save!返回模型:account.foo = bar; account.save!。这显然再次称为befor_save并重新加密我的字段。我最终得到了这样的东西:

GET https://{instance}/DefaultCollection/{project}/{team}/_apis/work/TeamSettings/Iterations/{iterationid}/Capacities?api-version={version}

GET https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/Fabrikam-Fiber/_apis/work/teamsettings/iterations/2ec76bfe-ba74-4060-970d-4567a3e997ee/capacities?api-version=2.0-preview.1 

{
  "values": [
    {
      "teamMember": {
        "id": "8c8c7d32-6b1b-47f4-b2e9-30b477b5ab3d",
        "displayName": "Chuck Reinhart",
        "uniqueName": "fabrikamfiber3@hotmail.com",
        "url": "https://fabrikam-fiber-inc.vssps.visualstudio.com/_apis/Identities/8c8c7d32-6b1b-47f4-b2e9-30b477b5ab3d",
        "imageUrl": "https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=8c8c7d32-6b1b-47f4-b2e9-30b477b5ab3d"
      },
      "activities": [
        {
          "capacityPerDay": 0,
          "name": null
        }
      ],
      "daysOff": [],
      "url": "https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/6d823a47-2d51-4f31-acff-74927f88ee1e/748b18b6-4b3c-425a-bcae-ff9b3e703012/_apis/work/teamsettings/iterations/2ec76bfe-ba74-4060-970d-4567a3e997ee/capacities/8c8c7d32-6b1b-47f4-b2e9-30b477b5ab3d"
    }
  ]
}

答案 1 :(得分:0)

选项1(使用回调可能会出错):

简短答案:使用after_save代替before_save

长答案:How to organize complex callbacks in Rails?

使用时:

account = Account.new

account.save

您每次都触发before_save钩子。

选项2(可能是错误):

也许您实际上是在多次触摸唱片。

例如:

def create
  @account = Customer.find(params[:customer_id]).accounts.create(account_params)

  if @account.save
    redirect_to customer_account_path(@account.customer.id, @account.id)
  else
    render :new
  end
end

实际上,您正在通过创建和保存来触摸它。在这种情况下,我建议:

def create
  @account = Customer.find(params[:customer_id]).accounts.build(account_params)

  if @account.save
    redirect_to customer_account_path(@account.customer.id, @account.id)
  else
    render :new
  end
end

Build不会尝试保存记录,因此您不会再遇到任何问题。希望这可以帮助!祝你有美好的一天!