为什么before_create回调覆盖创建! PARAMS?

时间:2017-03-10 08:47:16

标签: ruby-on-rails rails-activerecord

这段代码让我抓狂。不应该通过create!方法设置的padding方法覆盖set_padding值内传递参数吗?

Banner.create!(padding: {left:100, right: 200, top:300, bottom: 400})
  

插入"横幅" (" padding"," created_at"," updated_at")VALUES   ($ 1,$ 2,$ 3)返回" id" [["填充&#34 ;,   "的 {\"顶部\":20,\"底部\":25,\"左\":60, \"对\":60} "],[" created_at",   " 2017-03-10 08:37:00.183376"],[" updated_at"," 2017-03-10   08:37:00.183376"]]

正如您所见,感谢before_create回调,创建了另一个padding值的记录。为什么before_create会覆盖我传递的参数?我认为首先调用before_create回调,然后执行create!,因此 - 覆盖之前由before_create修改的模型属性......

# == Schema Information
#
# Table name: banners
#
#  id                  :integer          not null, primary key
#  padding             :text

class Banner < ActiveRecord::Base
  serialize :padding, JSON
  before_create :set_padding

  def set_padding
        self.padding = { top: 20, bottom: 25, left: 60, right: 60 }
    end
end

3 个答案:

答案 0 :(得分:1)

好吧,我调试了Rails行为。

def set_padding
  byebug # <----
  self.padding = { top: 20, bottom: 25, left: 60, right: 60 }
end

在此byebugself.padding设置为{left:100, right: 200, top:300, bottom: 400},但正如您猜测的那样 - 它下方的一行会将其覆盖为另一个值......

所以我的解决方案很简单 - 如果将self.padding设置为某种内容,请不要执行此方法。

更具体地说,我改变了这一行:

before_create :set_padding

到此:

before_create :set_padding, :if => lambda { |banner| banner.padding.nil? }

答案 1 :(得分:1)

  

我认为首先调用before_create回调,然后执行create!,因此 - 覆盖以前由before_create修改的模型属性。

不,你的理解是错误的。使用before_create方法create!回调实际上无事可做。例如,它也将在此处调用:

banner = Banner.new(...)
banner.save
在将对象即将保存到数据库之前调用

before_save / before_create。这是修改/按摩数据或中止操作的最后机会。

答案 2 :(得分:0)

<强> before_create:

在db中保存新对象之前将调用

。当此方法返回false时,将通过回滚来阻止创建。

因此,当你需要做一些事情,比如在保存之前检查一些不适合验证的东西,你可以在before_create中使用它们。

例如:在创建新工人之前请求Master获得许可。

<a href="/project">Home</a>

另一个用途是你要在保存之前格式化一些属性,如大写名称等。

<强> after_create:

第一次在数据库中保存对象后调用。就在你不想中断创作而只是记下创作或在创作后触发某些东西时,这很有用。

例如:在创建具有角色mod的新用户之后,我们想要通知其他mod

before_create :notify_master
def notify_master
  # notify_master via ipc and 
  # if response is true then return true and create this successfully
  # else return false and rollback
end