Devise: Show error when the user is already confirmed - ruby-on-rails

I would like to show a error message when a confirmed user tries to resend confirmation. Is this something that is already provided by devise or should i have to override some of their methods? If so which methods?

I got this working by overriding create action of confimations controller
def create
self.resource = resource_class.send_confirmation_instructions(resource_params)
if successfully_sent?(resource)
flash[:notice] = "Confirmed already, Please try signing in" if resource.confirmed?
respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
else
respond_with(resource)
end
end
I am just overriding the flash notice in the case of confirmed user

The first thing you want to decide is if you really want to put a message for confirmed users. This might allow user enumeration (i.e have a robot try to find the users' email on your site... that's why there's the paranoid mode.
If you truly want to display a confirmation message, you do not need to override the controller. Your user will already have an error in the resource something like: "was already confirmed, please try signing in". You therefore don't need to modify the flash for this, you might simply want to use devise_error_messages! (or your own custom code to display error content).
Hope this helps.

Related

How to display errors in activeadmin forms after overriding controller

I have a situation where I need to override create in activeadmin. I autofill the fields and if the data already exists it should update otherwise create. Here is my create method:
def create
id = params[:company].dig(:id)
if id.present?
#company = Company.find(id)
if #company.update(permitted_params[:company])
redirect_to resource_url
flash[:notice] = 'Company created successfully'
else
#add errors to semantic errors
end
else
new_permitted_params = permitted_params[:company].except(:id)
#company = Company.new(new_permitted_params)
#company.save
if #company.errors.any?
#add this to semantic errors so that activeadmin handles and displays the errors
end
end
end
I want to display the errors which violate the validations so that the user knows if he/she has entered an invalid entry.
I found this but it looks like a workaround more than a solution. Please help me solve this.
Thanks in advance.
I created a new HTML file in views named new.html.arb and added insert_tag renderer_for(:new) in it. After that all I did was
if #company.errors.any?
render 'new'
end
I discovered it by seeing the default behavior of activeadmin. I hope this helps other people who are looking to do something similar. This is the result that I get and which was required by me.
I wonder if client side logic to submit to different URLs depending on id.present? might make things more restful.

Check if a model is confirmable

I'm kinda new to Rails, so if I am doing this totally wrong, just tell me :)
I have two models built with devise in my rails app, one is confirmable, the other is not.
I would like to set the after_sign_up_path_for(resource) on the user home page or on a separated page indicating that a confirmation email has been sent depending on wether my resource has to confirm its registration or not.
I can check existence of the confirm fields in the data model, but is there a cleaner way to do it, something like resource.confirmable?
Is there a cleaner way than overwriting after_sign_up_path to redirect to different pages depending on wether the model is confirmable ?
Thanks
You could do something like the following:
resource.class.devise_modules.include?(:confirmable)
Or
resource.respond_to?(:confirmed?)
Regarding to check if the user is already confirmed, you could use the following:
def after_sign_up_path_for(resource)
if resource.class.devise_modules.include?(:confirmable)
if resource.active_for_authentication?
"path for confirmed user"
else
"path for waiting for confirmation"
end
else
"path for non confirmable model"
end
end
Check out the docs: http://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Confirmable

Rails How to Login a Guest User with Devise

So I have this app that I'm making where users have profiles after they signup and input their information.
At the moment I'm trying to add a feature that allows for new unregistered users to go to a profile to see what the app is like before they need to sign up (I'm planning on putting a "try it for free" button on the home_controller#index action. For authentication, I'm using the Devise gem.
Currently, I've watched the Railscast (393) on this, but I can't figure out (after several hours of trying) how to implement guest users and log them in using Devise.
I've also read about 4 different solutions on SO, and have decided to stick to this one (how to create a guest user in Rails 3 + Devise):
class ApplicationController < ActionController::Base
def current_user
super || guest_user
end
private
def guest_user
User.find(session[:guest_user_id].nil? ? session[:guest_user_id] = create_guest_user.id : session[:guest_user_id])
end
def create_guest_user
u = User.create(:name => "guest", :email => "guest_#{Time.now.to_i}#{rand(99)}#example.com")
u.save(:validate => false)
u
end
...
end
I have this in my application_controller.rb and don't understand how I would use these functions in the home_controller#index to create a guest user and log into the profile when the "Try it" button is clicked.
I've tried manually creating a user, saving it without authentication and then using Devise's sign_in method on link like so: Try it! and also tried
Try it!
I tried this, but the profile throws some validation messages saying I need to log in to view it. I've also tried removing before_filter authenticate! on the profiles_controller but I can't seem to get this to work at all.
Would anyone know how to create a user on the button click, and auto sign them into a guest profile? Thanks a lot for any help, I'm completely lost here.
I think you have a misunderstanding on what a guest user is. You say that you want guest users to auto sign in, and that is wrong. Guest users can't sign in, because... Well, because they are guests. You want to create them, but not sign them in.
This is why you want these helper methods in your ApplicationController, because when you try to get the current_user, if that doesn't exist (nil), you will have a fallback (that is why you use the || operator), that will assign a guest_user as a current_user.
So, forget about using sign_in links for guest users and you should be fine.

Rails validation is still firing despite unless option evaluating to true

I use devise_invitable in my app to allow users to send invitations. I realized a bad case in which a user has been invited but ignores the invitation and later returns to the app to sign up on their own. Because devise_invitable handles invitations by creating a new user using the provided email address for the invitation, my uniqueness validation on the email field will cause Rails to complain, telling the user that the email address is already taken.
I'm trying to write some logic to handle this case. I see two paths - either figure a way to detect this and destroy the previously created user and allow the new one to be created, or detect the user was invited and execute another flow. I've decided to implement the second option, as I'd like to still utilize the invitation if possible.
My limited experience has me questioning if what I've written will work, but I can't actually fully test it because the Rails validation on the email is triggered. I've made sure Devise's :validatable module is inactive. I created a method that (I think) will detect if a user was invited and in that case the uniqueness validation should be skipped.
#user.rb
...
validates :email, uniqueness: true, unless: :was_invited?
...
def was_invited?
if self.invitation_sent_at.present? && self.sign_in_count == 0
true
else
false
end
end
FWIW, I had originally written this in shorthand rather than breaking out the if/else, but I wanted to be very explicit in an effort to find the bug/failure.
The hope is that once the form passes validation, the create action will do some detection about a user's invitation status and, if they were invited, redirect them to the accept_user_invitation_path. Again, I haven't been able to actually test this yet because I can't get around the validations.
#registrations_controller.rb
def create
if User.find_by_email(params[:email])
#existing_user = User.find_by_email(params[:email])
#existing_user.save(validate: false)
if #existing_user.was_invited?
redirect_to accept_user_invitation_path(:invitation_token => #existing_user.invitation_token)
end
else
super
end
end
In a desperate effort, you'll see I've also added the .save(validate: false) to try to short circuit it there, but it's not even getting that far.
If I comment out the email validation entirely, simply to test the rest of the logic/flow, I get a PG error complaining on uniqueness because of an index on the email address - I don't want to tear all this apart simply to test this method.
I've tried to mess with this for hours and I'm at a loss - any help is appreciated. Let me know if there's any other code you want to see.
Looking at the redirect:
redirect_to accept_user_invitation_path(:invitation_token => #existing_user.invitation_token)
I can see that there is no return which should mean that if that redirect was being called you should be getting an AbstractController::DoubleRenderError error as the parent controller's create method should be trying to render the new view.
From this I would guess that the query you are using to find the existing user is not actually returning a result, possibly because you are using params[:email] whereas if you are using the default views or a properly formatted form it should be params[:user][:email].
Maybe you should give more responsibilities to your controller...
If you find the user, use that, else create a new one. Assuming your form appears with http://yourapp/users/new, change it in your routes to http://yourapp/users/new/:email, making the user input their email before advancing to the form.
def new
#existing_user = User.find_by_email("#{params[:email]}.#{params[:format]}") || User.new
if #existing_user.was_invited? # will only work for existing user
redirect_to accept_user_invitation_path(:invitation_token => #existing_user.invitation_token)
else
render 'new'
end
end
def create
# do maybe something before saving
if #existing_user.save(user_params)
# do your magic
else
render 'new', notice: "Oops, I didn't save"
end
end

Rails: How to enter value A in Model X only if value A exists in Model Y?

I'm trying to build a registration module where user can only register if their e-mail is already in an existing database.
Models:
User
OldUser
The condition on User will be
if OldUser.find_by_email(params[:UserName]) exists, allow user registration.
If not, then indicate error message.
This is really simple to do in PHP where I can just run a function to execute a mysql query. However, I couldn't figure out how to do it on Rails. It looks like I have to create a custom validator function but seems to be overkilled for a such simple condition.
It should be pretty simple to do. What have I missed?
Any pointer?
Edit 1:
This solution by dku.rajkumar works with a slight modification:
validate :check_email_existence
def check_email_existence
errors.add(:base, "Your email does not exist in our database") if OldUser.find_by_email(self.UserName).nil?
end
For cases like this, is it better to do validation in the model or at the controller?
you can do it as
if OldUser.find_by_email(params[:UserName])
User.create(params) // something like this i guess
else
flash[:error] = "Your email id does not exist in our database."
redirect_to appropriate_url
end
UPDATE: validation in model, so the validation will be done while calling User.create
class User < ActiveRecord::Base
validates :check_mail_id_presence
// other code
// other code
private
def check_mail_id_presence
errors.add("Your email id does not exist in our database.") if OldUser.find_by_email(self.UserName).nil?
end
end
I'd recommend starting with Devise.
See https://github.com/plataformatec/devise
Even if you have unusual needs like these, you can normally adapt it. Once you get to know it, it's extremely powerful, solid and debugged, and you can do all sorts of things with it.
Bellow is just an initial implementation .../app/controller/UsersController for User registration related actions.
def new
#user = User.new
end
def create
#user = User.new(params[:user])
#old_user = User.find_by_email(user.email)
if #old_user
if #user.save
# Handle successful save
else
render 'new' # and render some error message telling why registration was not succeed
end
else
# render some page with some sort of error message of 'new' new users
end
end
Update:
Check out the following resources for more info:
Ruby on Rails Tutorial
Rails: User/Password Authentication from Scratch, Part I/II

Resources