Rails/Devise: pass param after sign_in - ruby-on-rails

In my app I use Devise for authentication. Users can be invited to sign_in to the app through a link that has a token attached as a param.
The link looks e. g. like this:
https://chaos-jadz.c9users.io/tokens/?token_value=88042c1c-822e-4e80-b911-3c25a41fdc3f
At the moment once a user signs in the app redirects to the root path.
What I want to do now is: once a user signs in and if token_value is present then I want the app to redirect to a specific controller/action with the token as param.
I'm aware of the after_sign_in_path method Devise provides. Redirecting after sign_in to my specified controller/action is no problem. However I am not aware how to pass the param token_value also to the controller/action.
This is my sign_in form (I am using the param here as a hidden field):
<div class="panel panel-default devise-bs" style="font-family:arial">
<div class="panel-heading">
<h4><%= t('.sign_in', default: 'Sign in') %></h4>
</div>
<div class="panel-body">
<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { role: 'form' }) do |f| %>
<div class="form-group">
<%= f.label :spielername %>
<%= f.text_field :username, autofocus: true, class: 'form-control', placeholder: "player101" %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, autocomplete: 'off', class: 'form-control' %>
</div>
<div class="form-group">
<%= f.hidden_field :token, :value => params[:token_value], class: 'form-control' %>
</div>
<% if devise_mapping.rememberable? %>
<div class="checkbox">
<%= f.label :remember_me do %>
<%= f.check_box :remember_me %> <%= t('.remember_me', default: 'Remember me') %>
<% end %>
</div>
<% end %>
<%= f.submit t('.sign_in', default: 'Sign in'), class: 'btn btn-primary' %>
<% end %>
</div>
</div>
<div class="col-xs-12 shared-links">
<%= render 'devise/shared/links' %>
</div>
Can you help?

I was facing a similar, if not identical, problem trying to pass params from a Devise registration form through the default auto-login via after_sign_in_path_for(resource). The goal was to route a new user to the page from which they had originally clicked the "Sign up" button. (It's an events app, and the user should be sourced back to the event they came to sign up for.)
I got it working by including a hidden form field as you did, and making sure it was permitted by including this in my ApplicationController:
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:event_token])
end
Then I just referenced resource.event_token in the after_sign_in_path_for(resource) block:
def after_sign_in_path_for(resource)
if resource.event_token
event_path(Event.find_by(token: resource.event_token))
else
user_path(resource)
end
end
So if a user signs in with an event token, it fires; if not, it doesn't.
I imagine you could do the same thing with resource.token to pass your params forward inside the path helper.

if you have specific url for that controller/action then below code will work
def after_sign_in_path_for(current_user)
specific_url(token: params["user"]["token"])
end

Related

Rails/Devise. Include captcha response param within sign_in process

Without making a custom Sessions controller that inherits from the hidden devise controller, I want to figure out a way of adding the parameter, "g-recaptcha-response" to be included in the authenticating process from the default devise view.
Here's my view with the recaptcha figure included. When I click on it I do get a response when my app calls the SessionController#create method. I'm trying to figure out how to make this process detect that the captcha form has been clicked and authenticates the user logging in because of it.
<h2>Log in</h2>
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<% if devise_mapping.rememberable? -%>
<div class="field">
<%= f.check_box :remember_me %>
<%= f.label :remember_me %>
</div>
<% end -%>
<div class="g-recaptcha" data-sitekey="6LeeL5gUAAAAADbq0vt4d9biAs8oegkPx9ttUkKb"></div>
<div class="actions">
<%= f.submit "Log in" %>
</div>
<% end %>
<%= link_to 'Sign Up', new_user_registration_path %>
In essence, if a bot were to attempt automatically signing in repeatedly, the devise controller would see that the captcha was not clicked and stops them from trying to log in.

Navbar login form in a Rails web app (with Bootstrap)

I'm making a Rails web app with the limited knowledge I have - mostly from the Hartl Rails Tutorial. I'm also using Bootstrap.
I decided it would be good to have a dropdown login form in the navbar, in addition to the form at '/login'. The form looks nice enough, but I can't get it to work.
Here is my current code for my working, '/login' form:
<%= form_for(:session, url: login_path) do |f| %>
<div class="form-group">
<%= f.label :username %>
<%= f.email_field :username, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<%= f.submit "Log in", class: "btn btn-primary center-block" %>
<% end %>
Here's my code for the non-working navbar form:
<%= form_for(:session, url: login_path, method: :post,
html: { role: "form", id: "navbar-login" }) do |f| %>
<div class="form-group-sm">
<%= f.label :username %>
<%= f.text_field :username, class: 'form-control',
name: 'username', placeholder: 'Username' %>
</div>
<div class="form-group-sm">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control',
id: 'password', name: 'password',
placeholder: 'Password' %>
<%= link_to "Forgot password?", '#' %>
</div>
<%= f.submit "Log in", class: "center-block" %>
<% end %>
And here's my sessions_controller.rb create method:
def create
user = User.find_by(username: params[:session][:username])
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to user
else
flash.now[:danger] = "That email and password combination isn't
correct."
render 'new'
end
end
The error I get when submitting the form is as follows:
NoMethodError in SessionsController#create
undefined method `[]' for nil:NilClass
The error also points to this line of the create method:
user = User.find_by(username: params[:session][:username])
I guess the answer is pretty simple, but I can't quite figure it out. I'm sure it must be either form_for or the create method that isn't working.
Thanks in advance for any help.
Remove the name attribute from every field in the form.
Rails handles it for you and the way you are naming it is not creating the param that you expect.

How to create an error message when users enter incorrect inputs on registration or form submission

I have two forms on my rails app that require a user to enter a code to confirm that they belong to a school and in the other form a code for a classroom. Every time a user enters or leaves the code blank I get this error message:
First argument in form cannot contain nil or be empty
It's always in the create method of the controller so I must not have the correct syntax.
Here are the two controllers where the error occurs.
Registration Controller
class RegistrationsController < Devise::RegistrationsController
skip_before_filter :verify_authenticity_token, :only => :create
def update
super
end
def new
super
end
def create
code = params[:user][:code]
#school = School.where(:code => code).first
unless #school
flash[:error] = "School code not valid"
render :new
end
params[:user][:school_id] = #school.id
super
end
School controller
def create_teacher
authorize #school
params[:user][:school_id] = #school.id
params[:user][:role] = "teacher"
#teacher = User.create(teacher_params)
if #teacher.id.nil?
flash[:error] = #teacher.errors.full_messages
render :new_teacher
else
respond_with #school
end
end
How do I correct this issue so that it renders a flash error message?
EDIT Screen Shots of actual error. Note, they are both in the create method so I think it's an identical problem.
EDIT: Registration form for adding users to schools.
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h1>Sign up</h1>
</div>
<div class="panel-body">
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :school_code %>
<%# f.text_field :code, class: "form-control" %>
<input type="text" id="code" name="user[code]" value>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, class: "form-control" %>
</div>
<strong>Student</strong> <%= f.radio_button(:role, "user") %>
<div class="form-group">
<%= f.submit "Sign up", class: "btn btn-lg btn-primary" %>
</div>
<% end %>
</div>
<div class="panel-footer">
<%= render "devise/shared/links" %>
</div>
I think the issue is with your <%= form_for .. %> I can get the same error if I enter an invalid argument for that. For the school one try <%= form_for #school %> And make sure your new method in your controller (whichever one is rendering the page with the form) is making a new instance of the object,
def new
#school = School.new
end
And the same with the pin
Something like this may be what you're looking for
before_action :check_code, only: :create
...
def check_code
unless School.find_by school_code params[:school_code]
flash[:error] = "Invalid school code"
redirect_to new_reg_path
end
end
And to show the flash message
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>">
<%= message %>
</div>
<% end %>

Devise login form within Bootstrap Modal, prevent close and redirect after wrong login

I have a devise login form built into a bootstrap modal. Login works great. However, if a user enters the wrong login information the modal window closes and redirects. How can I prevent this default action happening in rails, and keep the modal open to include the error messages.
Thanks!
Code:
<div class="modal" id="LoginModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
<div><%= f.email_field :email, :autofocus => true, class: "form-control", placeholder: "Email" %>
</div>
<%= f.password_field :password, class: "form-control", placeholder: "Password" %>
</div>
<div class="form-extra">
<% if devise_mapping.rememberable? -%>
<%= f.check_box :remember_me, class: "remember-check" %> <%= f.label :remember_me, class: "remember" %>
<% end -%>
</div>
<div><%= f.submit "Log in via email", :class => "btn btn-email" %></div>
<%= render partial: 'layouts/flash_messages', flash: flash %>
<% end %>
</div>
</div>
You will probably need to do some custom javascript. That can be done a couple ways.
Remove the submit button and just have an input button with an id. When that is clicked, send the request to your registrations controller to render back an ajax response. Display the message if there is an error, redirect to the login page if it returns a session.
Prevent the default action and then handle the request through ajax, if you get a valid session back allow the default submit action to continue. Otherwise display the message.

Devise current_user not working after making registration a partial via application helper

So earlier, my devise code would work no problem. However, today, upon changing up some of the website, including making my devise registration a partial and adding the following code to my application helper (sorry this was wrong earlier, was tired :P)
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
the current_user method no longer works. Could anyone tell me why?
The code for the partial is
<div class="panel panel-default">
<div class="panel-heading">
</div>
<div class="panel-body">
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="form-group">
<h5> <FONT FACE="HELVETICA NEUE"> Name</font></h5>
<%= f.text_field :name, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<h5> <FONT FACE="HELVETICA NEUE"> Company </font></h5>
<%= f.text_field :company, class: "form-control" %>
</div>
<div class="form-group">
<h5> <FONT FACE="HELVETICA NEUE"> Real Estate Email </font></h5>
<%= f.email_field :email, class: "form-control" %>
</div>
<div class="form-group">
<h5> <FONT FACE="HELVETICA NEUE"> Telephone</font></h5>
<%= f.telephone_field :telephone, class: "form-control" %>
</div>
<div class="form-group">
<h5> <FONT FACE="HELVETICA NEUE"> Password </font></h5>
<%= f.password_field :password, class: "form-control" %>
</div>
<div class="form-group">
<h5> <FONT FACE="HELVETICA NEUE"> Confirm Your Password </font></h5>
<%= f.password_field :password_confirmation, class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Sign up", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
The issue will likely be this:
making my devise registration a partial
current_user
When you mention your current_user method "no longer works", I don't think the case will be it won't be working; it will likely be your changes which are preventing it from working.
Without code, I can only speculate, but there are several things you need to clear up:
--
event handler
You mention you have included the Devise resource helpers in your "event_handler". I'm not sure what you mean, but the surest way to get this working is to use the official Devise documentation & put it in application_helper.rb:
#app/helpers/application_helper.rb
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
--
partial
You mentioned you're using a partial to get show the devise registration view. This is fine, but how are you passing the data to it? You'll probably have an issue whereby you cannot access the resource helper, as it's been assigned to the event_handler

Resources