I might be approaching this problem the wrong way ... so if you have a more elegant solution I'm all ears.
Imagine I'm making a system like Kickstarter. I want my users to be able to specify how much they want to pledge before I ask them to sign up.
Then, if they're not registered I need them to sign up before putting them back in the flow that they would have been on had they just signed in. Devise makes this easy by redirecting a user back to the after_sign_up_path_for which ends up being after_sign_in_path_for by default.
So this will always issue a GET request. But if I have data that I received from the POST with the amount they wanted to pledge, but that's lost.
Is the only way to do this to store that posted data in the session? Or is there a clever way to start creating the pledge record without the user (without needing to run jobs to destroy orphaned pledge records)?
I found the approach described in this blog post over at highgroove.com quite interesting in this regard:
http://highgroove.com/articles/2012/10/09/lazy-user-registration-for-rails-apps.html
The basic idea is to always have an anonymous user at hand, even if the current vistor is not registered. Like this you can create e.g. associations as usual and — once the visitor actually does sign–up — you edit the user rather than all associated objects.
If the user does not ever register, you can simply look for abandoned user accounts and delete them including their associations, rather than look for all kind of abandoned models.
Related
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.
I'm stuck figuring out the best practice...
I want to create a "following" system in a way that a user can follow a car (getting email updates when car price changes, etc). The part of implementation that's giving me headaches is when I want to introduce lazy registration by only using email.
Everything needs to work as AJAX requests.
In the interface, there will be a button to trigger the follow action, which will check if the user is registered or not. If a user is logged in, create a new CarSubscription item, otherwise display a form where he could type his email address. Once submitted, the form should create a user with no password (if email exists, ask for the password and log in) and then it should create the relationship item.
The challenge here is to use redirection after submission of the form to the CREATE action of the CarSubscriptionController. Since I can't redirect using POST I can't simulate the CREATE or DESTROY action.
The non-RESTful solution would be to create 2 actions under cars_controller: follow and unfollow and let them do the logic of creating entries and deleting them. That would enable me to just store the request path and use it after the user enters their email and logs in.
How can I achieve what I want using RESTful resources?
After trying to describe my problem here, it seems it's way too complicated and I am indeed very stuck... There are 3 different controllers and possibly 4 requests in this scenario.
Any help would be tremendously appreciated!
Please see my flow chart below:
Not an expert here, I don't know if it's the best solution, but what I have done in similar situation is :
In your controller, respond with javascript instead of redirecting the user
In your javascript file, use $.post(...) to issue a POST to your controller action
Et voilà!
You can also use ActiveResource to achieve this, but I actually never tried that solution : http://api.rubyonrails.org/classes/ActiveResource/Base.html#label-Custom+REST+methods
Person.new(:name => 'Ryan').post(:register)
Hope this helps
I had a very similar need and had trouble pulling the various bits of info on how to do this with Devise and Rails together into a working example. Here's a fully working example based on Rails 4, Ruby 2, and Devise 3.0:
https://github.com/mwlang/lazy_registration_demos
Right, im building an order form for a site that doesn't require any kind of user signup or authentication. The form has three models: Order, OrderImage, Print. An order form has many OrderImage's and an OrderImage has many Prints.
A user requires the ability to Upload images (OrderImage's) with their order and also the ability to go back and edit each OrderImage before the Order is confirmed and submitted.
The form is multistep and made up of four stage:
Upload Images
Review Uploads
Your Details
Confirm Uploads
This is fine and everything is working as planned and data is stored to the database throughout the Order process as the user enters more details or uploads more images.
However, this means URL's such as "/upload?order=5" exist which isn't good. Because there is no authentication this means anyone could potentially guess the URL of an Order and change it.
So i'm just wondering what the best way of managing this process is? I've got a couple of ideas in mind, but not sure if any of them are the best solution for the problem:
Generate a random order number within 6 digits for example so the url would be more like: "/upload?order=645029". This would result in there being less chance of someone guessing an order number, but really not very secure still.
Combining the above idea with a status on the order, such as "Complete". So when an Order is finally submitted, it is marked as complete. I could then prevent any "Complete" orders from being accessed again. However, during the Order process, the order number could still be guessed and tampered with.
Making use of the session and storing the order number here instead of in the URL, or as a hidden value in the form.
I have watched Ryan Bates' Railscast on Multistep forms in which he stores data in the session. However, Ryan himself concedes that storing complex Models and objects this way isn't practical.
So any suggestions on the best way for handling a non-authenticated order form would be much appreciated, thanks.
I would go with option #3. You're right that it's not good to store complex objects in the session, but all you need to store is the ID number of the order, then you can look it up in the database. You can use a before_filter to ensure that the requested order belongs to the current user:
class OrdersController < ApplicationController
before_filter :check_ownership, :except => [:new, :create]
private
def check_ownership
redirect_to '/' unless params[:id] == session[:current_order_id]
end
end
This example could easily be extended later to allow users with accounts to view their order history (rather than just the current order). Options #1 and #2 are only masking the problem, and would probably be more difficult to extend later.
I hate to respond with a question... but: How does a user find his order when he come back to the site later?
Without registration, you have to find a way to associate a User with the order!.
I can't see how you could do that securely, whitout at least asking him a unique username.
But then, anyone would be able to guess this username and get to the order!.
I would say, if you don't want authentication... then you should not care that other user see orders of anyone!
If this is a problem, you will need a simple form of auth.
What would be the best way to go about giving users the ability to share a private link that enables anyone who clicks it to view a certain page/document/item that have privacy restrictions in place?
In my case:
A User creates events which are limited to certain groups of relationships in the database (namely: friends, friends of friends, etc.) I have a :before_filter in the event controller that checks the eligibility of the current logged in user to make sure that that user has permission to see the event. If they don't they get booted to the root page with an error message.
However, I want a special scenario to exist where a user can create an event with those same privacy settings and IN ADDITION, be able to share a special link with his or her friends via e-mail, facebook, etc. Those users do NOT need an account (but will need to make one in order to sign up for the event). This is important because there is also a :before_filter in the application_controller which makes sure a user is logged in.
I'm thinking there is something I could do with routing here... Right now I just have the simple /events/72 setup. Should each event have two different links: a normal one, and a "special code" version which enables them to bypass those two :before_filter?
What are people's thoughts?
I agree with David Lyod's answer (separating this concern in a different controller).
But for creating the hash I strongly recommend you salting the hash with some secret phrase.
require "digest"
Digest::SHA512.hexdigest("#{created_at}#{user_id}.mysupersonicsecretSALT")
Doing this it is not possible, without the knowlegde of the secret phrase, to calculate the hashes and test them against your system until it hits an existing one.
If you're handling sensitive data you should not be lazy.
Cheers,
Lukas
I would have a separate controller that uses a hash value to reference the event.
Something simple like the created_at + user_id hashed to create a unique reference.
You could also simply skip the check on a certain action but I would much prefer the first solution .
I'm looking at implementing some form of anonymous user system in Rails. I need to let people do things (creating records, looking at what they've created, etc), without actually creating an account. Once they create an account, everything persists without risk of losing it by clearing cookies or something.
Right now, I'm thinking it's pretty straightforward. Have an is_anonymous field in the User model, and use something like this to access the currently logged in user:
def find_user
session[:user_id] ||= create_new_anonymous_user.id
end
Assuming the session persists for some reasonable period of time, and the session cookie doesn't expire, that should keep everything running smoothly.
However, there is this piece of me that is convinced that I'm missing something security-related. Has anyone done something like this before? Am I missing something super-obvious?
Thanks!
The only real security issue is going to be if these anonymous users can perform critical operations.
Your system means that anyone with the specific cookie will gain access to the site. Not necessarily a big deal, but it really depends on the type of information your users are providing.
I have done something similar in the past (in my case I was tracking progress through a site and when the user logged in or registered, I attached the "guest" data to their account. When you do the switch, make sure you delete the anonymous record to prevent further access and it should be fine.
I just found a pretty cool example of "trial users" using Authlogic: http://github.com/gisikw/authlogic_trial
Assuming the session persists for some
reasonable period of time, and the
session cookie doesn't expire, that
should keep everything running
smoothly.
Perhaps you should set a separate long lived cookie for the new user, so they can have multiple sessions (at least from that browser).
Are you sure that you want to let people create objects that are tied to accounts that may not exist? Unfortunately I don't know much about what your application is actually doing but I would think that going down this path might leave you with a bunch of orphaned objects not really "owned" by any real users.
If you really do want to do this I think what you have is decent. You could be creating a real user, flagged as "guest" (or whatever) and once the user wants to really register they are prompted for other information and unflagged. You should add access control for guest vs non-guest, etc.