【发布时间】:2014-09-12 14:58:02
【问题描述】:
我有一个 user 表和一个具有 1-1 关系的 setting 表。我想为新创建的用户插入一些默认设置。我正在考虑使用用户的after_create 回调。但是,我不确定这是否是事务性的。这种情况的最佳方法是什么?
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-4 transactions
我有一个 user 表和一个具有 1-1 关系的 setting 表。我想为新创建的用户插入一些默认设置。我正在考虑使用用户的after_create 回调。但是,我不确定这是否是事务性的。这种情况的最佳方法是什么?
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-4 transactions
您可能会发现after_initialize 回调对于为user 构建setting 对象和分配默认setting 很有用。示例:
class User < ActiveRecord::Base
has_one :setting
after_initialize :init_user_setting
private
def init_user_setting
# Assign default setting or build
self.setting = ...
end
end
有了这个,您将拥有完整的父 user,包括孩子 setting。当您调用 user.save 时,user 和 setting 都会被保存,并且都发生在事务中。
【讨论】:
after_initialized 不仅在创建对象时被调用,而且是用户的实现。另外,感谢您在答案中指出belongs_to 问题。根据您的建议,我已将其更改为 has_one!
您可以同时使用after_create 回调或观察者。两者都会好的。但是您还应该在属性分配的初始化方法中设置默认值。或者您也可以在保存调用后使用用户的创建方法来执行相同的操作。但这不是一个好方法。所以更喜欢 call_back 或观察者。
【讨论】:
--更新--
当您开始为模型注册新回调时,它们将排队等待执行。此队列将包括您模型的所有验证、注册的回调和要执行的数据库操作。
整个回调链被包装在一个事务中。如果任何 before 回调方法完全返回 false 或引发异常,则执行链将停止并发出 ROLLBACK; after 回调只能通过引发异常来实现。
在 before_save 回调结束时将属性设置为 false 后,我终其一生都无法弄清楚为什么对象永远不会保存!回调之前必须返回真值,否则会回滚。
--上一个--
你需要做这样的事情。这是我处理货币以外的任何事情的默认方法。
class User < ActiveRecord::Base
has_one :setting
after_create :setup_user
private
def setup_user
user_settings = self.setting.new
user_settings.attr1 = foo1
user_settings.attr2 = foo2
user_settings.save
end
end
class Setting < ActiveRecord::Base
belongs_to :user
end
理想情况下,您应该对用户进行验证并进行验证,这样如果用户有效,则设置也有效。但是如果你不这样做,你需要使用
if !user_settings.save
self.destroy
end
对于默认值的放置位置,如果设置默认值取决于用户,请将它们粘贴在 setup_user 方法中。如果设置默认值不关心用户,请将它们粘贴在设置的 before_save 或 before_validation 方法中。关于用户,您需要在用户未验证的情况下使用 after_create 方法,您希望这些回调仅在成功创建用户时触发。您不想使用 after_validation 用户,因为不会创建用户,并且如果设置包含尚未创建的用户的外部 id,那么您的数据库将立即不一致。
基于事务的方法
class User < ActiveRecord::Base
has_one :setting
after_commit :setup_user, on: [:create]
after_rollback :undo_user, on: [:create]
private
def setup_user
user_settings = self.setting.new
user_settings.attr1 = foo1
user_settings.attr2 = foo2
user_settings.save!
end
def undo_user
#The users settings didn't save so roll back the user
self.destroy
end
end
class Setting < ActiveRecord::Base
belongs_to :user
end
要将其放在同一个事务中,您需要使用 after_commit 和 after_rollback。使用 .save!将抛出异常并触发 after_rollback。如果没有设置,您将没有用户。
【讨论】: