Rails - Confirmation Fields Are Tied to HTML Form Helpers - ruby-on-rails

Rails only checks for field confirmations if there is a corresponding _confirmation field in the request.
To explain it further, here is a sample Rails view:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
<%= f.label :password %>
<%= f.password_field :password, autocomplete: "off" %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off" %>
<%= f.submit "Sign up" %>
<% end %>
This form works as expected.
However, if you remove:
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off" %>
Passwords are no longer confirmed.
The problem I am having is all my JSON requests are going through successfully without a corresponding _confirmation field.
This request is successful:
{
"email": "me#example.com",
"password" : "somepassword"
}
This is not:
{
"email": "me#example.com",
"password" : "somepassword",
"password_confirmation": "_somepassword
}
Also, for the second JSON, if password and password_confirmation match then the request is successful(which is understood).
I think the first request should not be successful since there is no password confirmation.
Is this a bug or an expected behaviour since confirmation fields should be tied to ActiveRecord and not HTML from helpers.
How will one replicate field confirmations in Rails based JSON APIs then?

I think that validation of the confirmation is kind of useless in the context of an JSON API. You would basically only validate that the developer read your API description.
Therefore I would argue that it makes sense that it does not validate if the confirmation key is missing. Since a form would always return both fields it would always validate user input.
If you really want to enforce the confirmation (even on the JSON API) just follow the docs:
NOTE: This check is performed only if password_confirmation is not nil. To require confirmation, make sure to add a presence check for the confirmation attribute:
validates_presence_of :password_confirmation, if: :password_changed?

Related

Error using Devise new registration on my rails project

I am building my first rails application using the Devise gem for authentication.
The login works great but the new registration (sign up) page delivers an error on the PAGE and will not let me register.
See image
Is this an issue with strong parameters or my application controller. Your help would be greatly appreciated.
This is probably because you have validations enabled in your User model where you specified the email and password can't be blank.
So, you have to provide email and password of a user when trying to save the info.
Update
If that's not the case, then it could be related to strong parameters. See this thread.
In your application_controller.rb file, add the following:
before_filter :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :password_confirmation) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:email, :password, :password_confirmation) }
end
Configure your other actions like above too.
More update
The main issue was in the sign up form as it was not using the form builder properly and was not posting the params. I modified the app/views/devise/registrations/new.html.erb file to this:
<h2>Be cool and sign up if you dont have an account:</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="col-md-4">
<h2>Signup</h2>
<form class="form-signup">
<div class="form-group">
<label for="email">Email</label>
<%= f.text_field :email, class: "form-control", placeholder: "First Name", tabindex: "2" %>
</div>
<div class="form-group">
<label for="password">Password</label>
<%= f.password_field :password, class: "form-control", tabindex: "2", placeholder: "Password", required: true %>
</div>
<div class="form-group">
<label for="password_confirmation">Password</label>
<%= f.password_field :password_confirmation, class: "form-control", tabindex: "2", placeholder: "Password Confirmation", required: true %>
</div>
<div><%= f.submit "Sign up", class:"btn btn-primary"%></div>
</form>
<%= render "devise/shared/links" %>
</div>
</div>
</div>
<% end %>
</div>
making sure the params are posting to the controller properly, and everything is working as expected now.
With what I can see, and what you explained:
you filled in the email and password field
it went through your controller and then to the model
there is validation in your model that is complaining of the absence of email and password.
I am assuming that you are using the sign-up page generated by Devise (this is already set up to get a new user form, bound with a new instance of the User class).
From the above three points (and the assumption), it stands to reason that both the email and password that you filled in are getting lost somewhere along the way.
My guess will be that this is happening somewhere in your controller. According to your routes, that will be the registrations controller (the create action).
Do you have a custom registrations#create controller? if yes => I think your params are not being allowed into building the new User which the save action is being called on.
If that is the case, you will need something like:
def new_user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
and then building and saving the new user as:
#user = User.new(new_user_params)
#user.save
Hope this helps to throw some light into it...

Don't allow user to submit a form with empty fields in ruby on rails

I am starting use Ruby on Rails and I am having a little problem. I have a form with 3 fields, this is the code:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.text_field :name, autofocus: true, placeholder: "Name" %>
</div>
<div class="field">
<%= f.email_field :email, autofocus: true, placeholder: "Email" %>
</div>
<div class="field">
<%= f.number_field :age, autofocus: true, placeholder: "Age" %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
In the email field when you write something that is not an email and try to submit, the browser (chrome or firefox ) display an error saying that the field must content an #. The same happen with the age field, if a letter is entered the browser show an error saying that the field only accept numbers.
I wanna know how to make that the browser show a message when any field is empty when you try to submit. I know how to do it in cakephp so I guess it can be done here in ruby too. I already validate the fields in the model, setting the presence in true but that only works for show a message after you submit and the page reload again.
When you use something like:
f.email_field
It is generating an HTML5 input element that tells the browser it has to be a valid email. HTML 5 also has a required='required' option that can be used to prevent blank fields.
You can add it like this:
<div class="field">
<%= f.email_field :email, autofocus: true, placeholder: "Email", :required => 'required' %>
</div>
This will add required='required' to your form element. Note that in HTML5 you only need the word required in your form element, but the only way I know to add it in Rails is to use the option form I'm showing you here.
This will prevent submitting the form without that field. This works for current versions of Firefox, Chrome, Opera, and IE11. Safari will prevent the submission but doesn't indicate why. It just does nothing.
I would check this out: http://blueashes.com/2013/web-development/html5-form-validation-fallback/
You can set the HTML required attribute to true. Just add required: true to each field.
Here's what your new form will look like:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.text_field :name, required: true, autofocus: true, placeholder: "Name" %>
</div>
<div class="field">
<%= f.email_field :email, required: true, autofocus: true, placeholder: "Email" %>
</div>
<div class="field">
<%= f.number_field :age, required: true, autofocus: true, placeholder: "Age" %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
Your case is pretty custom, that's why it looks pretty easy, but what you're really trying to achieve here is called 'client-side validation'.
To be really portable and user-friendly it has to be done in JavaScript. Basically this will be a script that validates the fields and outputs the corresponding error messages to the user, preventing form submission at the same time. This is almost the same that Rails does on the server side when you submit the form.
Once the problem is defined, you can approach it in one of the following ways:
Stay with Rails. Rails is initially designed to handle form validation on the server side. You can just accept the way it is, and it will yield the cleanest, shortest and the most semantic code possible. For it to be more seamless you can easily pull in some AJAX for it, which should be easy (http://guides.rubyonrails.org/working_with_javascript_in_rails.html). To user it'll look like nothing ever got submitted.
Write some custom JS yourself to handle those validations. Either on your own, or with the aid of libraries like http://jqueryvalidation.org/. This is going to be a mess, since you'll basically have to duplicate Rails server-side validation code on the client-side in a different language. And keep it in sync.
Use one of the helper libraries for Rails. E.g. https://github.com/joecorcoran/judge looks promising, but there are others to be Googled. These guys exercise the same idea: you've got server-side validations and they should be easily usable on the client-side. Certain libraries generate JavaScript automatically, others just send the form to be validated to the server behind the scenes.
If I were you, I would choose the 1st way + AJAX. Other ways would make simple matters unnecessarily complex, and instead of writing useful stuff you'll most certainly have to dive into debugging obscure JS and cryptic meta-programmed Ruby/Rails libraries.
Hope that helps!
HTML 5 has required=true option that can be used to prevent form submission with empty fields. In rails form helpers, you can use it like
<%= f.text_field :first_name, required: true %>
<%= f.email_field :email, required: true %>

Ruby on rails text_field confirmation

I have two lines
<%= f.text_field(:email, class: 'new_user_info', autofocus: true, placeholder: 'Email') %>
<%= f.text_field(:email_confirmation, class: 'new_user_info', autofocus: true, placeholder: 'Email Confirmation') %></td>
On http://edgeguides.rubyonrails.org/active_record_validations.html, it states that you can use the
confirmation: true
property with the following format
<%= text_field :person, :email %>
<%= text_field :person, :email_confirmation %>
I need the confirmation to work with the first format that I stated. However, I am unable to do so. When I add the confirmation: true property it is ignored by the validator. Could someone please tell me how to validate the fact that both emails are the same with Ruby on Rails using the first set of text_field tags that I gave?
Thanks for your time
Try using this instead
validates_confirmation_of :email

Turn autocomplete off with rails form_tag

I'm trying to turn autocomplete off in one of my rails forms. Here's what I've tried so far:
# add it at the form level
= form_tag admin_sessions_path, autocomplete: "off" do
That didn't work.
# add it at the element level
.panel
= label_tag :email
= email_field_tag :email, params[:email], autocomplete: 'off'
Neither did that.
# add it to both
= form_tag admin_sessions_path, autocomplete: "off" do
# add it at the element level
.panel
= label_tag :email
= email_field_tag :email, params[:email], autocomplete: 'off'
When I visit my form, my email address and saved password are already filled-in. What am I doing wrong here? I love rails, but it really drives me mad sometimes.
As of Rails 4+
Disable autocomplete for an entire form with form_tag:
= form_tag admin_sessions_path, html: { autocomplete: "off" } do
Disable autocomplete for an entire form with form_for:
= form_for #user, html: { autocomplete: "off" } do |f|
Disable autocomplete for a single form element:
= f.text_field :foo, autocomplete: 'off'
Hope this helps!
the autocomplete attribute should be assigned to the html key like so:
html: {autocomplete: 'off'}
In latest version of chrome autocomplete: 'off' does not work. Instead use autocomplete: 'disabled'
There several ways of turning off the autocomplete functionality:
On form level: (autoceomplete turned of for all inputs)
<% form_tag(:form_name, #form_name, autocomplete = "off") do |f|%>
Per input:
<%= text_field_tag('my input', nil, autocomplete = 'off') %>
Simple Form per input:
<% f.text_field :fieldname, input_html: {autocomplete: 'off'} %>
Edit:
Unfortunately, this method has drawbacks
Fields are not filled back after validation errors and render :xxx
solution to this issue is to make alias_attribute :c_ountry, :country, but personally I don't like the hackyness of it
Method does not work on English locale (at least for me), but works on other locales
Edit 2:
Ultimately I solved it with a combination of three approaches which I described in more general question
Original answer:
It's the fault of HTML and mostly Chrome, not Rails.
As of December 2020 and Chrome 87 all of the above solutions didn't worked for me, neither do many variations from the web with autocomplete, readonly, onclick, type, etc. attributes' workarounds.
Solution to prevent Autofill
What worked is to not name the field with their full names. i.e. if we have country and city fields, then instead of this
= f.text_field :country
= f.text_field :city
do this
= f.text_field :c_ountry
= f.text_field :cit_y
Then manually reassign params in controller. i.e.
def user_params
params[:user][:country] = params[:user].delete(:c_ountry)
params[:user][:city] = params[:user].delete(:cit_y)
params.require(:user).permit(:country, :city)
end
Gotcha:
I noted that Chrome is triggering autofill also when it finds other words in type. For example, I observed that this triggers autofill
= f.text_field :d_istrict
while this don't trigger autofill
= f.text_field :d_istric_t

Google Chrome - Ruby on Rails firing Please match the required format

I'm using Ruby on Rails to make my login form and when trying to log in, or create a new account I get this client-side error that prevents me from POST'ing the form.
This is the Ruby code I'm using to generate the form View.
#account-form
h2 Create your free account!
p Signing up is completely free and you can use all of our features.
= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
= f.error_notification
.form-group
= f.label :email
= f.input_field :email, class: 'form-control'
.form-group
= f.label :password
= f.input_field :password, required: true, class: 'form-control'
.form-group
= f.label :password_confirmation
= f.input_field :password_confirmation, require: true, class: 'form-control'
button.btn.btn-default type='submit' Sign up
= render 'devise/shared/links'
That is generating the following HTML (for the input):
<input class="string email optional form-control"
id="user_email"
maxlength="255"
name="user[email]"
pattern="\A[^#\s]+#([^#\s]+\.)+[^#\s]+\z"
size="255"
type="text" value="">
Why is my valid email causing this validation to trigger? Any suggestions?
By default, devise had a complex regex that validates email.
I suggest you to simplify this regex. Why? http://davidcel.is/blog/2012/09/06/stop-validating-email-addresses-with-regex/
It can be done by adding to config/initializiers/devise.rb following line:
config.email_regexp = /.+#.+/
That's it.
You could take out the 'form control' validation and see if that helps. Validating email addresses with regexp is very complicated, and apparently you don't care that much whether or not they are entering a valid email address, since the email field is optional. I'd take the form control part out and assume good user input or make them validate their email in another way (like responding to an email).

Resources