Hello. LoginSystem is cool, it populates the @session instance variable of controllers with many useful info. The fact is : it would be cool to let models know about the session, too. For instance, after_update and after_create callbacks could store *who* did *what* on *what. Aim : having ActiveRecord::Base::session defined, returning the @session of the controller which manipulates the model. Here''s a way to do that. I was wondering whether it was good ruby and good rails because I''m a real newbie. I don''t know either if the class member I added to ActiveRecord::Base doesn''t break when several users use the application, leading to multiple sessions. First, let controllers give @session to models : (In controllers/application.rb) class ApplicationController < ActionController::Base include LoginSystem before_filter :export_session_to_models def export_session_to_models ActiveRecord::Base.set_session { @session } end end Now, let models know the set_session method, and let''s define ActiveRecord::Base::session: (In controllers/application.rb) # This unless is required for proper behavior in FastCGI context unless defined? ActiveRecord::Base::session class ActiveRecord::Base @@session = nil class << self def set_session(&action) @@session = action end def session @@session.call() end end def session self.class.session end end end Is this code OK ? --- Now that this framework is set, I can store who did what on what on any database update : (In controllers/application.rb) class ActiveRecord::Base after_update :update_history after_create :create_history before_destroy :destroy_history def update_history history (''update'') end def create_history history (''create'') end def destroy_history history (''destroy'') end def history(action) unless kind_of?(History) history = History.new(:action => action) history.ref = self history.save end end end With, roughly, a History model like : :user_id # who performed the action :action # the action :date # when :ref_table # the table of the altered model :ref_id # the id of the altered model (In models/history.rb) class History < ActiveRecord::Base def ref=(object) write_attribute(''ref_table'', object.class.table_name) write_attribute(''ref_id'', object.id) end before_create :fix_history before_update :fix_history def fix_history write_attribute(''user_id'', session[:user].id) if user_id.nil? write_attribute(''date'', Time.now) if date.nil? end end -- Posted via http://www.ruby-forum.com/.
lagroue wrote:> Hello. > > LoginSystem is cool, it populates the @session instance variable of > controllers with many useful info. > > The fact is : it would be cool to let models know about the session, > too. > For instance, after_update and after_create callbacks could store *who* > did *what* on *what. > > Aim : having ActiveRecord::Base::session defined, returning the @session > of the controller which manipulates the model.OK. Thanks to http://www.koziarski.net/archives/2005/07/16/environment I understand things better. LoginSystem has nothing to do with that. class ActiveRecord::Base cattr_accessor :session end class ApplicationController < ActionController::Base before_filter :export_session_to_models def export_session_to_models ActiveRecord::Base.session= @session end end Is much sufficient. My history framework should read : (in controllers/application.rb) class ActiveRecord::Base cattr_accessor :session end # this is the actual unless required by FastCGI unless defined? ActiveRecord::Base::history class ActiveRecord::Base after_update :update_history after_create :create_history before_destroy :destroy_history def update_history history (''update'') end def create_history history (''create'') end def destroy_history history (''destroy'') end def history(action) unless kind_of?(History) history = History.new(:action => action) history.ref = self # without the fastcgi unless, the number of historics saved grows !! history.save end end end end -- Posted via http://www.ruby-forum.com/.
Gregory Seidman
2006-Apr-06 12:29 UTC
[Rails] LoginSystem : make @session available to models
On Thu, Apr 06, 2006 at 12:51:01PM +0200, lagroue wrote: [...] } The fact is : it would be cool to let models know about the session, } too. [...] This should be a FAQ. It gets asked all the time. As such, I have added it to the FAQ at http://wiki.rubyonrails.com/rails/pages/FAQ#mvc --Greg
Good idea Lagrou, I''ve just tried your solution : class ActiveRecord::Base cattr_accessor :account after_update :update_log def update_log puts("store to log here") end end but there''s something strange, update_log method is called SIX times even if there''s only ONE @article.save call in article_controller And the more I cycle throught list->post (then save)->list the more update_log is called (14 times on second cycle) I don''t understand why Did you had this problem too ? -- Posted via http://www.ruby-forum.com/.
Nuno wrote:> Good idea Lagrou, I''ve just tried your solution : > > class ActiveRecord::Base > cattr_accessor :account > after_update :update_log > > def update_log > puts("store to log here") > end > end > > but there''s something strange, update_log method is called SIX times > even if there''s only ONE @article.save call in article_controller > > And the more I cycle throught list->post (then save)->list the more > update_log is called (14 times on second cycle) > > I don''t understand why > > Did you had this problem too ?Yeah, I do have it. I thought, by mistake, that this unless defined? ActiveRecord::Base::history (unless defined? ActiveRecord::Base::update_log) would fix that. More investigation lead me to that fact : When ActiveRecord::Base is altered in controllers/application.rb : - callbacks are triggered too many times on FastCGI mode (too many times, precisely, an increasing number of times at each request. The tracebacks are the same for each spurious callback trigger) - callbacks are NOT triggered on CGI mode. So the main problem may be controllers/application.rb. I''m investigating oher ways to inject code. Thanks for your answer ! -- Posted via http://www.ruby-forum.com/.
OK. So far, I came up with this solution for my session/history feature : I defined lib/history_system.rb : class ActiveRecord::Base cattr_accessor :session end module HistoryModel def update_history history (''update'') end def create_history history (''create'') end def destroy_history history (''destroy'') end def history(action) unless kind_of?(History) history = History.new(:subtype => action) history.ref = self history.save end end end module HistorySystem protected def prepare_history ActiveRecord::Base.session= @session end end In controllers/applications.rb : require_dependency "login_system" require_dependency "history_system" class ApplicationController < ActionController::Base include LoginSystem model :user include HistorySystem before_filter :prepare_history end In *every* models/model.rb I want its model to have history features : (I gave up the idea of giving it to every ActiveRecord::Base subclass) require_dependency "history_system" class <Model> < ActiveRecord::Base include HistoryModel after_update :update_history after_create :create_history before_destroy :destroy_history end The History model has already been described in a post before. So. That works, in CGI and FastCGI modes, there is no longer too many calls, BUT I could not inject that code in any ActiveRecord::Base subclass. Consider that as further exercice ! Thanks again. -- Posted via http://www.ruby-forum.com/.
Gazoduc
2006-Apr-07 08:55 UTC
[Rails] Re: LoginSystem : make <at> session available to models : do not use class variables !
lagroue <lagroue@...> writes:> module HistorySystem > > protected > > def prepare_history > ActiveRecord::Base.session= <at> session > end > endIsn''t this going to break if you have two concurrent requests on the same process (that is sharing the same class variables) ? I posted a solution to this issue here : http://www.ruby-forum.com/topic/60732#58279 It''s the stuff with secure { }
lagroue
2006-Apr-08 07:50 UTC
[Rails] Re: LoginSystem : make <at> session available to models : do
Gazoduc wrote:> lagroue <lagroue@...> writes: >> module HistorySystem >> >> protected >> >> def prepare_history >> ActiveRecord::Base.session= <at> session >> end >> end > > Isn''t this going to break if you have two concurrent requests on the > same > process (that is sharing the same class variables) ? > > I posted a solution to this issue here : > http://www.ruby-forum.com/topic/60732#58279 > > It''s the stuff with secure { }That''s exactly the kind of answer I was waiting. I admit I have difficulties finding clear documents explaining how (when) Rails creates instances. On CGI mode, a new ruby process is launched, so I *guess* there is no persistency whatsoever except the @session which *may* be marshalled *somewhere*. But in FastCGI mode, I''m still blinded by a total fog. I *infer* theories on Rails from the odd behaviors it shows when I try some edgies solutions, but I still miss a reference document. *sigh* Thanks for your solution, I''m gonna read it right now. -- Posted via http://www.ruby-forum.com/.