[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