Best way to override named_scope for has_many associations in Rails?
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.
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...
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"
精彩评论