1. Skip to navigation
  2. Skip to content

The ELC Community Blog

A knowledge exchange on Ruby on Rails and Agile Development


Scope Controller Model Plugin

by jsiegel on August 10, 2007

ELC Plugins

ScopeControllerModel plugin was created to DRY up controller and model logic when working a common data model pattern. Particularly, when access to model data is restricted to the current_user or their account. Supposing you have:

class Invoice < ActiveRecord::Base
  belongs_to :account
end
class Account < ActiveRecord::Base
  has_many :invoices
end

In this circumstance, there are two models: accounts and invoices. We want invoices to be restricted to the account of the currently logged in user, but also leverage scaffold_resource to make our site building nice and snappy.

A scaffold_resourced default controller will make reference to @invoices = Invoice.find(:all); however, this returns all invoices when we only want the invoices for a particular user. Likewise, Invoice.create(param[:invoice]) creates an invoice and has an inherent insecurity that a user can overload form data to create the invoice into the account of their choice. Enter ScopeControllerModel:

class InvoiceController < ApplicationController
  scope_controller_model :invoice, :conditions => { :account => Proc.new { |c| c.send(:current_user).account } }

This code snippit shows ScopeControllerModel being used to enforce a condition throughout all model find and create calls.

Install ScopeControllerModel by:

./script/plugin install http://svn.elctech.com/svn/public/plugins/scope_controller_model

Feedback welcome.

Quick update!
After some suggestions, we've modified the plugin to support a few new bits of functionality. In order to allow particular controller actions to bypass the scope_controller_model filtering, it now supports an API similar to before_filter. Also, callbacks are now supported as well as Proc's when establishing the object that actually associates to the scope. Example below:

class InvoiceController < ApplicationController
  scope_controller_model :invoice, :conditions => { :account => :current_user_account }, :except => :new

  def new
    @invoice = Invoice.new
  end

  def show
    @invoice = Invoice.find(params[:id])
  end

  private
  def current_user_account
    current_user.account
  end

end

All in all a simple update, but hopefully a useful one! As always, feedback welcome!

Comments

Blake at 3:05 AM on August 14 2007

This is exactly what I need. I’ve spent the last few days modifying acts_as_paranoid to get the functionality this plugin appears to already offer. Thank you so much!

God bless!

Blake

Blake at 4:06 AM on August 14 2007

You can apply an account restriction to a lot of models by modifying scope_controller_model to accept an array of model names. Change line 17 onward in controller.rb to: if model.is_a?(Array) model.collect { |model| scope_controller_model(model, options) } else … end

Jonathan Siegel at 8:58 AM on August 16 2007

Thanks Blake! I’ve just made an update to the plugin following your suggestion.

Mark at 5:54 PM on August 29 2007

What about passing in a table name? There are times when I’m selecting on a model but I want to add the scope to one of the :include models.

An an example would the the authentication plugin where the finder is called on Role but I want to scope the roles_users table.

I’ve been doing some of this in my project, where :table_name is optional.

   1  
   2  @project.scope_model(Role, :table_name => 'roles_users') { yield }

Michael at 11:08 AM on September 2 2007

So, will this allow for true account separation when it comes to building our apps? What other tools would I need to implement something like Basecamp or Shopify, where everyone has their own wholly controllable account with unique URL, etc?

Maxim Kulkin at 8:46 AM on May 4 2008

Uh, that is ugly.

Don’t understand why this

   1  account.invoices.create! params[:invoice]

doesn’t satisfy you.

Add a comment


home | services | Ruby on Rails Development | code | blog | company