I am using Rails 3.2 and Devise. I am wondering if Devise provides an "Email (address) Confirmation" field just like Password Confirmation for the user to type in a Password field and then type in a Password Confirmation field before the website sends out a confirmation email or processes the sign up registration. If not, must I add a email_confirmation and validate the User model (after rails g devise User)?
Thanks in advance
I haven't found if devise does what you ask (the question is referring to a second :email_confirmation field similar to :password_confirmation, 'confirmable' seems to be solely related to confirmation links). I had to do this as well and I figured out how to do it using builtin active record validation (rails 3.2.8, devise 2.1.2):
In your model add confirmation: true to your email validation and :email_confirmation to attr_accessible.
In your view add an :email_confirmation field.
As an example, in your model (not assuming other validations or attr_accessibles):
attr_accessible :email, :email_confirmation
validates :email, confirmation: true
which will use the builtin active record 'confirmation' validation (the same as for passwords). Finally, in your view(s) you'll need to add something like:
<div><%= f.label :email_confirmation %>
<%= f.email_field :email_confirmation %></div>
There may be a cleaner way but this worked for me. However, my only experience with devise so far has been when adding it to existing models, I haven't used it when it's generating the models for you (presumably it's mostly the same).
I was faced with the same issue.
Here's how I solved it
From the official RailsGuide
You should use this helper when you have two text fields that should receive exactly the same content. For example, you may want to confirm an email address or a password. This validation creates a virtual attribute whose name is the name of the field that has to be confirmed with "_confirmation" appended.
class Person < ApplicationRecord
validates :email, confirmation: true
end
In your view template you could use something like
<%= text_field :person, :email %>
<%= text_field :person, :email_confirmation %>
This check is performed only if email_confirmation is not nil. To require confirmation, make sure to add a presence check for the confirmation attribute (we'll take a look at presence later on in this guide):
class Person < ApplicationRecord
validates :email, confirmation: true
validates :email_confirmation, presence: true
end
There is also a :case_sensitive option that you can use to define whether the confirmation constraint will be case sensitive or not. This option defaults to true.
class Person < ApplicationRecord
validates :email, confirmation: { case_sensitive: false }
end
The default error message for this helper is "doesn't match confirmation".
From my experimentation, using the official RailsGuide,
If you want to change the confirmation message to say, Email confirmation must be given correctly, then use add a message option this way:
class Person < ApplicationRecord
validates :email, confirmation: true
validates :email_confirmation, presence: { message: "must be given correctly" }
end
That's all.
I hope this helps
There are a few minor differences for newer versions of Rails compared to the original answer. Just figured I'd add this in case it helps anyone else.
Add an attr_accessor for email_confirmation to your model and validate the email field against the email_confirmation field. Set case_sensitive to false { case_sensitive: false } on the validation unless you have configured the email field to be case sensitive.
app/models/user.rb
class User < ApplicationRecord
attr_accessor :email_confirmation
validates :email, confirmation: { case_sensitive: false }
end
Permit email_confirmation on the sign up params.
app/controllers/users/registrations_controller.rb
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:email_confirmation])
end
Add the email_confirmation field to your sign up form.
app/views/devise/registrations/new.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render 'devise/shared/error_messages', resource: resource %>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email, autofocus: true, autocomplete: 'email', required: true %>
</div>
<div class="field">
<%= f.label :email_confirmation %>
<%= f.email_field :email_confirmation, required: true %>
</div>
<!-- other fields -->
<% end %>
Assuming you have the gem installed, when you perform this function :
rails generate devise:install
It will generate your migration file that will contain your email_confirmation stuff that you will need to go in the direction you're referring to. All you have to do is not comment it out. Otherwise, I comment out all the other stuff that I don't need.
The module you are referring to is called confirmable
Assuming you havn't found this yet, this link will explain the rest :
How do I set up email confirmation with Devise?
Related
I have a study that can have participants. I have a simple_form where the user can add participants. It looks a bit like a table:
name | company | email OR mobile | timezone
name | company | email OR mobile | timezone
name | company | email OR mobile | timezone
By default, the screen has three fieldset rows, and the user can add more rows if needed. Each row is one participant.
I would like my participant model to validate only the rows that have been filled out, and ignore rows that are blank because even though we are showing three by default to the user, not all three are required fields.
Here's the relevant portion of app/models/participants.rb.
class Participant < ApplicationRecord
belongs_to :study
validates :name, presence: true
validates :company, presence: true
validates :time_zone, presence: true
if :channel == 'sms'
validates :mobile_number, presence: true
elsif :channel == 'email'
validates :email, presence: true
end
end
In participants_controller.rb I have:
def index
3.times { #study.participants.build } if #study.participants.length.zero?
end
The problem is that I get an error because simple_form thinks that all three fields are required, and not just the first row.
Rails' validators accept conditions:
validates :mobile_number, presence: true, if: Proc.new { |p| p.study.channel == 'sms' }
validates :email, presence: true, if: Proc.new { |p| p.study.channel == 'email' }
By default all inputs are required. When the form object includes
ActiveModel::Validations (which, for example, happens with Active
Record models), fields are required only when there is presence
validation. Otherwise, Simple Form will mark fields as optional. For
performance reasons, this detection is skipped on validations that
make use of conditional options, such as :if and :unless.
And of course, the required property of any input can be overwritten
as needed:
<%= simple_form_for #user do |f| %>
<%= f.input :name, required: false %>
<%= f.input :username %>
<%= f.input :password %>
<%= f.button :submit %>
<% end %>
Try to put all the inputs as required: false. That should allow skip simple_form validations and the data came into the controller and the model can be filtered or/and validated and every other things you want to do before persist.
In the model class you can use several ways of validations for example:
you also can use the :if and :unless options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option.
for example
class Participant < ApplicationRecord
belongs_to :study
validates :name, presence: true
validates :company, presence: true
validates :time_zone, presence: true
validates :mobile_number, presence: true if: :channel_is_sms?
validates :email, presence: true if: :channel_is_email?
def channel_is_sms?
channel == "sms"
end
def channel_is_email?
channel == "email"
end
end
or also you can use custom validator where you do all that you need validate. for example
class MyValidator < ActiveModel::Validator
def validate(record)
unless record.channel == 'sms'
...
... actions here
...
end
end
end
class Person
include ActiveModel::Validations
validates_with MyValidator
end
When I create a new form in ActiveAdmin, I want validations on my form input fields. But I can't find a related tutorial. I want some fields to accept only alphabets, some only digits , and some should be of specific length.
f.input :name, :label => "Title", input_html: { autofocus: true }
f.input :description
f.input :email
f.input :contact_number
f.input :contact_person
[Answer not only for ActiveAdmin, but for RoR in general]
You should do it in model.
• For digits only:
You want your :contact_number to be a digit, so your model (e.g. User) should look like this:
class User < ActiveRecord::Base
validates :contact_number, numericality: {only_integer: true}
end
• For min. 5 characters:
If description for example must be at least 5 characters it will be:
validates_length_of :description, minimum: 5
• For letters only:
validates_format_of :name, with: /^[-a-z]+$/
(details about reg. expressions --> Validate: Only letters, numbers and - )
Additional info:
If your form don't pass model validation it will return alert about wrong argument (which is accessible in flash[:alert] array).
More about it in:
http://guides.rubyonrails.org/active_record_basics.html#validations
You can have the validations defined in your corresponding Model class.
See the official documentation for Rails validation.
ActiveAdmin will pick it up when you try to create/edit/update objects of that model if you have Rails standard validations or even custom validations defined in your Model class.
For example, for your email validation, you can have this in your model:
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
Then, when you try to create/save an object through ActiveAdmin, it will show you error if the email is not in the correct format.
So, you have to define all of your validations (for all the fields that you want) in your model. That's it!
And, to display a list of all validation errors, you have to do:
form do |f|
f.semantic_errors *f.object.errors.keys
# ...
end
Update
Add these validations to your Model class:
validates_presence_of :description
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
validates :contact_number, :presence => {:message => 'hello world, bad operation!'},
:numericality => true,
:length => { :minimum => 10, :maximum => 15 }
These are Rails standard validations. You can add custom validations to your model too.
For example, if you want to add a custom validation for the username, you can define that like this:
validate :username_must_be_valid
And, then define the custom validator method username_must_be_valid in the same model class like this:
private
def username_must_be_valid
errors.add(:username, 'must be present') if username.blank? && provider.blank?
end
Trying to create a profile form in which a user can add information about their hobbies to their user profile. But I get the following error when trying to do so.
NoMethodError in Users#edit_profile
undefined method `hobbies' for #<User:0x007ff1a8a1f198>
Does anyone know what the problem could be, or a potential solution? I'm new to rails but I was under the impression that 'text_field' was a safe bet to make any custom input work. Would installing the strong parameters gem help this out at all?
edit_profile.html.erb
<h2>Tell us about yourself</h2>
<%= form_for #user do |f| %>
<%= f.label :first_name %><br />
<%= f.text_field :first_name, autofocus: true %>
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
<%= f.label :hobbies %><br />
<%= f.text_field :hobbies %>
<div><%= f.submit "Update" %></div>
<% end %>
user_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
end
def edit
end
def update
#user = User.find(params[:id])
#user.update!(user_params)
redirect_to #user
end
def destroy
end
def edit_profile
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :hobbies)
end
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :remember_me, :hobbies
#validates :first_name, presence: true, length: { maximum: 50 }
#validates :last_name, presence: true, length: { maximum: 50 }
end
You don't mention it, but I will assume you're running Rails 4.x.
Rails 4.x introduced strong parameters, so in your controller you need to add a private method to set the allowed parameters and remove the attr_accessible from your model.
So in you case it will be:
def user_params
params.require(:first_name, :last_name).permit(:email, :password, :password_confirmation, :remember_me, :hobbies)
end
If you still have trouble to understand the concept, or came from a previous Rails version, take a look at this blog post.
Does anyone know what the problem could be, or a potential solution?
Sure - the problem is you don't have a hobbies attribute in your User model :)
Since you're new, I'll explain a bit about Rails after I answer the question. However, let me explain the value of creating the right attributes:
#app/models/user.rb
class User < ActiveRecord::Base
attr_accessor :hobbies
end
This is what you'll need to create a single attribute for your User model. The attr_accessor directive is a Ruby method which sets a getter and setter in your User model
This will give Rails the ability to populate the hobbies attribute of your Model. However, the data will not be persistent, as it will only be set on a per-instance basis in the model, meaning it will be lost when you refresh the page etc
Using the code above should get your form working, regardless of whether you're using Rails 3 or 4.
Models
Rails is famously an MVC framework - which means it has 3 core components - models (builds data from the database), controllers (configure data for the view) & views (displays the data from the controller & model).
When you load a Rails application, you're sending a request, which will be routes to a particular controller action. This will then call data from your database, allowing you to manipulate it in your view.
Models, therefore have to be populated from your database. They do this by taking the various attributes you have in your datatables, and creating a series of getters and setters for them. These give you the ability to access the data within the attributes, or set new ones.
Your error occurs because you don't have the relevant attribute set in your datatable. You'll need to create a migration to add the hobbies attribute to your User model:
> $ rails g migration AddHobbiesToUser hobbies:string
> $ rake db:migrate
The migration should create something like:
class AddPartNumberToProducts < ActiveRecord::Migration
def change
add_column :users, :hobbies, :string
end
end
I am working in a project where users can either have admin: true / false. The application will only let admin users login in to the system, the other users are just clients whose settings only admins can edit. This is some sort of commerce application.(Rails 3.2.13)
I would like to keep both concepts in the same table since in the future there will possibly be the option of logging in for non-admin users and interact with their profiles, so all the logic will be already implemented.
I've got this User resource:
ActiveRecord::Schema.define(:version => 20131204200554) do
create_table "users", :force => true do |t|
t.string "name"
t.string "surname"
t.boolean "admin"
t.string "password_digest"
t.string "email"
t.string "auth_token"
end
end
This is the user model:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :name, :surname,:email, :password, :password_confirmation
validates :name, presence:true, length: { maximum:50}
validates :first_surname, presence:true, length: { maximum:50}
VALID_EMAIL_REGEX= /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive:false}
validates :password, length:{minimum:6}
validates :password_confirmation, presence:true
before_save{ self.email.downcase! }
before_save :generate_auth_token
private
def generate_auth_token
self.auth_token=SecureRandom.urlsafe_base64
end
end
And I am trying to implement the functionality of User editing, however I only want to allow the editing of name, surname and email. Hence, I present only those fields in the form:
<%= form_for(#user) do |f| %>
<%= f.label :name,"Name" %>
<%= f.text_field :name %>
<%= f.label :surname,"Surname" %>
<%= f.text_field :surname %>
<%= f.label :email,"Email" %>
<%= f.text_field :email %>
<%= f.submit "Save" %>
I am trying to accomplish the goal with this code:
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
# Handle a successful update.
flash[:success]="User updated successfully"
redirect_to #user
else
flash[:danger]="Error updating user"
render 'edit'
end
end
My problem is that when trying to update_attributes I get not unexpectedly an error validating password/password_confirmation, but since I'm using has_secure_password, these fields do not exist in the database, only password_digest. I am thinking about the best option to accomplish all this:
Update #user object with new field values.
Reflect this change in User table.
Run the validations, i.e. email validation.
While using has_secure_password. These are the options so far:
Use of update_attribute(best so far).
1.1 Pro: updates the User table
1.2 Con: I have to update_attribute(field1) for each of the fields, so more lines of code
1.3 Con: Apparently this method no longer exists in Rails 4, problem in case an upgrade is desirable in the future.
1.4 Con: No validations
Use of #user.attributes=params[:user] in the controller method
2.1 Pro: Updates multiple fields at once.
2.2 Con: Does not update the User table.
User of update_attributes
3.1 Pro: Both multiple fields and table update
3.2 Con: Not working ( duh!)
Suggestions?
It looks like you want to validate the presence of password on create only (also notice more concise way to validate password confirmation):
validates :password, length:{minimum:6}, confirmation: true, on: :create
You can then use update_attributes
You may want to restrict what params can be submitted by using strong params:
Gem: https://github.com/rails/strong_parameters
also included in Rails 4 http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
FINAL SOLUTION:
I have a Rails 3 app that uses Devise to handle authentication. In the signup form i have the following fields:
<p><%= f.label :first_name %><br />
<%= f.text_field :first_name %></p>
<p><%= f.label :last_name %><br />
<%= f.text_field :last_name %></p>
I need to capitalize first and last names and combine them in the User model in a database field called 'login' (e.g. Lastname, Firstname). Here is the complete user model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :remember_me, :login
validates :first_name, :last_name, :email, :password, :password_confirmation, :presence => true
before_create :create_login
def create_login
self.login = "#{last_name.capitalize}, #{first_name.capitalize}"
end
end
Thanks.
I genuinely, honestly, and truly applaud your use of the power of Ruby, but since this is such a straightforward and static concatenation of two strings, I'd go with:
def create_login
login = "#{last_name.capitalize}, #{first_name.capitalize}"
end
As for the nil:NilClass issue, are you adding first_name and last_name columns to your users table in your associated migration?
before_create :create_login
validates :first_name, :presence => true
validates :last_name, :presence => true
def create_login
login = [last_name, first_name].map(&:capitalize).join(", ")
end
Short explanation
I think it is good to get first_name and last_name on registration: so we will ad validation to it. Also it is good idea to validate length and match it with some regexp.
Then, as far as login is creates only once, we will add before_create callback, which will be executed only when object is creating (not updating). before_create callback will be run only if validation is passed, so if first_name or last_name is blank - validation won't be passed and callback won't be executed till first_name and last_name is filled.
UPD
Ok, as far as you get your error:
def create_login
login = [last_name, first_name].compact.map(&:capitalize).join(", ")
end