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/.