Rails Automatic Scoping ala Userstamp
I am working on an app to keep track of my customer base, projects, tasks, communications with customers, and some other functionality that you might find in CRM & Project Management apps. So I have a simple interface with a select box of all customers which I have placed in the header. Selecting a customer there acts as a global filter meaning it should do the following:
- Limit the results I get in my lists of projects, contact reports, people, and tasks so that I can focus on one customer at a time.
- I would also like to be able to leave that variable empty so that if I need to look at complete lists I can.
- One last thing, it should do this without adding tons of code all over the place and without brute force.
Userstamp Method
The Userstamp plugin gives us a good example of setting a current_user variable using the application controller and a session variable.
cattr_accessor :current_user
end
The following code allows our models to refer to the User model because the session variable cannot be accessed from within models.
before_filter do |c|
User.current_user = User.find(c.session[:user].id) unless c.session[:user].nil?
end
end
Well, in my case I am not working with a User but a Customer. So we’ll take what we’ve learned then apply it. Since my method is a cheap and easy ripoff of Userstamp I’ll name my method Trampstamp (because it’s cheap and easy).
Trampstamp Method
In my method the first thing that needs to be setup is the model to receive the current_customer. I’ll set that up in my Customer class.
cattr_accessor :current_customer
has_many :people
has_many :projects
...
Now I need a way to store that value.
def filter
if params[:customer_id]
session[:customer] = Customer.find(params[:customer_id])
else
session[:customer] = nil
end
redirect_to :back
end
...
And a way to retrieve the session value and set the current customer.
before_filter do |c|
Customer.current_customer = c.session[:customer] unless c.session[:customer].nil?
end
...
And finally a way to limit my search results without having to add conditions all over the application.
belongs_to :customer
def self.find(*args)
unless Customer.current_customer.nil?
self.with_scope(:find => { :conditions => [‘customer_id = ?’, Customer.current_customer.id] }) { super }
else
super
end
end
end
Result – Judo Style automatic scoping
When I have a current_customer set,Project.find(:all)will yield the following query:
SELECT * FROM projects WHERE (customer_id = 1)
When no current_customer is set, it is business as usual. I suppose it would be really easy to add another method to automatically add :customer_id to project.create, and others. Maybe I’ll release that as a plugin so it’s even DRYer than this.
Here is the complete contact report list with no customer set.

This is the same list with the customer set.



