Attaching existing order (order.email) to create an account, Devise? - ruby-on-rails

This is the scenario I would like to accomplish:
User creates an order (enters email into order table).
User is sent order confirmation email with link to sign up.
If User decides to sign up, it will connect to the account.
What would it take to accomplish this?
I'm a bit mixed up because the Order is already created and wouldn't have a current_user for the order model to attach to the User model. How would I then have it so the order.buyer_id (which is used for the current_user of the User who creates the Order) then gets associated with the to-be-signed up User who just created the order. How could I somehow embed this information in the "sign up" link that gets sent? To somehow say "if this email signs up and is confirmed, become the buyer_id for said order"?
Also, is this good practice?
Other option:
Or should I just have a "email" and "password" field when checking out where the User field get sent ahead of the payment token so the order attaches to the current_user?
Does anyone have other ideas or what I should do?
Other than this, the only thing I'm currently doing is a simple "sign up before ordering if you want to save your orders"

Email is unique for each user so after user signed up and account created you can run a small query where you assign created user to orders. It can be accomplished in the model
class User < ActiveRecord::Base
after_create :connect_orders
...
def connect_orders
Order.where(email: self.email).updated_all(buyer_id: self.id)
end
end

Related

Rails validation vs authorization

I have a scenario where I am unsure of whether a particular function should be considered validation or authorization. I can code it either way.
Users can "like" articles.
When a user creates a new "like" I need to ensure the user has not already liked the article. The front end will limit the functionality however I want backed end safeguards.
Should the process of ensuring a user has not already liked the article be considered validation or authorization?
Further to comments received:
If auth determines if the option is available to the user, or not & validation determines if the user selection is valid then...
Auth will make the option to click "like" available even when then user has previously "liked" and therefore it will inevitably fail validation.
This thinking results in an invalid option being presented to the user.
Is ensuring the user can only delete/edit their own "likes" auth or validation? The previous logic implies it should be validation as the user is either authorised to add/update or destroy within the model or not and ensuring their actions are valid is the role of validation However it would be illogical to present the option to delete another user's like only to reject upon failed validation.
This is validation. I don't know your model architecture, but if you have a Like model, you could validate like this:
class Like < ActiveRecord::Base
belongs_to :user_id
belongs_to :article_id
validates :article_id, uniqueness: { scope: :user_id }
end
You should also make sure that a unique constraint is present at the DB level, to avoid a potential race condition.
This sounds more like validation. You have to check in your model that this article was liked by this user or not. If it is, then this like is invalid and he can't like it now. Otherwise, it will pass the validation and the user will be able to like this article.
Authorization should come, when some user can like some set of articles, but not all, in those situation, In my honest opinion.
a. should use rails validation to make sure he/she can like once not more then that.
b.authorization is to restrict user from hitting like.
authorization would be: is this user allowed to perform this action; validation: will this action succeed. given that user is allowed to 'like', ensuring he can do it only once is a validation problem. to solve it put unique constraint on db level (user_id, article_id).

How do I change user status along with Devise actions

I'm using Rails 4.1 with Devise 3.2.4
I'm using Devise's email confirmation to setup user accounts, but I also need do things after email confirmation such as setup billing information before an account can be considered active.
How do I manage a user's status along with Devise's mechanism?
I.e. when a user first signs up, I want their status to be "new". When they confirm their email, I want their status changed to "email_confirmed", and when they submit payment information, I want it to change to "active". I also want to account for when they change their email address -- their status needs to return to "new".
Devise uses "confirmation_token" field in users table. You can use it to set all of you conditions. You can add a boolean field in users table lets say 'active'(default false). When a new user signs up "confirmation_token" field contains your token so you could check for its not nil condition but we don't need user to be active now so 'active' field will remain false. Now when a user clicks on the link in email, devise changes the "confirmation_token" field to nil so again you could check it but we still don't want the user to be active so your 'active' field will remain false.
Now if you look at devise github repo when a user clicks on the confirmation token in email, your app is redirected to confirmation controllers show action.
In your case what you can do is redirect the user to your payment information page with a notice saying something like "you need to complete payment information to do transactions" or whatever you may like. You'll have to override devise after_confirmation_path method for that something like:
# The path used after confirmation.
def after_confirmation_path_for(resource_name, resource)
if signed_in?(resource_name)
signed_in_root_path(resource)
else
# your payment information page path
end
end
And when user completes the payment information details successfully you can set his/her active field to true and build on from there.

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.

Generate unique usernames in rails

How can I generate unique usernames based on a format. So for example the first user signs up. The username for him is AAA001 the second user signs up the username will be AAA002, and it keeps incrementing like that. How can I set it up so even if two users click sign up at the same time the database just sends them each a unique username. This is gonna be done on RoR.
Thank you in advance
you can generate the username in the after_safe hook of the model and save! again in a transaction (to prevent race conditions) and use the DB-ID of the already saved user to generate the username
You need to use database transactions.
Here is an example:
ActiveRecord::Base.transaction do
#code goes here
end
This will ensure that the code inside the transaction is blocking.

Pass Account ID to New User During Sign Up

Currenntly, my application is designed using Devise for authentication. I have it so when the first user signs up, an account is created in an Accounts table and the account_id is passed to the User table. I also have it set so that each time a new account is created that user is tagged as an admin. Finally, I have it working where the admin can create new users.
My problem is that at the time the new users are created I need to have these users be assigned the same account_id as the admin to tie the users together. I can do this if I add an account_id field on the form and have the admin manually enter it. What I want to have is that this is automated in the background.
I tried many varieties without success. This is one of the unsuccesful attempts where I put the following in the user.rb
before_save :add_account_id_from_parent
def add_account_id_from_parent
return true unless self.users.present?
self.users.update_attribute(:account_id, 1)
end
I used the number "1" just to see if I could get anything automated and placed in that field.
Like I said manually everything works, but I want it so the acocunt_id is automatically added during sign up based on the admins account_id.
I'm a bit confused why you are calling self.users. If I understand correctly, you want to assign account_id to 1 after a new user is created (as a test). You can do that like this:
before_save :add_account_id_from_parent
def add_account_id_from_parent
self.account_id = 1
end
You don't need to actually update the record since this is assigned before save, and save will write the new value to the db.
Again I might be missing something, if so please clarify.
UPDATE:
If you're validating that account is present, you'll need to change the callback to a before_validation instead of before_save, like so:
before_validation :add_account_id_from_parent

Resources