[Rails] Re: Let't keep globals out of our rails (upsetting MCV? )
Tobias Lütke
tobias.luetke at gmail.com
Mon Apr 10 13:13:48 GMT 2006
These are just global variable with syntactic sugar.
On 4/10/06, lagroue <lagroue at free.fr> wrote:
> Based on the generous information many of you gave, here's my own
> attempt, lib/context_system.rb
> (I apologize for the poor English of my documentation).
>
> # Here we define a way for models to access a context set by the
> controllers.
> #
> # We add those methods to ActiveRecord::Base instances :
> # - context the context object
> # - context_session same as context[:session] (context has to be a
> Hash)
> # - context_user same as context[:session][:user]
> # (defined in a LoginSystem context)
> #
> # Those methods raise unless controllers had the context set before.
> # The context can not be nil.
> #
> # Controllers who include the ContextSystem module have two ways to
> define
> # the context :
> #
> # - a "local", thread-safe way
> # - a "global", not thread-safe way
> #
> # Both are always available, but the "global" methods will raise if
> # ActionController::Base.allow_concurrency is true.
> #
> # Thus the "local" way is best practice.
> #
> # -----
> #
> # Let's describe the two ways :
> #
> # 1) "local" methods
> #
> # In your controller code, give with_context or with_session methods a
> block.
> # Inside this block, the given context will be available to all
> # ActiveRecord::Base instances.
> #
> # - with_context(object) { ... } stores object as the context
> # - with_session { ... } stores {:session => @session} as the
> context
> #
> # Example :
> # def update
> # with_session do
> # # update and save a model.
> # ...
> # model.modifier_id = model.context_user.id
> # model.save
> # ...
> # end
> # model.context # raises since we're out of the with_session block
> # end
> #
> # If required by ActionController::Base.allow_concurrency, a mutex makes
> sure
> # that no more than one with_context or with_session block runs at
> # a given moment.
> # If not required, no mutex is used.
> #
> #
> # 2) "global" methods
> #
> # Those methods are to be used as filters :
> # - store_context may be called on before_filter
> # - store_session may be called on before_filter
> # - reset_context should be called on after_filter
> #
> # They *do not require* the controller to use the local methods
> with_context
> # or with_session for all models to know about the context.
> #
> # Exemple :
> #
> # require_dependency "context_system"
> # class FooController < ActionController::Base
> # def update
> # # update and save a model.
> # ...
> # # no surrounding with_session block, but this line works :
> # model.modifier_id = model.context_user.id
> # model.save
> # ...
> # end
> #
> # include ContextSystem
> # before_filter :store_session
> # after_filter :reset_context
> # end
> #
> #
> ------------------------------------------------------------------------------
>
> if ActionController::Base.allow_concurrency
> # thread safe mode
>
> require 'thread'
>
> class ActiveRecord::Base
>
> class << self
>
> def context_mutex
> @@context_mutex = Mutex.new unless defined? @@context_mutex
> @@context_mutex
> end
>
> def with_context(context)
> # protect the context with a mutex
> context_mutex.synchronize do
> @@context= context
> result = yield
> @@context= nil
> result
> end
> end
> end
>
> def context
> raise(RuntimeError, "Missing with_context or with_session block in
> Controller method.", caller) unless defined?(@@context) &&
> !@@context.nil?
> @@context
> end
> end
>
> module ContextSystem
>
> def with_context(context)
> ActiveRecord::Base.with_context(context) do
> yield
> end
> end
>
> def store_context(context)
> raise "Not allowed when ActionController::Base.allow_concurrency
> is true"
> end
>
> def reset_context
> end
>
> end
>
> else
> # not thread safe mode
>
> class ActiveRecord::Base
>
> cattr_writer :context
>
> def context
> raise(RuntimeError, "Missing store_context or store_session
> before_filter in Controller class, or with_context or with_session block
> in Controller method.", caller) unless defined?(@@context) &&
> !@@context.nil?
> @@context
> end
> end
>
> module ContextSystem
>
> def store_context(context)
> ActiveRecord::Base.context = context
> end
>
> def reset_context
> ActiveRecord::Base.context = nil
> end
>
> def with_context(context)
> ActiveRecord::Base.context = context
> result = yield
> ActiveRecord::Base.context = nil
> result
> end
> end
> end
>
> # session an user mappings on context : thread-independant
>
> class ActiveRecord::Base
>
> def context_session
> context[:session]
> end
>
> def context_user
> context[:session][:user]
> end
> end
>
> module ContextSystem
>
> def with_session
> with_context({:session => @session}) do yield end
> end
>
> def store_session
> store_context({:session => @session})
> end
> end
>
> --
> Posted via http://www.ruby-forum.com/.
> _______________________________________________
> Rails mailing list
> Rails at lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>
--
Tobi
http://shopify.com - modern e-commerce software
http://typo.leetsoft.com - Open source weblog engine
http://blog.leetsoft.com - Technical weblog
More information about the Rails
mailing list