I\'ve got these two classes.
class Article < ActiveRecord::Base
attr_accessible :body, :issue, :name, :page, :image, :video, :brand_ids
has_many :pub
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.