session[:key] = value doesn't work - ruby-on-rails

I am trying to make use of session data in my application and for some reason I don't have something setup right.
The code:
session[:key] = some_value
Generates the following error:
The error occurred while evaluating nil.[]
Other controllers don't have an issue with the session, so I am guessing I missed some basic configuration thing somewhere.

Ok, I think I got it figured out now. I had a slightly more complex situation that my example. I actually had the following:
session[:chat_history][chat.from.id] ||= []
So I had an error with double array. I added the following:
session[:chat_history] ||= []
Problem was the first time I did this, I put it in a before_filter method. Apparently the session object is nil in the before_filter method, at least the way I have my application setup.
So I moved the initializer to the methods that actually access the session and life is good again.

It looks like the session variable is nil which makes me think the framework couldn't set it for one of these reasons:
Browser passed in no cookie for the session
Browser passed in a cookie but it didn't match anything the server expected
It was stated that some controllers work. Did something have the opportunity to create a session for the user before those controllers ran?

Related

Instance variable in controller with Ruby On Rails

When someone is logging into my application, I use:
def create
#user = User.authenticate(params[:email], params[:password])
[...]
end
Ok, then, when someone is logging out:
def destroy
user = User.find_by_id(session[:user_id])
[...]
end
Knowledge
As far as I know, variable scopes work based on a scope, at least on Ruby (on Rails).
Our friend said:
In case of controllers, it present for that HTTP request alone, the object and the instance variables.
Ok. My variable scope created on create method is useless for destroy method, but I was thinking about the subject and the following question appears: There's a way to preserve #user for that controller at all, regardless of the HTTP request?
I mean, # in this case seems useless to me because its not flexible. I don't know, just sounds strange for me I can't reuse it when I want to.
That's how the web works and why http is a 'stateless protocol'. You must understand that you are not starting to run a program and stop it when your user logs out. But you 'restart' the program for every single request. It's a new instance, a new process that knows nothing of the last one and for sure shares no memory with it. Actually the Rails instance that handles the create and the one that handles the destroy could easily run on two physically different servers!
There is no state (but what you put in the session storage or the URL params). # in this case means that your view can use this data (which in the Ruby context means that Rails already is doing some tricks to get it handed over there, since these are two different classes and the view would otherwise not know anything about the controllers instance variables).

Confirm on Apache Passenger deployment: rails access session in model

I am using this to access session in Model.
http://www.zorched.net/2007/05/29/making-session-data-available-to-models-in-ruby-on-rails/
Can anybody confirm that it will work with Apache + Passenger deployment too?
Or if there are any other alternatives to achieve the same?
Thanks,
Imran
I did not find any code on the internet that works, so I did some research and wrote my own. It works for Rails 3.2.x and probably on some other versions.
Insert this in your ApplicationController
# Set a filter that is invoked on every request
before_filter :_set_current_session
protected
def _set_current_session
# Define an accessor. The session is always in the current controller
# instance in #_request.session. So we need a way to access this in
# our model
accessor = instance_variable_get(:#_request)
# This defines a method session in ActiveRecord::Base. If your model
# inherits from another Base Class (when using MongoMapper or similar),
# insert the class here.
ActiveRecord::Base.send(:define_method, "session", proc {accessor.session})
end
I will not remind you that accessing your session from a model may lead to bad code. Other posts may tell you, that you are stupid. Though there are some valid reasons to access the session from your model, like implementing a Model.save method, that saves to the current users session.
Yes. It is the only efficient way I found to use session data in model. I also used it and never faced any deployment issue with Apache + passenger.
But you need to confirm when you will be playing with session values. On each new request to server, session value gets stored in thread and we can access it in model. If you are applying any logic by using thread value, then also make sure with situation when thread value might be nil also.
Because I got an issue where on development, my every code worked fine but on production, during starting server it caused an issue as initially it considered thread value as nil.

rails: authlogic passing a session parameter to UserSession.find

I'm passing the user session via a parameter (params['session_key']) for one controller (it's a flash upload script so I have to pass it via a param).
I don't know how to access the user session with authlogic by using the raw param string.
Normally I do this:
#current_user_session = UserSession.find
I thought I could do this:
#current_user_session = UserSession.find(session_key)
But passing the key as a parameter to the method doesn't appear to work.
Any idea how I look up the user session with authlogic when I can't access the session cookie and need to use a param with the session key?
In order to flash to get authenticated you need a "hack" that is quite tricky to get working.
don't know if you're using uploadify but you might need the same solution indicated here:
http://thewebfellas.com/blog/2008/12/22/flash-uploaders-rails-cookie-based-sessions-and-csrf-rack-middleware-to-the-rescue
the only problem is, I never found a 100% working solution on the internet, I started with this post and solved the problem manually with quite a pain here at work.
As I recall, I added exception on protect_from_forgery to my tmp_uploader method
Another necessary thing was on the render for the method where I had to specifically indicate:
render :action => 'tmp_uploader.js.rjs'
There is also a problem with filters using respond_to method that my AppController used, also added the tmp_uploader method to his :except list
Sorry I can't recall exactly what else I had to do, but it really was a big pain.

How to access global variable in a view in Ruby on Rails?

I have a User model.
I have a Session controller, in which I have a global user variable that is assigned as follows:
$user = User.authenticate(params[:session][:email], params[:session][:password])
(I've made user global just to try to solve this problem, so if there's a better way please let me know!)
I need to use the email of the logged in user as a parameter to send to Flex part of my website. At the moment I'm creating the link as follows:
<%= link_to "secondpage", secondpage_path(:email => #session.$user.email)
But I'm getting the following error:
compile error
/Users/benhartney/rails_projects/talk/app/views/layouts/_header.html.erb:12:
syntax error, unexpected tGVAR
..._path(:email =>
#session.$user.email) ).to_s);
#output_buffe...
There's also a little arrow pointing at $user
If I remove the $ from $user, I get this error:
undefined method `user' for
nil:NilClass
If I remove the
(:email => #session.user.email)
part, everything works fine, so I think all of the code except for this is ok.
Can anyone tell me what I'm doing wrong?
Thanks for reading!
I think what you are looking for is a session variable.
Rails is primarily a framework for creating web applications, and http is stateless, i.e. each request knows nothing about what went on before. To get over this limitiation, web developers use cookies or session variables to simulate maintenance of state, i.e. data, across requests.
Check out http://guides.rubyonrails.org/action_controller_overview.html#session
You can't have a global variable local to something, as far as I understand (this time, you can't have a global variable that is local to session)
Try using :email => $user.email
if you're adamant that you need a global variable for something.
You can also try
Thread.current[:email]

How do I store an instance variable across multiple actions in a controller?

Say I want to store some variable in my controller. I want to initialize it in one action, increment it in another, and read it in yet another. Just declaring this variable with #foo doesn't work because #foo dies after the action that created it is rendered.
I do not want this variable to be stored in a model.
Is there a way to preserve this variable besides storing it in a session?
It seems like I've run into this simple problem a few times, and I want to know the best way to go about solving it.
Not really. Each call to a controller action is stateless. Nothing is available after the controller action finishes. A new controller instance is created for each request, and then discarded at the end of the request.
If you don't want to store it in the session, or database model, you don't have many options if you're wanting that variable to be specific to a particular session.
If it is global across all sessions, you could put it in a ##class_variable rather than an #instance_variable, but that can get messy once you start having multiple Rails processes (each which will have their own copy of it), or if you're running in threadsafe mode, you can end up with nasty concurrency bugs.
I guess you could look at something like memcached, but you'd still need to key that to some user_id or other session marker (unless it's global)
I too am wondering why you are against using session? If you don't like working with session directly in your actions, you could emulate a surviving #foo instance variable with filters. Something like this maybe?
class FooController < ApplicationController
before_filter :load_foo
after_filter :save_foo
private
def load_foo
#foo = session[:foo] || 0
end
def save_foo
session[:foo] = #foo
end
end
Your actions will the be able to manipulate the value through the #count instance variable and this will be automatically persisted to session.
You could make use of the built in Rails.cache mechanism to store the value but as mentioned in the first answer you'd have to key it off something like the user_id. This is a nice way to go since you can back it with different storage mechanisms.
Rails.cache.write(:foo)
# in later action
Rails.cache.read(:foo)
One other thing you could look at is the flash hash, which provides a keep method to make the flash value last more than one subsequent request.
So in action 1 you could create the value:
flash[:foo] = some_value
flash.keep(:foo)
In action 2 you can access it, and call keep again if you want it to stay alive for more subsequent actions.
flash[:foo] #use it for something
flash.keep(:foo) # keep it for another request
It's a bit of a tricky thing to do cleanly within the context of http requests.
If it's a simple count or string, I think the best solution is to store it in the session. That way it will be there if you are using multiple web servers.
Why are you against using a session for this?
Don't worry, sessions won't bite.
Also, the session is probably the best way to do this.

Resources