I am using devise for authentication and i have a problem in the recover password form, whose link is sent by e-mail. When I define a new password, the form is sending a POST request, instead of a PUT. It's redirecting to user/password# with 'Email can't be blank' notice.
So, edit.html.erb has method: : put, but it isn't working.
<%= form_for(resource, as: resource_name, url: user_password_path(resource_name), html: { method: :put }) do |f| %>
I'm stuck in this all day and haven't figured a way out
This is the full edit.html.erb
<h2>Change your password</h2>
<%= form_for(resource, as: resource_name, url: user_password_path(resource_name), method: :PUT) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<%= f.hidden_field :reset_password_token %>
<div class="field">
<%= f.label :password, "New password" %><br />
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em><br />
<% end %>
<%= f.password_field :password, autofocus: true, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation, "Confirm new password" %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="actions">
<%= f.submit "Change my password" %>
</div>
<% end %>
This is the generated form
<h2>Change your password</h2>
<form class="new_user" id="new_user" action="/user/password.user" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="_method" value="patch" /><input type="hidden" name="authenticity_token" value="Zf5rxkU11tVmt4i8hDpFPDL5y+/jzRQT/O/si6RnraidCN5vxofmVS1abO4nJ8iqlncZfCRr1jdLjMfxwMx45A==" />
<input type="hidden" value="xk6EkLsyxCyvvpDyY6Ug" name="user[reset_password_token]" id="user_reset_password_token" />
<div class="field">
<label for="user_password">New password</label><br />
<em>(6 characters minimum)</em><br />
<input autofocus="autofocus" autocomplete="new-password" type="password" name="user[password]" id="user_password" />
</div>
<div class="field">
<label for="user_password_confirmation">Confirm new password</label><br />
<input autocomplete="new-password" type="password" name="user[password_confirmation]" id="user_password_confirmation" />
</div>
<div class="actions">
<input type="submit" name="commit" value="Change my password" data-disable-with="Change my password" />
</div>
</form>
My passwords controller
# frozen_string_literal: true
# Deals with user login and generates JWT
class User::PasswordsController < Devise::PasswordsController
prepend_before_action :require_no_authentication
# Render the #edit only if coming from a reset password email link
append_before_action :assert_reset_token_passed, only: :edit
skip_before_action :verify_authenticity_token
respond_to :json
wrap_parameters :user
before_action :configure_permitted_parameters, if: :devise_controller?
def create
super
end
def edit
super
end
def update
super
end
def new
super
end
end
My routes.rb
constraints subdomain: 'api' do
scope module: 'user' do
devise_for :users,
path: '/user',
path_names: {
registration: 'signup',
sign_in: 'login',
sign_out: 'logout'
},
controllers: {
sessions: 'user/sessions',
registrations: 'user/registrations',
passwords: 'user/passwords'
}
Server log
Thanks in advance
I ran into this same issue using the Devise password reset functionality. I was adding Devise to an API Rails application (config.api_only = true) and apparently the Rack::MethodOverride middleware that is responsible for identifying the hidden method attribute and changing the request to a PUT/PATCH request was not included in the API-only middleware stack. As a result, the request made it to the main app still as a POST request.
I added the following line to config/application.rb, which solved the problem:
config.middleware.insert_after Rack::Runtime, Rack::MethodOverride
Related
I have a ruby on rails project that is using the devise gem for authentication. I'm trying to use a captcha form in the sign up page to prevent bots from creating thousands of dummy logins
I'm not interested in using the recaptcha gem that works with devise as I haven't had any luck setting it up correctly.
I trying to set it up using this as a reference https://recaptchainrubyonrails.blogspot.com/
Here's my sign up page
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url:
registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="g-recaptcha" data
sitekey="6LeeL5gUAAAAADbq0vt4d9biAs8oegkPx9ttUkKb"></div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<br>
I do have my routes file point to a separate registrations controller instead of the one created within the devise registrations
devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout' }, :controllers => {:registrations => "registrations"}
I can create a user regardless if I click on the captcha form. When I do click on it I get the parameter, g-recaptcha-response, in the create method that has a long text string such as
"g-recaptcha-response"=>"1234567890abcdefghi..."
I tried a create method that would look at that parameter and see if it is not nil. When it is nil I would like to back one page to the sign up page.
class RegistrationsController < Devise::RegistrationsController
def create
if not params[:g-recaptcha-response].present?
redirect_to :back
end
end
end
I can't even get to the parameter as it errors out saying
undefined local variable or method `recaptcha' for #<RegistrationsController:0x7219e5a0> Did you mean? catch"
I'm trying to capture this parameter, look at the value of g-recaptcha-response and somehow cancel the creation of a user if the response was nil or empty string
Alrighty, this is what I figured out that worked. Thanks to everyone who helped
#response = params[:"g-recaptcha-response"]
if #response == nil
flash[:notice] = "Please click on captcha form!"
redirect_back(fallback_location: new_user_registration_path)
else
flash[:notice] = "You signed up successfully!"
redirect_to root_path
end
Use 'g-recaptcha-response' instead of :g-recaptcha-response. You need to use string syntax because you cannot use - in symbol naming
I have combed all the docs and how-to's I can find but can't figure this out. I have a functioning Devise set-up except that after signing out the sign in email field is blank. The 'remember me' check box is selected no matter if I check it or uncheck it on previous sign-ins.
Here is the config values I have so far:
My sign-in view:
<%= form_for(resource, :html => {:class => "" }, as: resource_name, url: user_session_path) do |f| %>
<fieldset>
<div class="form-group">
<%= f.email_field :email, class: "form-control", placeholder: "Email", autofocus: true %>
</div>
<div class="form-group">
<%= f.password_field :password, class: "form-control", placeholder: "Password", autocomplete: "off" %>
</div>
<% if devise_mapping.rememberable? -%>
<div class="checkbox">
<label>
<%= f.check_box :remember_me %> Remember Me
</label>
</div>
<% end -%>
<input class="btn btn-lg btn-success btn-block" type="submit" value="Sign In">
<%= link_to new_user_password_path, class: "btn btn-lg btn-info btn-block" do %>Forgot Password<% end %>
<%= link_to user_registration_path, class: "btn btn-lg btn-primary btn-block" do %>Register<% end %>
</fieldset>
<% end %>
My Routes with custom session controller:
devise_for :users, :skip => [:sessions, :registrations], :controllers => { :registrations => 'users/registrations', :sessions => 'users/sessions' }
class Users::SessionsController < Devise::SessionsController
def create
current_user.remember_me = true
super
end
end
Devise initializer:
config.remember_for = 2.weeks
Model:
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :timeoutable
# http://stackoverflow.com/questions/14417201/how-to-automatically-keep-user-remembered-in-devise
def remember_me
true
end
I think thats it - the more I read am I perhaps missing something here like is the email / username sign-in field meant to be populated with the users email / username?
My cookies seem to be empty if that helps.
This happens because remember_me comes in params as "on", but is compared to Devise::TRUE_VALUES, which are [true, 1, '1', 't', 'T', 'true', 'TRUE'].
The easiest way is to make it work is to insure your remember_me comes as one of that values. Example of check-box(notice value="1"):
<input type="checkbox" name="user[remember_me]" value="1" checked="checked" />
Another way if you want to make it work with "on" value you can add "on" to Devise::TRUE_VALUES. So in your config/initializers/devise.rb just add as the first line:
Devise::TRUE_VALUES << ["on"]
In my current Ruby on Rails project, the devise plugin has been used for authentication. To change the password, I added the devise plugin's passwords/edit.html.erb file into the user directory in my project. Everything's working fine except the error messages are not showing.
This is my current update_password method
def update_password
#user = User.find(current_user.id)
if #user.update_with_password(params[:user])
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
I've mentioned the require validation in the user model as follows
validates_presence_of :name, :primary_locale, :current_password, :password, :password_confirmation
This is my edit form code:
<div id="loginForm" class="editPwFormHeight">
<div id="loginHeader"><h3><%= image_tag("wif_small.png"); %></h3></div>
<div id="loginContent">
<%= form_for(#user, :url => { :action => "update_password", :locale => params[:locale] }, :method => "post") do |f| %>
<%= f.hidden_field :reset_password_token %>
<p><%= f.password_field :current_password, :class => "login_txt", :placeholder => I18n.t('wi.common.enterCurrentPw'), :autocomplete => "off" %></p>
<p><%= f.password_field :password, :class => "login_txt", :placeholder => I18n.t('wif.common.newPw'), :autocomplete => "off" %></p>
<p><%= f.password_field :password_confirmation, :class => "login_txt", :placeholder => I18n.t('wif.common.confirmPw'), :autocomplete => "off" %></p>
<p>
<input id="user_submit" name="commit" type="submit" value="<%= I18n.t('wif.common.updatePw') %>" class="login_btn" />
<input id="user_cancel" name="commit" type="button" value="<%= I18n.t('wif.common.cancel') %>" class="login_btn" />
</p>
<% end %>
</div>
</div>
Anyone can help me to solve this issue. I wanted to show the error message if the user has not typed the current password, or any other error which are currently supporting by the devise
You need to add the following line to your template:
<%= devise_error_messages! %>
You can customise the messages themselves by editing Devise's translation files, e.g. config/locales/devise.en.yml
If you're not using devise's built-in controllers, then you will need to register the DeviseHelper module as a helper in your controller using the helper method.
So I am trying to get client_side_validations gem working and when I tab out of my email field, I get this error:
Uncaught TypeError: Cannot read property 'user[email]' of undefined
This is my form helper:
<%= form_for(resource, :as => resource_name, :class => "send-with-ajax", :url => user_registration_path(resource), :validate => true) do |f| %>
<%= f.email_field :email, :id => "form-email", :placeholder => "your-email#address.com", :input_html => {:autofocus => true}, :validate => true %>
<%= f.submit :label => "Submit", :value => "Sign Me Up!" %>
<div class="ajax-response"><%= devise_error_messages! %></div>
<% end %>
Which generates this HTML:
<form accept-charset="UTF-8" action="/users" class="new_user" data-validate="true" id="new_user" method="post" novalidate="novalidate">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="9JdqaiushdauhsdioauhdoiuhNLSAVCGrc+PLJAQ=" />
<input data-validate="true" id="form-email" input_html="{:autofocus=>true}" name="user[email]" placeholder="your-email#address.com" size="30" type="email" />
<input label="Submit" name="commit" type="submit" value="Sign Me Up!" />
<div class="ajax-response"></div>
</form>
Edit 1: Even when I change the form helper from f.email_field :email, to f.text_field :email...I am still getting this error.
So I found the solution, it seems that either client_side_validations or devise are altering the id of the form - which would break the JS validation.
So the solution is to enforce the id of the form, so my form_for helper now looks like this:
<%= form_for(resource, :as => resource_name, :class => "send-with-ajax", :url => user_registration_path(resource), :validate => true, :html => { :id => 'user_new' }) do |f| %>
I found this solution here.
Have a look at the following #263 Client Side Validations. This should help.
I have few models - User, Teacher and TeacherLeader.
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :user_login,
:password,
:teacher_attributes,
:teacher_leader_attributes
has_one :teacher
has_one :teacher_leader
accepts_nested_attributes_for :teacher_leader
end
class Teacher < ActiveRecord::Base
belongs_to :user
has_one :teacher_leader
end
class TeacherLeader < ActiveRecord::Base
belongs_to :user
belongs_to :teacher
end
I want to save data in TeacherLeader via nested attributes. So, in User model i added accepts_nested_attributes_for :teacher_leader and attr_accessible :teacher_leader_attributes.
Also i have controller:
class TeacherLeadersController < ApplicationController
def new
...
#user = User.new
#teacher_leader = #user.build_teacher_leader
#teachers_collection = Teacher.all
.collect do |t|
[ "#{t.teacher_last_name} #{t.teacher_first_name} #{t.teacher_middle_name}", t.id ]
end
#choosen_teacher = #teachers_collection.first.last unless #teachers_collection.empty?
end
def create
user = User.new( params )
user.user_role = "class_head"
if user.save
flash[:success] = "Successfully created class head!"
else
flash[:error] = user.errors.full_messages
end
end
end
Also i i have view for TeacherLeader controller (new.html.erb):
<%= form_for #user, :url => teacher_leaders_url, :html => {:class => "form-horizontal"} do |f| %>
<%= field_set_tag do %>
<%= f.fields_for :teacher_leader do |tl| %>
<div class="control-group">
<%= tl.label :teacher_id, "Teacher names", :class => "control-label" %>
<div class="controls">
<%= select_tag( :teacher_id,
options_for_select( #teachers_collection, #choosen_teacher )) %>
</div>
</div>
<% end %>
<div class="control-group">
<%= f.label :user_login, "Login", :class => "control-label" %>
<div class="controls">
<%= f.text_field :user_login %>
</div>
</div>
<div class="control-group">
<%= f.label :password, "Pass", :class => "control-label" %>
<div class="controls">
<%= f.text_field :password %>
</div>
</div>
<% end %>
<%= f.submit "Create", :class => "btn btn-large btn-success" %>
When i'm trying to save my models, i get strange errors such "User login can't be empty" and others. I know that validations of User models generate them (i don't know why, i get such errors even if have values in params). I suppose, that i do something wrong in view, because after submiting i have such params:
teacher_id: '1'
user: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
user_login: schoolh_1rF32
password: txaqxuTXz96auhX
commit: Create
action: create
controller: teacher_leaders
But i should have something like this:
user: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
user_login: schoolh_1rF32
password: txaqxuTXz96auhX
teacher_leader_attributes:
teacher_id: '1'
What is wrong? Can i fix that?
UPD: HTML code for class head creation page:
<form accept-charset="UTF-8" action="http://0.0.0.0:3000/teacher_leaders" class="form-horizontal" id="new_user" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="ZKlDTKG8SU8fZuMrUfQoCOSGknOhj651DT2LJDrfliA=" /></div>
<fieldset>
<div class="control-group">
<label class="control-label" for="user_teacher_leader_attributes_teacher_id">Teacher names</label>
<div class="controls">
<select id="teacher_id" name="teacher_id">
<option value="1" selected="selected">Jack P. Tompson </option>
<option value="2">Ronald V. Herwud</option>
</div>
</div>
<div class="control-group">
<label class="control-label" for="user_user_login">Login</label>
<div class="controls">
<input id="user_user_login" name="user[user_login]" size="30" type="text" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="user_password">Password</label>
<div class="controls">
<input id="user_password" name="user[password]" size="30" type="text" />
</div>
</div>
</fieldset>
<input class="btn btn-large btn-success" name="commit" type="submit" value="Create" />
</form>
You need not
<%= select_tag( :teacher_id,
options_for_select( #teachers_collection, #choosen_teacher )) %>
but something like
<%= tl.select( :teacher_id,
options_for_select( #teachers_collection, #choosen_teacher )) %>