Rails: if has_many relationship changed

后端 未结 5 1503
借酒劲吻你
借酒劲吻你 2021-01-01 15:21

I\'ve got these two classes.

class Article < ActiveRecord::Base
  attr_accessible :body, :issue, :name, :page, :image, :video, :brand_ids
  has_many :pub         


        
5条回答
  •  离开以前
    2021-01-01 15:41

    A bit late, but for other people who are looking for a similar solution, you can detect changes in the Relationship (also has_and_belongs_to_many) on this way:

    class Article < ActiveRecord::Base
      attr_accessible :body, :issue, :name, :page, :image, :video, :brand_ids
      has_many :publications
      has_many :docs, :through => :publications
    end
    
    class Doc < ActiveRecord::Base
      attr_accessible :issue_id, :cover_id, :message, :article_ids, :user_id, :created_at, :updated_at, :issue_code, :title, :template_id
      has_many :publications, dependent: :destroy
      has_many :articles, :through => :publications, :order => 'publications.position'
      has_many :edits, dependent: :destroy
      accepts_nested_attributes_for :articles, allow_destroy: false
    
      after_initialize :initialize_article_changes_safe
    
      after_save :change_articles
      after_save :initialize_article_changes
    
      before_add_for_articles << ->(method,owner,change) { owner.send(:on_add_article, change) }
      before_remove_for_articles << ->(method,owner,change) { owner.send(:on_remove_article, change) }
    
      def articles_changed?
        @article_changes[:removed].present? or @article_changes[:added].present?
      end
    
      private
    
      def on_add_article(article)
        initialize_article_changes_safe
        @article_changes[:added] << article.id
      end
    
      def on_remove_article(article)
        initialize_article_changes_safe
        @article_changes[:removed] << article.id
      end
    
      def initialize_article_changes
        @article_changes = {added: [], removed: []}
      end
    
      def initialize_article_changes_safe
        @article_changes = {added: [], removed: []} if @article_changes.nil?
      end
    
      def unchanged_article_ids
        self.article_ids - @article_changes[:added] - @article_changes[:removed]
      end
    
      def change_articles
        do_stuff if self.articles_changed?
        do_stuff_for_added_articles unless @article_changes[:added].nil?
        do_stuff_for_removed_articles unless @article_changes[:removed].nil?
      end
    end
    

    The two hooks before_add_for_NAME-OF-RELATION and before_remove_for_NAME-OF-RELATION are triggered when adding or removing a relation. The triggered functions (you can not link a function by name, you have to do it by lambda) add the ids of the added / removed relation items to the @articel_changes hash. When the model is saved, you can handle the objects by their ids in the change_articles function. After it, the @articel_changes hash will be cleared.

提交回复
热议问题