Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

delete in a relation doesn't call sweeper

#826

Summary

  • @users_friend.user.friends.delete(@users_friend.friend) # Dont call the sweeper observer
  • @users_friend.destroy # Call the sweeper
  • @users_friend.user.friends << @users_friend.friend # Call the sweeper

In these situation, destroy and destroy2 do similary things.
* One do: @users_friend.user.friends.delete(@users_friend.friend) * And the other: @users_friend.destroy

Only the second one call the observer. I can understand these, and imagine why happens. But if these doesn't execute as expected, something like:

@users_friend.user.friends << @users_friend.friend

Must don't run too.

I put the important code here, and add a sample app as attachment.

class User < ActiveRecord::Base
  has_many :users_friends
  has_many :friends, :through => :users_friends
end

class UsersFriend < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, :class_name => "User", :foreign_key => "friend_id"
end

class UsersFriendSweeper < ActionController::Caching::Sweeper
  observe UsersFriend
  def after_destroy(record)
    puts "after_destroy"
    debugger
  end
  def before_destroy(record)
    puts "before_destroy"
    debugger
  end
end

class UsersFriendsController < ApplicationController
  cache_sweeper :users_friend_sweeper

...

  # POST /users_friends
  # POST /users_friends.xml
  def create
    @users_friend = UsersFriend.new(params[:users_friend])

    @users_friend.user.friends << @users_friend.friend #These call the sweeper before_save
    respond_to do |format|
        flash[:notice] = 'UsersFriend was successfully created.'
        format.html { redirect_to(@users_friend.user) }
        format.xml  { render :xml => @users_friend, :status => :created, :location => @users_friend }
        format.js
    end
  end

  def destroy
    @users_friend = UsersFriend.find(params[:id])
    @users_friend.user.friends.delete(@users_friend.friend) #Dont call the sweeper

    respond_to do |format|
      format.html { redirect_to(users_friends_url) }
      format.xml  { head :ok }
      format.js   { render :action => "create"}
    end
  end

  def destroy2
    @users_friend = UsersFriend.find(params[:id])
    @users_friend.destroy #These call the sweeper before_destroy

    respond_to do |format|
      format.html { redirect_to(users_friends_url) }
      format.xml  { head :ok }
      format.js   { render :action => "create"}
    end
  end
...
end

Reported by Guillermo Álvarez · August 14th, 2008 @ 11:51 AM

State: invalid
Milestone: 2.x
Assigned to: Pratik Pratik
Importance: none

Activity

  1. legolin
    legolin
    • Tag changed from 2.1, activerecord to 2.1, activerecord

    I'm having the same problem. The workaround is simple but it seems dangerous to have observers not listening to such things.

    September 19th, 2008 @ 01:52 AM

  2. Pratik
    Pratik
    • Assigned user set to Pratik
    • State changed from new to incomplete

    Could you please upload a patch/failing test - http://rails.lighthouseapp.com/p... ?

    Thanks.

    December 20th, 2008 @ 07:15 PM

  3. Ryan Bigg
    Ryan Bigg
    • State changed from incomplete to stale

    Please submit a patch if you wish to see this fixed.

    April 11th, 2010 @ 01:53 AM

  4. Ryan Bigg
    Ryan Bigg
    • State changed from stale to invalid

    destroy sweepers should only work for destroys. The idea of using delete is that it runs like destroy, but without the callbacks. Use destroy rather than delete.

    April 11th, 2010 @ 02:03 AM