how to add an element to devise session - ruby-on-rails

I am working with rails and devise for authentication, I want to add an element to the session hash, if I was using the native authentication session i would do session[:cart_id], but with devise I dont know if that would work or how to do it the devise way, for now I made a relationship between the customer model and the cart model: a customer has one cart, that way I can access the cart using customer.cart but I saw that many people dont relate the cart to the customer that way, they just create the cart and keep the id in the session hash. so my questions are:
1- How to add an element to the session with devise?
2- Relating the Cart model with the Customer model (a customer has one cart) is a correct approach or should I try to go with the cart_id in the session hash?

Devise don't change anything to the session, it may use keys like :user_return_to (given your devise session is "user") but mostly you are free to use the session as you wish.
Session[:cart_id] is fine, do not store anything like a model in session, store its id instead, and fetch the corresponding record from the database from the database when access is needed.
See also this chapter about session storage: http://guides.rubyonrails.org/security.html#session-storage

Related

Rails 5 access profile data anywhere in session without querying database each time

I've a user profile (with name, logo, about_me) which is created after user creation(using Devise). Profile table uses user_id as Primary key.
Now I want that whenever the user creates/updates a post, while filling in form some details are taken from profile, so profile data or #profile be available in post form as I cannot expose my model in form.
To set post.myname attribute in create and #update I'm doing this:
#myprofile = Profile.find_by_user_id(current_user)
write_attribute(:myname, #myprofile.name)
I read from various sources but what's the best solution of the 4 given and if anyone can back with easy code as I do not want to do something extensive? Thanks in advance.
1)Form Hidden fields - Like get the profile data as above in hash in #edit and then pass through form and access fields in #update but that way we will pass each field separately. Can one #myprofile be passed?
2)Session - I feel if profile data is stored in a session and someone updates profile then updated data won't be available in that session.So not sure if it is plausible.
3)Caching - easy way to do that?
4)polymorphic profile---tried it but I didnot get relevant example. I was stuck with what to put as profileable id and type and how to use them in the code.
If your Profile and User models have a one-to-one relationship with each other, the simplest solution is to remove the Profile model altogether and move its fields into the User model.
Devise already queries the database to obtain the current_user object. So, your example would like this:
write_attribute(:myname, current_user.name)
Which wouldn't hit the database (after Devise has retrieved the current_user object).
If you're forced to keep the Profile model, in looking at your four scenarios ...
You could use a session variable. Something like:
session[:profile_name] ||= #myprofile.name
This would go in a controller action.
The trick here is that you will want to redefine the each relevant session variable if the profile gets updated. And because you don't have access to the session in the model, you'd be best to perform that action in the controller. So, not pretty, but it could work.
You could also use low-level caching, and save the profile relationship on the user. In general, you could have a method like this in your user model:
def profile_cached
Rails.cache.fetch(['Profile', profile.id]) do
profile
end
end
Here, too, you will have to know when to expire the cache. The benefit of this approach is that you can put this code in the model, which means you can hook its expiration in a callback.
Read more about this in Caching with Rails.
I would avoid hidden fields and I'm not sure how a polymorphic relationship would solve you not hitting the database. So, #2 and #3 are options, but if you can combine the two models into one, that should simplify it.

Unique Session ids in Rails

I made a shopping cart model for a webapp that I am working on. It was just a standard ruby on rails model.
It lets users add products to the shoppingcart, but only shows it to them if they are the user that added the item. However, I'd like to let users who haven't signed in add items to a shopping cart.
Right now I'm using devise so I can check for a current_user, and assign that shopping cart item to that user. However is there a similar unique session id or anything I can use to simulate a user. So I only show the items that were added to the one person?
The reason for this is I'd like my user to go through as much of the ordering process as possible before asking them to sign-in and make an account.
Thanks
A simple method for this is creating a shopping cart and then adding that identifier to the session regardless of their logged in state.
For example:
#shopping_cart = ShoppingCart.create(user: current_user)
session[:shopping_cart_id] = #shopping_cart.id
Later you can retrieve the current shopping cart, if any, as a before_action handler.
I worked on similar problem. What I did was, I used session_id. First, you need a table(say, product_list) to hold the product list for temporary purpose. Populate each product to this table along with session_id. This will help you to identify the association of product_list with the active user. On checkout copy the record from product_list to your shopping_cart table and delete the record from product_list.
Try this, it might help you with the current problem.

Rails Security - Enforcing ownership at the model level

I recently coded up a 'friend' capability with my website. The way it works is if a user wants to 'friend' another user, sending a request creates a user_connection record with the original user set at the user_id and the requested user set as the contact_id. If the other user accepts the request, then another user_connection record will be made, with the user_id and contact_id reversed. If both user_connections exist, then the two users are considered friends. This currently gives each user access to any buildings shared between the two users.
I was wondering if there was some way I could enforce my user_connection model to make sure that whoever is creating the record gets set as the user_id. Otherwise it seems that someone could spoof the user_connection create request to make themself a contact of whomever they want, and then could spoof building shares using the same methodology. Are there any built in methods to prevent this?
My first thought was to have an initializer that always set the user_id to the current_user's id, but it appears that current_user is outside of the context of the model.
Don't allow user_id to be provided as a parameter, using strong params.
So, you could create the relation like that:
#friendship = current_user.friendships.new(contact_id: other_user.id)
Also make sure you provide the correct condition for current_user.
That's it... user_id is implied but never provided.

Create new page in Rails to add roles to existing users

I want to create a new page in my rails app that you can access once you're logged in. All you would see is a dropdown with the existing users and a dropdown with the role you want to assign to that user with a submit button that would add the role to the user_role column for that user. Do I do this with a
rails g controller add_roles new create
or
rails g scaffold add_roles
How do I get it to submit the correct info to the user table?
From my understanding, a rails scaffold is a full set of controller, model, and migration. In your case, I don't think you want a add_roles_controller, and an add_roles model, you just want to update a column of your existing Users DB correct?
If so, ask yourself if you really need a controller to do this, this type of functionality can be done in an existing user_controller (or something of the like). If you are going the CRUD route, you can consider this an update upon a user.
You can make an active record call from any controller, lets say you're in a user_controller and you have a users model, you could do something like:
#users = Users.all
That would return an object of all the user's stored in the db from which can can loop through them, picking out each individuals role attribute.
If you need help on creating a form, you're going to need to elaborate, this will require changing your routes to respond to a POST to a certain controller action. That controller action can then take the parameters of the post, say a user's role, and update the Users database accordingly
if you haven't yet, check out the gem devise - it's a very easy way to login/logout and it includes some pretty awesome session management
Devise
And if you want more functionality, I'd look into rolify. I haven't used it but it seems like a great way to add roles to users. Rolify

Ruby on Rails: how can I store additional data in the session for authlogic

I'm using Authlogic to authenticate users.
I understand how to create and use sessions, but want to store an additional id variable in the current_user session created by authlogic.
Can I just do something like this:
session[:authlogic_sess_name] = #extra_id.id
However, I'm not sure what the authlogic session is named though or how to access it.
Thanks!
Why would you not just store the value in the session?
session[:extra] = #extra_id.id
The Authlogic current_user is simply a value in the current session, managed by the Rails stack itself.
I agree with Toby, if you don't need this additional attribute to be on AuthLogic's UserSession object, then it may be simpler to store the value in the session hash itself.
But in my specific case, and perhaps in yours too, I have information that I want on the UserSession record specifically rather than the session hash, because I want to access it in a callback in the UserSession model, where "session" is unavailable.
Here is an older blog post describing how to store an additional attribute on UserSession:
http://railsblog.kieser.net/2010/03/authlogic-custom-logins-and-persisting.html
EDIT: I didn't have much luck with this approach myself. To do the things that required information from the session hash, I put that logic in the controller instead of the model.
AuthLogic actually has certain callbacks that execute controller methods. For instance, AuthLogic will call last_request_update_allowed? if your controller responds to that, right before setting last_request_at.

Resources