# LoginSystem : make @session available to models

**URL:** <https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998>\
**Category:** Rails\
**Created:** [April 6, 2006, 12:51pm UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998 "2006-04-06T12:51:01Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![lagroue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/439d5e/32.png) [@lagroue](https://www.ruby-forum.com/u/lagroue)\
**Post date:** [April 6, 2006, 12:51pm UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998/1 "2006-04-06T12:51:01Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![lagroue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/439d5e/32.png) [@lagroue](https://www.ruby-forum.com/u/lagroue)\
**Post date:** [April 6, 2006, 1:25pm UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998/2 "2006-04-06T13:25:26Z")

</div>

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](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

---

<div class="post-metadata">

**Author:** ![lagroue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/439d5e/32.png) [@lagroue](https://www.ruby-forum.com/u/lagroue)\
**Post date:** [April 6, 2006, 2:31pm UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998/3 "2006-04-06T14:31:11Z")

</div>

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 [Peak Obsession](http://wiki.rubyonrails.com/rails/pages/FAQ#mvc)

–Greg

---

<div class="post-metadata">

**Author:** ![lagroue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/439d5e/32.png) [@lagroue](https://www.ruby-forum.com/u/lagroue)\
**Post date:** [April 6, 2006, 3:52pm UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998/4 "2006-04-06T15:52:20Z")

</div>

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 ?

---

<div class="post-metadata">

**Author:** ![lagroue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/439d5e/32.png) [@lagroue](https://www.ruby-forum.com/u/lagroue)\
**Post date:** [April 7, 2006, 9:52am UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998/5 "2006-04-07T09:52:29Z")

</div>

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 !

---

<div class="post-metadata">

**Author:** ![lagroue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/439d5e/32.png) [@lagroue](https://www.ruby-forum.com/u/lagroue)\
**Post date:** [April 7, 2006, 10:15am UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998/6 "2006-04-07T10:15:54Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![lagroue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/439d5e/32.png) [@lagroue](https://www.ruby-forum.com/u/lagroue)\
**Post date:** [April 8, 2006, 9:50am UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998/7 "2006-04-08T09:50:02Z")

</div>

Gazoduc wrote:

> lagroue \<lagroue@…\> writes:
> 
> > module HistorySystem
> > 
> > protected
> > 
> > def prepare\_history  
> > ActiveRecord::Base.session= 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 :  
> [Models accessing the session - Rails - Ruby-Forum](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.

---

<div class="post-metadata">

**Author:** ![lagroue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/439d5e/32.png) [@lagroue](https://www.ruby-forum.com/u/lagroue)\
**Post date:** [April 7, 2006, 10:56am UTC](https://www.ruby-forum.com/t/loginsystem-make-session-available-to-models/56998/8 "2006-04-07T10:56:19Z")

</div>

lagroue \<lagroue@…\> writes:

> module HistorySystem
> 
> protected
> 
> def prepare\_history  
> ActiveRecord::Base.session= 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](http://www.ruby-forum.com/topic/60732#58279)

It’s the stuff with secure { }
