Browse the Ruby on Rails Community.

You are here: Browse Railsplugins Global Scope

Global Scope

  • Copyright© 2006 Dimitrij Denissenko
  • http://www.dvisionfactory.com
  • http://retro.dvisionfactory.com
  • svn://dvisionfactory.com/rails/plugins/global_scope
  • Please read LICENCE document for more information.

This plugin allows to define ActiveRecord’s method parameters with a global scope. The functionality is analogous to the original with_scope method, but it applies globally and not just within a given block.

The plugin is not meant to be used in a usual application development process because general scopes are almost never a good idea. The purpose of the provided code is to fix an side-effect issue of multiple aliasing of ActiveRecord’s ‘find’ method. Details of the issue and a possible integration example are given in the next chapters.

Side-effects of "find aliasing" - an example

Think of an example application that uses the acts_as_paranoid[http://www.agilewebdevelopment.com/plugins/acts_as_paranoid] and the default_order[http://www.agilewebdevelopment.com/plugins/default_order] plugins. Both alias the ‘find’ method, to append conditions and enhance its functionality:

default_order

alias_method :find_without_order, :find
alias_method :find, :find_with_order
def find_with_order(args)
  ...  # new find method
end

acts_as_paranoid

alias_method :find_with_deleted,  :find
...
def find(args) 
  ... # new find method
end

A problem occurs as soon as a model uses two(or more) ‘find’ manipulating extensions at the same time. Example:

class Author < ActiveRecord::Base
  order_by "last_name" 
  acts_as_paranoid
  ...
end

The first ‘order_by’ call aliases the original ‘find’ to ‘find_without_order’ and defines a ‘find_with_order’, which basically is the new ‘find’. The second alias (‘acts_as_paranoid’) makes ‘find_with_order’ to ‘find_with_deleted’ and introduces a new, own ‘find’.

So what exactly happens? The original, unaliased ‘find’ method has the following behaviour:

Author.find(:all)                 # SELECT * FROM authors

After ‘order_by “last_name”’ the behaviour changes to:

Author.find_without_order(:all)   # SELECT * FROM authors
Author.find(:all)                 # SELECT * FROM authors ORDER BY last_name

And finally, after ‘acts_as_paranoid’:

Author.find_with_deleted(:all)    # SELECT * FROM authors ORDER BY last_name
Author.find(:all)                 # SELECT * FROM authors WHERE deleted_at IS NULL ORDER BY last_name

Some might already see sources for possible defects. Doing multiple ‘find’ aliasing almost certainly results in side-effects. Although in the example above, ‘find’ should (per definition) return only not-deleted records (those where ‘deleted_at’ is nil), a call like

Author.find_without_order(:all, :order => "pre_name")

would break this definition and perform

SELECT * FROM authors ORDER BY pre_name

statement, which certainly does not reflect the intention of the programmer.

Integration with existing applications

Just a short example of How existing applications could be integrated with my global_scope plugin?>

Again, I will take recently published default_order extension as an example. The original code looks like that:

module DefaultOrder
  ...  
  module ClassMethods
    def order_by(order_string)
      self.class_eval  !args1
            else
              args[1] = {:order => "#{order_string}"}
            end
            find_without_order(args)
          end
end
alias_method :find_without_order, :find
        alias_method :find, :find_with_order
      end
    }
  end
end

A possible integration of global_scope could be:

module DefaultOrder
  ...  
  module ClassMethods
    def order_by(order_string)
      self.class_eval do
        if self.respond_to?(:global_scope) # new way ... one single code line
          global_scope(:set_by_default_order_plugin, :find => {:order => order_string})
        else # old way
          class << self
            def find_with_order(args)
              if args[1] 
                args1 = "#{order_string}" if args[1].is_a?(Hash) && !args1
              else
                args[1] = {:order => "#{order_string}"}
              end
              find_without_order(args)
            end
            alias_method :find_without_order, :find
            alias_method :find, :find_with_order
          end
        end
      end
    end
  end
end

NOTE: This description has been extracted from the Plugin README and so the formatting may need updating to make browser friendly

Users


See all 7 member details


Membership

+ Join this railsplugin

Record Maintainer

'None'