【问题标题】:callbacks on active record associations活动记录关联的回调
【发布时间】:2011-06-23 20:24:08
【问题描述】:

我有一个 has_many :entries 的假期批准模型,如果我销毁其中一个条目以销毁其余条目,有没有办法?如果是,我也想发送一封电子邮件,但不是每个条目都发送一封。有没有办法观察整个集合的变化?

【问题讨论】:

    标签: ruby-on-rails activerecord callback one-to-many


    【解决方案1】:

    回调可能不是一个好的选择,因为:

    class Entry < ActiveRecord::Base
      def after_destroy
        Entry.where(:vacation_id => self.vacation_id).each {|entry| entry.destroy}
      end
    end
    

    会产生一些不好的递归。

    这可能是你应该在控制器中进行:

    class EntriesController < ApplicationController
      def destroy
        @entry = Entry.find(params[:id])
        @entries = Entry.where(:vacation_id => @entry.vacation_id).each {|entry| entry.destroy}
        #send email here
        ...
      end
    end
    

    【讨论】:

    • 或者“@entry.vacation.entries.destroy_all”会更干净
    • 是的,我认为必须在控制器中执行此操作,只需删除设置为 :depoendent => destroy 的父 VacationApproval
    【解决方案2】:

    您可以使用before_destroy 回调。

    class VacationRequest < ActiveRecord::Base
      has_many :entries
    end
    
    class Entry < ActiveRecord::Base
      belongs_to :vacation_request
      before_destroy :destroy_others
      def destroy_others
        self.vacation_request.entries.each do |e|
          e.mark_for_destruction unless e.marked_for_destruction?
        end
      end
    end
    

    在将代码用于任何重要的事情之前,一定要对其进行测试,但它应该为您提供一些开始的方向。

    【讨论】:

    • 我想过这个问题,但是不会对每个调用 entry.destroy_all 调用 before_destroy 只会导致无限递归吗?
    • 使用(希望)更好的策略进行编辑。
    • 文档说mark_for_destruction 只对 :autosave 有用,所以当我看到 :dependent => destroy 会发生什么时,我试试看
    • 好的,请致电:autosave。不过要小心你把:dependent =&gt; :destroy放在哪里。您是否希望 VacationRequest 本身在其任何条目被销毁时也被销毁?
    【解决方案3】:

    我认为这应该可行:

    class Entry < ActiveRecord::Base
      belongs_to :vacation_request, :dependent => :destroy
    
      # ...
    end
    
    class VacationApproval < ActiveRecord::Base
      has_many :entries, :dependent => :destroy
    
      # ...
    end
    

    应该发生的是,当一个条目被销毁时,关联的 VacationApproval 将被销毁,随后其所有关联的条目将被销毁。

    让我知道这是否适合你。

    【讨论】:

    • 我在VacationApproval 中有它,但不是Entry.. 如果有一个条目不属于一个条目怎​​么办?会不会被允许存在。只有少数人实际上拥有与他们相关的 VacationApproval。
    • 我希望这行得通,但是 :dependent 只是 has_many 的一个选项,而不是 belongs_to (至少在 Rails 2.3 中)
    • 不错,松散的加农炮。不过,其他一些答案似乎可以解决您的问题。
    【解决方案4】:

    所以我最终做的是

    class VacationApproval < ActiveRecord::Base
      has_many :entries , :conditions => {:job_id => Job.VACATION.id }, :dependent => :nullify
    
    class Entry < ActiveRecord::Base
      validates_presence_of :vacation_approval_id ,:if => lambda {|entry| entry.job_id == Job.VACATION.id} , :message => "This Vacation Has Been Canceled. Please Delete These Entries."
    

    然后

    @entries.each {|entry| entry.destroy if entry.invalid? }
    

    在我的控制器的索引操作中。 和

    `raise "Entries are not valid, please check them and try again ( Did you cancel your vacation? )" if @entries.any? &:invalid?` 
    

    在提交操作中

    同时删除其他人的问题是,如果我的 UI 进行 10 次 Ajax 调用以选择 10 行,并且在我第一次以 9 个未处理的 404 响应结束时将其全部删除,这是不可取的。

    既然我不在乎,它们就留在那儿,只要不能提交条目就可以了。

    这对我来说是最简单/最安全/递归友好的方式,但可能不是最好的方式。感谢你的帮助!

    【讨论】:

      【解决方案5】:

      致任何好奇/寻求信息的人

      我后来通过这样设置 The Vacation APProval 模型解决了这个问题

      class VacationApproval < ActiveRecord::Base
          has_many :entries , :conditions => {:job_id => Job.VACATION.id }, :dependent => :delete_all
      end
      

      和我这样的入口模型

      class Entry < ActiveRecord::Base  
        after_destroy :cancel_vacation_on_destory
        def cancel_vacation_on_destory
          if !self.vacation_approval.nil?
            self.vacation_approval.destroy
          end
        end
      end
      

      使用 :delete_all 不会处理回调,它只是删除它们

      【讨论】:

        猜你喜欢
        • 2016-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多