Rails 4 session.id occasionally nil - ruby-on-rails

I'm running a simple website on Heroku and I'm noticing something strange occurring when I'm running the app. It appears that approximately 50-60% of my users are reporting a nil session_id when it gets logged in my database.
I'm using active_record_store for my session handler and Postgres as my db server. I've gotten similar results using the cookie_store, so i'm not sure what i'm doing wrong. The only guess I have is that the first request a user makes, the id might not be populated yet. The sessions table has the correct number of entries, but my tracking table does not.
Example Code
class CaptionController < ApplicationController
def index
#image = Image.order("RANDOM()").first
Tracking.log(session.id, Tracking::VIEW_CAPTION_ON_IMAGE, #image.id)
end
The code above results in 50% of the time, the session being nil in the table it logs to.

I found the answer, it looks like Rails is trying to be efficient by only creating a session if there is something to store. So accessing the session.id without storing something doesn't return consistent results.
You need to force the session to be created by storing something in it.
TLDR: Add this somewhere before you access the session ID.
session[:foo] = "bar"
Source: http://www.gani.com.au/2013/08/force-session-creation-in-rails/

Related

Updating and accessing a session with Ruby on Rails

I'm working with ruby on rails 2.5.
I have an object "payment_plan". This object can change with a toggle behavior that changes, and I need to keep this object alive thorough all the session and at the end it should be save par of it in my mongo db. I need to access the latest status of the object always. The controller should be capable to update the object and the view should be able to access the latest state of the object.
Any insights on how to do something like this would be great :)
I have try to create a helper function in the application controller but had problem accessing it from the view.
Also I prefer not to save the state of the object in the db, because it will be too many db calls later.
To access a controller helper function from view, define it as a helper:
class SomeController < ApplicationController
helper def some_helper
end
end
As for storing some data in session - it's ok, rails has nice session store mechanism for session[:my_object_prop] = 1/session[:my_object_prop] (see in official guide)
But keep in mind, that:
by default session is stored in cookies, which are passed in headers from client browser with every request to your server (even to images, if they are on the same domain), so it's only practical to save small amounts of data there.
user can clear their's cookies and data will be lost (this is usually fine)
the opposite of the latter - a user may come to your app with session data from old version of your code
thank you very much, that was very helpfull!
Another question, can I override a session value after setting it up?
for example session[:plan_id]="plan_id_1" and they further on in the run do something like this: session[:plan_id]="plan_id_2"
thanks!!!

Adding User-Agent & IP to a stored Session -RecordNotSaved -Rails

I'm currently building an in-house analytics system which tracks where a visitor clicks throughout each session, whether they are logged into a User account or are a visitor without an account.
I am currently saving my sessions to the database thanks to changes made through sessions_store.rb, however in addition to the session_id, I am trying to figure out how to add both UserAgent details and a visitor's IP to the sessions table.
I've tried a couple solutions but all have failed - my current solution appears to be the closest, however I keep encountering an ActiveRecord::RecordNotSaved error after updating the Session's attributes.
I am currently using a before filter in application controller:
before_filter :set_useragent_and_ip_in_session
def set_useragent_and_ip_in_session
if session
sess = request.session_options[:id]
#session = Session.where(session_id: sess).first
#session.update_attributes(:ip=>request.remote_ip, :user_agent=>request.user_agent)
#session.save!
else
end
end
I've inserted a debugging statement in my views and have played around the code in pry - the #session is valid and displays the #session.user_agent properly .... however when saving to the DB it justs rollsback.
When I use save!, I receive a Completed 422 Unprocessable Entity in the logs in addition to the following (pasted to gist to conserve space):
https://gist.github.com/anonymous/8019c2426334f395a5fd
Thanks! Any help would be very appreciated.
I would recommend rethinking your schema. A session can last many requests and you want a record per request. Also notice how your moving data off the request object and trying to store them into a session table. Instead make your very own request table and make a before filter that moves all the data you want from the request object to the request table. Now a session will have many requests.
I'm not sure why your record isn't saving however I would wager naming a model Session is conflicting with rails. By that same token when you make your request table you should give it a unique name like maybe SessionMeta and RequestMeta. Then SessionMeta could have many RequestMeta.

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 3 Cookie Based Sessions Question

With Rails 3, the default session storage mechanism is cookie_store. I assume that this means that the contents within the session hash are serialized, encoded and stored within a cookie in the browser? Does this mean that nothing (or very little) of the session is stored in the server?
I've had a few issues where I had a cookie overflow error and I'm assuming because I kept on adding to my user instance (which was also linked/fetched from the cookie).
u = session[:user]
u.add_this lots_of_data
so eventually I got a cookie overflow error.
Am I correct about this? Are sessions fully stored within cookies in Rails 3 (by default)?
Yes, if you use the cookie store, the session data is stored in the cookie. If you'd like to store it on the server, you will need to use another session store.
However, if you are storing model objects or "lots of data" in the session, you are most likely doing it wrong in the first place. Your data should go to the database, and the session should only contain as much information as you need to retrieve it.
In you case, this would mean to store the user id int he session, and load the user from the db in a before_filter.
Yes, you are right. The problem might come up if you keep on adding data to session.
But there are some other things that affect it.
Once, I ended up with CookieOverflow error, and the reason was the flash[:notice] messages.
If you use flash[:notice] = "message" and then redirect, the text "message" will be stored in the cookie. If the size of the text u pass is more than 4KBs, you get "CookieOverflow" error

Session problem using Facebooker with Ruby on Rails

I am reading the book Facebook Platform Development in order to try to code a small game for Facebook, and I have come across a "little" problem: I am trying to insert a user every time this is logged, into a database in my computer. I am using a couple of methods written in the book, but there seems to be a couple of problems:
I can't seem to retrieve the session_key from Facebook using the Facebooker helpers for RoR, and thus this value is null into the table in my database.
Every time I reload the webpage, I can see that even though the facebook_id is the same, the same user is added in another row to my table in the database, even though it shouldn't; it's just supposed to update the attribute session_key if this changes -anyway, right now this is null.
These are the three methods I am using in order to perform all this:
def self.for(facebook_id,facebook_session=nil)
user = User.find_or_create_by_facebook_id(facebook_id)
unless facebook_session.nil?
user.store_session(facebook_session.session_key)
end
end
def store_session(session_key)
if self.session_key != session_key
update_attribute(:session_key, session_key)
end
end
# Re-create a Facebooker::Session object outside a request
def facebook_session
#facebook_session ||= returning Facebooker::Session.create do |session|
# Facebook sessions are good for only one hour storing
session.secure_with!(session_key,facebook_id,1.hour.from_now)
end
end
Thanks a lot in advance to everybody!1.
Hey sadly facebook changes its API all the time!
Make sure that the book is up to date and that none of the API has changed as of when the book was written. Also check that the gem is also up to date.
I personally use http://github.com/chrisdinn/hyper-graph when dealing with facebook. It makes calls to the facebook graph (graph.facebook.com)

Resources