views:

69

answers:

3

I'm wondering if there is a way to set a scope on a model class for the rest of a request? I.e. I want to scope down some results, but I want to do it without the main restful controller knowing (perhaps in a before_filter injected into the controller).

Contacts.scope = { :conditions => {:public => true} } if ladeda

then later on

Contacts.all

should return the contacts with the scope. That is just pretend code, does anyone know if this is possible?

Cheers,

Brendon

A: 

I don't think the scope method even exists.

To make it work for all subsequent calls use

Contacts.default_scope(:conditions => {:public => true})

To make this less horribly errorprone maybe use an around filter and overwrite with

Contact.default_scope(:conditions => "")
nasmorn
Yea, tried this, I run passenger in development on my mac so I was instantly able to see the downfall of setting something like this, in that it remains for the next call! You're right about unsetting it afterwards. I guess if it could be proven to work well then it'd be ok, but what happens if one day passenger starts multithreading? Could be a bit of a disaster :)
Brendon Muir
+1  A: 

Here's how I would do it:

class Contact < ActiveRecord::Base
  named_scope :public_only, :conditions => {:public => true}
end

class ApplicationController
  protected
  def contacts
    @_contacts ||= ladeda ? Contact.public_only  : Contact
  end
end

class ContactsController < ApplicationController
  def index
    @contacts = contacts.all
  end
end

I'm moving the decision to use a scope or not to a helper method. Alternatively, you could move the helper method to the Contact model itself, such as this:

class Contact < ActiveRecord::Base
  def self.for_index
    ladeda ? self.public_only : self
  end
end

class ContactsController < ApplicationController
  def index
    @contacts = Contact.for_index
  end
end
François Beausoleil
Thanks, I went for something like that in the end. I'll post it below for interests sake.
Brendon Muir
A: 
module ContactFilterExtension

  unloadable

  def in_context(context)
    if proxy_owner.context == :special_area && context != :admin
      scoped(:conditions => {:public => true})
    else
      scoped({})
    end
  end
end

then

class ContactContainer < ActiveRecord::Base

  unloadable

    has_many :contacts, :dependent => :destroy, :order => :position, :extend => ContactFilterExtension

end

then in the controller:

  def index
    @contacts = @contact_container.contacts.in_context(context)
  end

That's simplified of course :) It also means that you can chain other scope after that one, and also build new records off of the context. Quite neat.

Also note that there are two contexts, one that we can only know of in the controller (where the user is in the system), and the other is the context of the ContactContainer which we can find through the models alone.

Also note the use of Contacts as an example wasn't the real use case :D

Brendon Muir