How do you model an anonymous user in an existing Rails schema? - ruby-on-rails

I'm working on my first simple Rails app in which users submit sport "tweets" (e.g. "tennis, squash") and the server matches them up with partners. The server will return you a list of SportMatches based on similar tweets and you have different options (e.g. email, SMS) to reply back to someone's tweet and accept him/her as partner. Initially, the modeling was straight forward since: User has_many SportTweets and SportTweet belongs to User. Notifications were simply part of the User, or they could have been modeled as a 1-to-1 relationship to User.
My business requirements changed a little, as now I have anonymous users who can also post SportTweets. Because they don't have an account/profile, they must also submit notifications (e.g. email, SMS) with the tweet. I don't know how to model this the Rails way. SportTweets are now either anonymous, or authenticated-user-posted (AUP). So, now, my SportTweets table will have the following columns:
type: either "anonymous" or "AUP"
user_id: only for AUP
notifications_id: only for anonymous
sports: for all
post_date: for all
post_location: for all
etc.
There would be a Notifications table. A notification record would belong either to a User, or to a SportsTweet. I guess I would model this with polymorphic associations.
That just doesn't look like the Rails way. Did anyone come across a similar problem? How did you solve it?

Did a bit of searching and the answer is STI. See The Rails 3 Way - Chapter 9.

Use Devise if you can. I think this link might help you.
In some applications, it's useful to have a guest User object to pass around even before the (human) user has registered or logged in. Normally, you want this guest user to persist as long as the browser session persists.
Our approach is to create a guest user object in the database and store its id in session[:guest_user_id]. When (and if) the user registers or logs in, we delete the guest user and clear the session variable. A helper function, current_or_guest_user, returns guest_user if the user is not logged in and current_user if the user is logged in.
Followed by the code which you might find helpful in that page

Related

How to remember the organization a user is logged in for? Switching between organizations

Background:
User and Organization have a many-to-many relationship through Relationship. So a user can be part of multiple organizations.
But a user can only be logged in for 1 organization.
Therefore the user has a screen where he can switch between the organizations he belongs to.
Also, user has a default organization, which is the organization the user initially logs in for. This is implemented using a has-one through relationship.
How to know/remember which organization a user is currently logged in for?
Now I'm a bit in a pickle how to implement how the app should know/remember which organization a user is currently logged in for. I see three options and am hoping for advice which should work best:
An additional column in the User db that stores the id of the organization (or relationship?) for which the user currently is logged in. A helper method logged_in_for could then find the organization based on the value in that column and return the organization the user is logged in for. Implementation using a db column also enables validation so that a user can't set the organization it is logged in for to an organization it is not even part of.
Use a cookie: session[:logged_in_for] that defines/sets the organization the user is currently logged in for. However, 1) I have doubts whether this is secure (not sure why), 2) I think the first option facilitates validation better, 3) I also don't think this would work in combination with the log in "remember me" option?
Implement an additional has-one through relationship that defines the organization a user is logged in for. This is basically an extension of the first option that adds a relationship. Since I already have so many relationships I don't prefer this option. Or is there no way around this addition for the first option?
Is the first option indeed an effective way to know/remember which organization a user is currently logged in for?
It really depends on which experience you're looking to create for the end user. In your cases:
This will allow remembering of organization between logins, which in your application, can be useful or complete non-sense. If indeed it's useful to remember an organization (i.e, the logistics of user choosing an organization after login is non-frequent), then this could create a better user experience.
session is secure, and you can use it like a hash and it would not collide with other features in your app (unless you use the same key). This case is suited for your application when user should always choose an organization after login, and thus it should be session based.
Ref: http://guides.rubyonrails.org/security.html
Like you mentioned, this is non-ideal, as you already know.
You can store the information in sessions hash, but not use cookie store, instead use Active Record store

Rails 4 proper way to prevent wrong user creating likes

I tried to find this on google but can't seem to find anything on this. I have a model called Likes, along with a controller which simply belongs to an Event and a User. I would like to prevent people from creating a Like when they're not logged in, and not allow them to create a like for another user. What is the proper way to do this?
Thank you
When you have a user based system, all queries related to user-owned data need to include the user, or originate from it. Most authentication systems have a helper to get the current user, often called current_user.
Assuming some things about your model, for "liking" an event, you could do it a couple ways:
current_user.likes.create(event_id: params[:event_id])
Like.create(event_id: params[:event_id], user: current_user)
Validations can help as well, making sure event and user IDs are always present. If no user is logged in, this should make it fail, assuming someone guessed the path to try and manually create a like.

Rails prevent double vote via cookies?

Relatively new rails programmer here, so bear with me.
I have an app where registered users can create polls but anyone can answer the polls.
I am using Devise for my authentication. I want non-authenticated users to be able to answer the polls but I want to prevent double-voting.
I assume this should be done with persistent (not session) cookies, but I'm not sure. So when the user enters the site, I create a user in devise and I store some random value in both the User model and in the cookie, and I check that the user has not answered the question previously when he/she attempts to load my "answer" page?
Can someone give me some advice on whether this is the right approach and/or point me towards a resource to help me get started?
I have found relatively little information out there on how to manage persistent cookies in Rails.
You can't reliably prevent people from voting multiple times without logging in. It's not possible. I guess people could also create multiple user accounts to vote so there is no fool proof way.
Cookies are often cleared automatically by certain popular cleaners and unless you are only going to allow people to vote on a product they have purchased I think you are kind fighting a lost battle.
Stack Overflow limits voting capability by making sure a certain level has been achieved before being allowed to vote but I guess that's not really applicable to your scenario.
This is not so much about sessions and cookies and more about setting up your database to record a vote including the voter id.
In the view that allows users to vote I would suggest that you switch between a voted icon and a vote now link depending on whether or not the currently logged in user has voted.
To determine if the user has voted then include the user id of the currently logged in user in a question_vote xref table.
For the belt and braces approach to prevent abuse of the html in the browser add the check to the validations of the question_vote record.
I would do this by adding a can_vote? method to the user model that accepts a question id as a parameter then you can use the question_id plus the user id to find a matching record in the question_vote table if a reordx is found return false otherwise return true

rails 3 - devise block user to login

i have something in mind, i have some user types, Building owner, building manager.
I want to create user as building manager, but i dont want they have access to login system. this user are only for some selectbox in my website, but i need to show them in my user index page.
what i think i can do is create normal user and with a before_save i create a new data in another table.
In a request i need to be able to setup in my building form more than one building manager. maybe the best are with nested form.. I think i will need to add building id to my user table. maybe they can be assigned more than one building.
for now, my db structure are like this :
table users with user data (username, password, email, first and last name, phone)
table usertype have userid, typename and accesslvl
But this problem give me some managing problem. They will not be associated with user data.
How can i resolve this? Does Device can block some user? I searched in the Devise docs, but nothing found.
Thanks for your help.
There is an approach where admin users can approve other user accounts for login. You could use a similar approach but programmatically approve the accounts you actually want to allow logins for. Details are here:
https://github.com/plataformatec/devise/wiki/How-To:-Require-admin-to-activate-account-before-sign_in

devise/cancan demo account

I'm using devise/cancan for my app and everything is pretty sound -- provided a user creates an account and signs in.
What I'd like to do is allow a user to get started without creating an account. And then sign up if they want to actually save their work.
Has anybody come across this before? Should I be figuring out how to create dummy accounts with devise? Or allowing unauthorized users access to creating models in my app via CanCan?
I could go into detail about how I've been thinking about approaching this, but it feels like a pretty obvious use case that somebody has come up with a nice solution for.
Thanks in advance,
Mike
If you go with creating dummy accounts, you would have to track the user somehow via a cookie and cache the values in that cookie in your db. Cancan does allow for guest accounts via the ability model. For example:
user ||= User.new # Guest user, for users who are not registered or don't have an account yet
Which is enough you to you started with applying permissions for non registered users. Note though, tracking by cookie alone is not very reliable and can lead to some type of security hazard (i.e. by means of cookie hijacking). User, one day, can also decide to clear out his cookies.
If need be, I would suggest letting the user do minimal interaction with a guest account and motivating the user to sign up / register with Devise as much as possible.
Hope that helps!
I actually am considering the same problem, I have a scheduling app that makes a calendar. To get over the problem I'm thinking that you use
user ||= User.new
Like was suggested above and using cookies to get the data to the database once the user creates an account.
This would mean that you would not have to worry about clearing out cookies because they would create an account if they want to save data.

Resources