Ruby on Rails - ApplicationController - ruby-on-rails

Am working on some guest account feature in my game application.If u register as a game user then devise gem loads the current account id to the session automatically. But when a user is a guest, am creating a account and a user type object with hard coded values and saving that to the database successfully. But when I try to store the object into the session its not working properly.
My code is like this,
def play_as_guest
account = Account.new(email: "guest_#{Time.now.to_i}#{rand(99)}#eossys.com", password: "password", is_guest: true)
account.save
game_user = GameUser.new(account: account, game_profile_attributes: {first_name: "Guest", last_name: "guest", nick_name: "guest"})
game_user.save
session[:current_account] = game_user
redirect_to "/game_profiles/#{account.id}/summary"
end
If i store the account obj
session[:current_account] = game_user
this is throwing an error of "ActionDispatch::Cookies::CookieOverflow in HomeController#play_as_guest"
if I try
session[:current_account_account] = account
its not working, because after redirecting its again asking for the login. since I am using the 'authenticate_account!' filter in every class.
What I want basically is to load the account object I have created into the session, like as if its a registered user.
Thanks for the help in advance.

Rails cookies have a maximum limit of 4k ( http://guides.rubyonrails.org/security.html#session-storage ). When you do something like obj session[:current_account] = game_user, you are attempting to stuff the whole game_user object in there, which causes you to run out of room with the ActionDispatch::Cookies::CookieOverflow error you mentioned. The preferred way to do this is to save only the id, like this obj session[:current_account_id] = game_user.id,and look it up when you need it. This is much more efficient, even if your whole object did fit into memory somehow.

I think we need the code of your authenticate_account! filter to answer it properly but for your error, this is because you try to put an entire object in your session, it is better to only put the id of the object in it :
session[:current_account] = game_user.id
UPDATE
With devise you should use the sign_in method to set the session for this user instead of manually setting the session variable, depending of how your are using devise it could be:
sign_in account or sign_in game_user

Related

How to set whodunnit for paper_trail when creating a new user?

The paper_trail gem tracks versions, and does a good job. However, there is one edge case I've been noticing. For most objects, the application controller sets whodunnit if you are logged in, and then all objects that are created during that session have a version that records "whodunnit" according to who is logged in.
The interesting case is where nobody is logged in because a new user is signing up. The user is created with a "nil" whodunnit, which is wrong because actually the user was created by themselves.
Of course, whodunnit can't know the id of the user before the user record is saved. I know this.
However, this creates a conflict later, as various batch jobs also modify user records, and not being in a web session, also create versions with nil whodunnit records.
Now I can't tell who created the user - some batch import process, or the user.
I'm pondering various solutions, like perhaps rummaging around the Papertrail::Versions table for that object and fixing whodunnit, but that seems pretty unclean.
Any advice?
You can force whodunnit in the create action on your controller.
before_filter :only => [:create] do
PaperTrail.request.whodunnit = "Public User"
end
If you insist on having the user id in the version table, you can do this:
ActiveRecord::Base.transaction do
#user.save!
#user.versions.last.update_attributes!(:whodunnit => #user.id)
end
For someone reading this in future, John-Naegle's answer
PaperTrail.whodunnit = "Public User"
Does not work anymore. Use
PaperTrail.request.whodunnit = "Public User"

Trouble assigning user access levels

I'm following this tutorial, as I wanted to learn how to create user authorization with singular roles (each user has one role) from scratch rather than using a gem like rolify that does it all for me, but I'm hung up on assigning the users access levels.
When I type erin = User.find(9) in the console it finds my test#test.com user. I try to issue the erin.admin! command but it throws an error about the password? (ActiveRecord::RecordInvalid: Validation failed: Password can't be blank).
I've also tried erin.access_level = "admin" which returns "admin" while I'm still in the console but no longer exists when I exit the console, fire up the rails server and try to test out my test#test.com user in my app.
Is there any other way to assign access levels? Am I just doing it wrong?
The User record cannot be saved because a validation exists that requires a password. I don't know if there are special rules for the format of the password, but you can easily set a password so that you can save the user:
user = User.find(9)
user.password = 'Test1234'
user.password_confirmation = 'Test1234' # you might need this as well
user.access_level = 'admin'
user.save #=> true
If user.save returns false, check user.errors for any other validation errors that would cause the record not to save.
For the second part of my question, where my database didn't seem to deploy to Heroku, it's because I was working in the dev db, not the production db.
To do that, I ran "heroku run rails console" and then followed the above steps to give a user admin access levels. More here: https://devcenter.heroku.com/articles/getting-started-with-rails4#console

Creating users (with no registration) using Devise

I want to be able to create users and save them to the database but Devise doesn't pass the request to the database, and doesn't return any error.
alice = User.new
alice.name = "Alice"
alice.save!
alice gets saved successfully, just not in the database.
I can do User.find(alice.id) and it returns data as long as I'm in the same session.
If someone have this problem, I found that Devise enforces email even when setting
email_required?
false
end
so even hitting save! will not raise an error.
Therefore the only way i found is to create a fake email, using something like this
"guest_#{Time.now.to_i}#{rand(99)}#anyemail.com"
then assign a self.role = guest, so the account would be easily identified.
I hope this helps

How can I find a devise user by it's session id?

Given session["session_id"] is it possible to find the logged in User to which that session belongs to?
At least on my system (rails 3.2, devise 2.0.4), you can do it like this:
session is:
{"session_id"=>"be02f27d504672bab3408a0ccf5c1db5", "_csrf_token"=>"DKaCNX3/DMloaCHbVSNq33NJjYIg51X0z/p2T1VRzfY=", "warden.user.user.key"=>["User", [3], "$2a$10$5HFWNuz5p6fT3Z4ZvJfQq."]}
session["warden.user.user.key"][1][0], then is 3.
So, I'd find it as:
User.find(session["warden.user.user.key"][1][0])
I'm not sure what you are trying to accomplish but will try to answer
If you want only the User from the current session, a simple way would be to store his id on session, for example:
def login(username, pass)
# do the usual authentication stuff and get user
if logedin
session[:user_id] = user.id
end
end
Then get the current user would be something like
current_user =User.find(session[:user_id])
If what you want is finding all the users that are currently logged in, I think you need to config your app to save session at DB, because predefined is that session data is store in cookies in the browser. For more information on this check this answer
How to track online users in Rails?
EDIT: Just noticed you are using devise so the first way is actually there for you. You just need to call current_user method at any controller.
For the second way check this answer "Who's Online" using Devise in Rails
And i might add this, as i was trying to do it the other way, if you are using ActiveRecord session_store you can find all stored sessions of a user like so:
ActiveRecord::SessionStore::Session.select{ |s| s.data["warden.user.user.key"] && s.data["warden.user.user.key"][0][0] == user_id }

Ruby on Rails session storage - how to *not* store certain fields in session store?

WARNING: Complete newbie to RoR and Ruby alert! *
I have a login method that looks like this:
#user = Person.find(:first, :conditions => ["email=?", params[:email]])
if #user and #user.password==params[:user_password]
session[:user] = #user
else
flash[:warn] = 'Invalid password!'
However, the user record can get very large, so I don't want to store the entire user record in my cookie session.
How can I modify this code so that a specific field does not get stored in the session? There are two fields that can get very large (very large user profile data) and will not fit within the cookie session 4 kilobyte limit, so I want to exclude those from being stored in the session.
I would do :
session[:user] = #user.id
And then create a before_filter going something like this:
before_filter :get_user
def get_user
#user = User.find_by_id(session[:user])
end
edit: This is not exactly what you were looking for, but if you can't store all the object in the session variable you might want to consider this option. It's only one request so it won't be too resource intensive. Plus like this you can check at every page load that the user exists and this might be helpful, security wise.
The design of Rails often serves to steer you in a very specific direction. In this case, the fact that by default Rails' sessions are stored in a cookie is a strong hint that you shouldn't be storing large objects in the session. By all means store the User ID, but not the User object itself.

Resources