这段代码让我抓狂。不应该通过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
答案 0 :(得分:1)
好吧,我调试了Rails行为。
def set_padding
byebug # <----
self.padding = { top: 20, bottom: 25, left: 60, right: 60 }
end
在此byebug
行self.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