Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3 default scope, scope with override

I have a situation where the behavior of an existing app is changing and it's causing me a major headache.

My app has Photos. Photos have a status: "batch", "queue", or "complete". All the existing Photos in the app are "complete".

99% of the time I need to only show complete photos, and in all of the existing codebase I need every call to Photos to be limited to only complete photos.

However, in the screens related to uploading and classifying photos I need to be able to fairly easily override that default scope to show batched or queued photos.

Like many others, I need to find a way to easily override the default scope in certain situations. I looked at these questions (1, 2) and they don't seem to answer what I'm looking for.

The code I wish worked is this:

class Photo < ActiveRecord::Base
  ...
  default_scope where(:status=>'complete')
  scope :batch, unscoped.where(:status=>'batch')
  scope :queue, unscoped.where(:status=>'queue')
  ...
end

However, that doesn't work. I tried wrapping the scope methods in lambdas, and that didn't work either.

I realize default_scope comes with baggage, but if I can't use it with overrides then I'm looking at adding scope :complete ... and having to comb through every call to photos in my existing app and add .complete in order to filter unprocessed photos.

How would you solve this problem?

like image 634
Andrew Avatar asked Aug 02 '11 22:08

Andrew


People also ask

How do you Unscope a default scope?

Use `unscoped`. Once the default scope has been removed, the call site will continue to work and the calls to `unscoped` can be removed at your leisure.

What are default scopes in Rails?

With default scopes, we can change/specify how records are retrieved by default from Active Record database. Any subsequent queries to the database will be retrieved/rendered following the default scope definition. For example, call the select Active Record finder method on the Tea class where rating is not exactly 3.

How do scopes work in Rails?

Scopes are used to assign complex ActiveRecord queries into customized methods using Ruby on Rails. Inside your models, you can define a scope as a new method that returns a lambda function for calling queries you're probably used to using inside your controllers.


2 Answers

def self.batch
  Photo.unscoped.where(:status=>"batch")
end
This thread is more authoritative: Overriding a Rails default_scope
like image 126
klochner Avatar answered Oct 06 '22 00:10

klochner


I give it a shot. Lets say you want to remove a where clause from a default scope (and not just override it with another value) and keep associations you can try this:

class Photo < ActiveRecord::Base
  default_scope where(:status => 'complete').where(:deleted_at => '').order('id desc')

  def self.without_default_status
    # Get the ActiveRecord::Relation with the default_scope applied.
    photos = scoped.with_default_scope
    # Find the where clause that matches the where clause we want to remove 
    # from the default scope and delete it.
    photos.where_values.delete_if { |query| query.to_sql == "\"photos\".\"status\" = 'complete'" }
    photos
  end

end
like image 30
schneikai Avatar answered Oct 06 '22 00:10

schneikai