Rails:将数据保存在两个表中

时间:2014-09-12 14:58:03

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

我有一个user表和一个{1-1}关系的setting表。我想为新创建的用户插入一些默认设置。我想用after_create回调用户。但是,我不确定这是否是交易性的。这种情况的最佳方法是什么?

3 个答案:

答案 0 :(得分:2)

您可能会发现after_initialize回调对于为setting构建user对象并分配默认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时,usersetting都会被保存,并且都会在交易中发生。

答案 1 :(得分:0)

您可以使用after_create回调或观察者。两者都没问题。但是,您还应该在属性分配的initialize方法中为设置设置默认值。或者您也可以使用用户的create方法在保存调用后执行相同操作。但这不是一个好方法。所以更喜欢call_back或者观察者。

答案 2 :(得分:0)

- UPDATE -

当您开始为模型注册新的回调时,它们将排队等待执行。此队列将包括所有模型的验证,已注册的回调以及要执行的数据库操作。

整个回调链包含在一个事务中。如果在回调方法之前返回任何错误或引发异常,则执行链将停止并发出ROLLBACK;回调之后只能通过引发异常来实现。

在before_save回调结束时将属性设置为false后,我无法终身找出为什么对象永远不会保存!在回调之前必须返回truthy值或它将回滚。

- 上一页 -

你需要做这样的事情。这是我处理货币的默认方法。

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。没有设置,您将没有用户。