views:

31

answers:

2

Note: I'm using Rails 2.3.8, not 3.

I have a Photo model with a default_scope:

default_scope :conditions => ["published = ?", true], :order => :position

Calling photo_album.photos returns all published photos ordered by position as it should. However, when looping through these photo albums in an admin panel to display the number of photos in each, the results are wrong:

pluralize(photo_album.photos.count, "photo")

returns 0, as none are published.

I know that similar questions have been asked, and the reply typically is along the lines of "use a with_exclusive_scope class method". As far as I can tell, this completely prevents the use of standard Rails associations - basically resulting in something like this:

pluralize(Photo.all_photos_in_album(photo_album.id).count, "photo")

and requiring a class method like:

def Photo.all_photos_in_album(album_id)
  self.with_exclusive_scope { find(:all, :conditions => ["photo_album_id = ?", album_id]) }
end

just to display the total number of photos in an album. This seems insane - overriding the default should not require abandoning Rails association conventions. with_exclusive_scope can not be used in an instance method (protected method) either - this would have allowed me to create a PhotoAlbum instance method called "all_photos" to at least preserve the semblance of associations (photo_album.all_photos). But no, that is not allowed :(

Aside from removing default_scopes, which have proven very useful across the site, does anyone know of a way override default scopes and maintain Rails association syntax?

Thanks!

Edit:

I wound up adding a PhotoAlbum instance method that, while it isn't an actual default_scope override, does at make for much nicer syntax in my views:

def all_photos_count
  PhotoAlbum.count_by_sql("SELECT COUNT(id) FROM photos WHERE photo_album_id = #{self.id} ORDER BY created_at")
end

pluralize(photo_album.all_photos_count, "photo")

While it's not exactly an AR has_many association and it relies on pure SQL, it's the best compromise I've found so far.

A: 

I don't understand why you don't do in Album:

has_many :photos
has_many :published_photos, :class_name => 'Photo', :conditions => ["published = ?", true], :order => :position

This way you could do:

@album.photos.count
@album.published_photos

And so on...

jordinl
Originally, I did something similar using a named_scope called :published (and not using a default_scope). The reason that I didn't go that route is that requesting album photos that are published occurs so much more frequently, I wanted it to be the default (both for purposes of leaner view code and to minimize changes in current code). default_scope would have been great for this, but since it's become like a really comfortable pair of shoes that won't come off (great for walking, bad for sleep), I may go back to my original plan (similar to your answer).
modulaaron
A: 

For me, the best solution in this case was to use neither default_scope nor has_many conditions and to just stick with named_scopes. Two named_scopes accomplished most of what I needed to keep my views lean:

named_scope :public_list, :conditions => ["published = ?", true], :order => :position
named_scope :private_list, :order => "created_at DESC"
modulaaron