【问题标题】:Rails: Save data in two tablesRails:将数据保存在两个表中
【发布时间】:2014-09-12 14:58:02
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    您可能会发现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 时,usersetting 都会被保存,并且都发生在事务中。

    【讨论】:

    • 至少你醒悟过来,避免了严格的交易方式。使用此实现,您需要注意不要在每次实例化时都这样做,但每次都会设置 init_user_setting。首先检查模型是否是新模型,但此时您基本上是在实现 after_create 。并且用户不应该属于某个设置。
    • @CleoR,感谢您的评论。我不确定我是否完全理解第一句话,您能否在“至少您意识到并避免严格的交易方法”中添加更多内容。没错,after_initialized 不仅在创建对象时被调用,而且是用户的实现。另外,感谢您在答案中指出belongs_to 问题。根据您的建议,我已将其更改为 has_one
    • 对不起,这是给 OP 的!我想我对我们的聊天有点生气。他完全无视我在说什么,但我猜他改变了主意。很抱歉造成混乱。
    • @CleoR,完全不用担心。我只是想更多地了解“避免严格的交易方法”。没有难过的感觉,保持冷静的人! :)
    • @CleoR 你很生气所以对这个问题投了反对票?太棒了!顺便说一句,我是决定选择适合我的问题的答案的人。无论如何,您都不能强迫接受答案,除非它只是正确的答案。然而,即使你的答案是正确的,它似乎只是为了答案而工作。
    【解决方案2】:

    您可以同时使用after_create 回调或观察者。两者都会好的。但是您还应该在属性分配的初始化方法中设置默认值。或者您也可以在保存调用后使用用户的创建方法来执行相同的操作。但这不是一个好方法。所以更喜欢 call_back 或观察者。

    【讨论】:

      【解决方案3】:

      --更新--

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

      整个回调链被包装在一个事务中。如果任何 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。如果没有设置,您将没有用户。

      【讨论】:

      猜你喜欢
      • 2014-10-27
      • 1970-01-01
      • 2016-02-18
      • 1970-01-01
      • 2019-08-15
      • 2013-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多