Simplify the delete operation in you Rails app

In the Ruby on Rails application I am working on, I have a model ‘Album’ and a model ‘Photo’. As you have guessed, each album can have many photos. This is a typical one-to-many relationship and can be coded like this:

class Album < ActiveRecord::Base
  has_many :photos
end

class Photo < ActiveRecord::Base
  belongs_to :album
end
&#91;/sourcecode&#93;

Since I want to have 'delete album' function in my application, I coded a destroy method in the my album controller.

&#91;sourcecode language='ruby'&#93;
class AlbumsController < ApplicationController
  def destroy
    @album = @account.albums.find(params&#91;:id&#93;)
    @album.photos.destroy_all
    @album.destroy
  end
end
&#91;/sourcecode&#93;

Nothing fancy here. A simple "delete the photos first before you delete the album" operation. This code has been in my application for several months and I even used the pattern in my other controllers. A while ago I was working on the admin pages and I was reviewing another 'destroy' method when I thought why should my "destroy" method explicity destroy the child records in my controller. My controller should know as little as possible (or none at all) how my models are related. My initial idea is to let the 'Album' model handle the deletion of the 'Photo' records. I thought a 'before_destroy' callback would do the trick. Just to be sure there are no gotchas, I looked it up in the Ruby on Rails API. I just found out, there is a simpler way of "delete the photos first before you delete the album". In my 'Album' model, I included the 'dependent' option in the 'has_many' association.

&#91;sourcecode language='ruby'&#93;
class Album <ActiveRecord::Base
  has_many :photos, :dependent => :destroy
end

All I need to do now is simply call ‘@album.destroy’ in my controller and all child photos will be deleted. Sweet.

Aside from the ‘dependent’ option, there is also the ‘exclusively_dependent’ which can delete the child records in a single SQL statement (which is faster than traversing each child record) on the condition that the child table has no hook methods on deletion and it is used only by the parent table.

5 thoughts on “Simplify the delete operation in you Rails app

  1. Hmmm, so what would you do if you allowed a photo to belong to many albums, ala iPhoto?

    How would you change things so that the photo could be deleted from an album, but still remain in other albums?

    And how would you change it so that if the photo is deleted, it’s deleted from all albums?

  2. Carmen, no problem. Thanks for dropping by

    Evan, as always, you’re the Rails hacker.

    Ian, thanks for these interesting questions. On question #1, initially I thought this would call for ‘habtm’. But on question #2 and #3, I have no idea if ‘habtm’ options can handle it. What would happen if an albums is deleted (in #2)? Photos that belong exclusively to the album will also be deleted? Or is the photo treated as a shared resource that if the numner of albums that reference it becomes zero, it can now be deleted? What would I do here is drop the ‘join’ and have a new model to represent this kind of relationship.

    Usability wise, I still find it complicated to have photos belonging to many albums. This behavior of an “album” and “photo” doesn’t map smoothly to the real world (at least in my world :)). If I would want to have photos belong to many albums, I would drop the term “album” and instead use “labels” or “tags”.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s