Adding first name and last name to devise sign up form - devise

I'm using Rails 4 and I'm trying to add first name and last name fields to the sign up process. I'm using Devise to handle authentication.
I've added first_name and last_name columns to my user model through a migration. I also added the following to my application_controller.rb file:
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:first_name, :last_name, :email, :password, :password_confirmation, :remember_me) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:email, :password, :remember_me) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password) }
end
However when I sign up, the first_name and last_name field can be left blank and even when they are populated the values are not saved to the user object.
How can I:
Force those fields to be required on sign up? I tried adding 'validates_presence_of :first_name, :last_name, :email' to the user model but had to remove it since the form for some reason always thinks the first_name and last_name fields are blank.
Update devise create action so that it saves the values passed in through the devise/registrations/new.html.erb file?
I have a Person model that i want to associate with this user (associations are created successfully and i have forms that edit both person and user fields but not sure how to build that into the devise sign up process.
Any help would be appreciated.

This is covered in the devise wiki
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-with-something-other-than-their-email-address

Related

What is better way to create Client record after User is registered (corresponding client record)

Basically i have user registering himself to the app , by using devise gem.
Instead of having standard sign up form like (email, password) i have an extra 2 fields (name, contact_nr) in total used (name, contact_nr, email, password, password_confirm) fields, :name and :contact_nr attributes exists in 'clients' table only.
Table name: clients
id :integer not null, primary key,
name :string(255)
surname :string(255)
contact_nr :string(255)
user_id :integer
class Client < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :client, dependent: :destroy
after_create :update_user_client
def name
return unless client
client.name
end
def contact_nr
return unless client
client.contact_nr
end
def update_user_client
Client.last.update_attributes(user: self)
end
end
In my RegistrationsController I have only one method
class RegistrationsController < Devise::RegistrationsController
before_action :create_client
private
def create_client
return if params[:user].blank?
Client
.new(name: params[:user][:name],
contact_nr: params[:user][:contact_nr])
.save(validate: false)
end
end
What bothers me is that kind of writing code, it feels like code smell.
How would you implement it?
Thanks guys looking forward to your answers..
First advice I can give is do not separate client and user into two tables if you don't have valid reasons and/or requirements for now. That would make things much easier.
If you have valid reasons, here are my advices on how to improve your existing state of this code piece:
Rails and all mature gems around it rely on 'convention over configuration', so you should check if there are conventional ways to achieve same results.
In your RegistrationsController instead of doing params[:user].blank? check, you should use Devise's way of doing this, provided with inherited methods as devise_parameter_sanitizer.permit within a before_action callback.
Instead of creating client in your controller, move that to model logic, and in your user model put accepts_nested_attributes_for :client.
Since both of your models(client and user) share same name, put a before_save callback, so that you can pass user's name attribute to client itself.
after_create callback is very risky, since it is not an atomic save (no guarantee that client will be updated after user record is updated.). So don't use it. accepts_nested_attributes_for will handle both create and update calls.
If name attribute for user would be fetched through client only, there is no need to keep name within user.
If you want to access client's contact_nr and name attributes directly from user model, then use delegate method inside it.
Putting all together, I would refactor that code piece as this:
class User < ActiveRecord::Base
has_one :client, dependent: :destroy
accept_nested_attributes_for :client
delegate :name, to: :client
delegate :contact_nr, to: :client
# optional. if you want to keep name attr in both models.
before_save :sync_names
private
def sync_names
self.client.name = name if client.present?
end
end
class RegistrationsController < Devise::RegistrationsController
before_action :configure_permitted_parameters
protected
def configure_permitted_parameters
added_attrs = [:name, :email, :password, :password_confirmation, client_attributes: [:contact_nr]]
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
end
end
Don't forget to update your signup and account update forms to accept nested attributes for client resource.
As far as you are validating the data with JS and filtering with params.require(:client).permit, the code looks fine. Try to create many differente scenarios in your Rspec. The test usually reveals unexpected flaws.

"Email can't be blank" Devise using username or email

I was following this how-to on How To: Allow users to sign in using their username or email address and did all the steps detailed there but when I try to register via the registrations/new.html.erb form I get this error:
Email can't be blank
In my model I have:
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :username, :email, :password, :password_confirmation, :remember_me
attr_accessor :login
attr_accessible :login
and
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions).first
end
end
any advice with this problem?
======= UPDATE
I found something here ■[rails]How to use Devise and Rails , without EMail here it is something like:
# Email is not required
def email_required?
false
end
With that added in my model I can create a record with username and leaving the email field blank, but when I try to create a second record without email the database rises an error:
Mysql2::Error: Duplicate entry '' for key 'index_parents_on_email':...
Should I use this, remove the index from my table in the database, and just validate the username in the model? because I don't really need the email field on that model.
Update
Asiniy's answer below actually works like a charm (:
Original (who knew?)
Your problem is the index on the mysql table, you might remove it from your migrations, but I'm not sure that will solve your problem. Not using the email in Devise is tricky, I would suggest a workaround like a fake email out of the username, something like this
"#{user.username}#fake.me"
It's not very clean but I see devise doing something similar for passwords when you use omniauth.
Rails 4 and Strong Parameters
I got into this problem for username in rails 4, and I had to configure the permitted parameters as below for sign_up:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit :username, :email, :password, :password_confirmation
end
end
end
This is described in Devise Doc
Normal solution
class User < AR::Base
devise_for tralala
def email_required?
false
end
end
Please refer to the https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L29

Create "organization" automatically when user signs up?

I'm using Devise for authentication with two custom fields added = :organization_id and :username. I also generated a scaffold for the Organization which simply consists of Name.
Currently when users sign up they can type in an Organization ID (integer) and a username (string).
Users belong_to organizations, and organizations has_many users.
Here's what my models look like (I left everything else untouched except for the files inside app/views/devise/registrations to add organization_id and username):
#user.rb
class User < ActiveRecord::Base
belongs_to :organization
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :organization_id, :username
end
#organization.rb
class Organization < ActiveRecord::Base
has_many :users
end
What I would like is for an organization to be automatically created when a user signs up without the user having to specify the organization_id.
Also, ideally the #organization.name would be exactly the same as :username
How would I go about doing this?
I've seen the Railscast on nested model forms but he's creating a question inside the survey form, and questions belong to a survey. I need to do it the other way around (create an organization inside the user form, where users belong to a survey.)
Any help and suggestions would be greatly appreciated..
class User < ActiveRecord::Base
before_create :create_organization
private
def create_organization
self.organization = Organization.create :name => self.username
end
end
The create_organization method will be executed right before the sql query which creates the user. It'll create a new organization and assign it to the user.

Accept terms of use rails

What is the best way to add a check for accepting terms of use in a rails app?
I can't seem to get validates_acceptance_of working quite right. I added a bool to my user model (was that necessary?). And then have a checkbox that returns either true/false.
I feel like I'm just making a silly little mistake. Any ideas?
In your model,
validates_acceptance_of :terms
If you're using attr_accessible in your model then make sure you also add,
attr_accessible :terms
In your view,
<%= form_for #user do |f| %>
...
<%= f.check_box :terms %>
...
<% end %>
There is no need for an extra column in the users table unless you plan on denying access to users who have not accepted the terms of service, which won't exist since they can't complete registration in the first place.
This is a working Rails 4 solution:
Terms of service doesn't need to be a column in the database
Form
= f.check_box :terms_of_service
models/user.rb
validates :terms_of_service, acceptance: true
And most important, devise will sanitize your parameters and terms of service will be removed from the submitted params. So:
registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:full_name,
:email, :password, :password_confirmation, :terms_of_service)
end
end
end
This is a working solution for Rails-6.1 (I18n) + Devise-4.8.0 + SimpleForm. No need to add a column in the "users" table in DB.
View
<% label_str = t('read_html', mylink: link_to(t('terms'), '/a/b/c')) %>
<%= f.input :terms_of_service, label: label_str, as: :boolean, checked: false %>
Or, if you use Indo-European languages only, you can make it a little more simple, like:
label_str = (t('agree_html')+link_to(t('terms'), '/a/b/c')+'.').html_safe
/app/models/user.rb
attr_accessor :terms_of_service
validates_acceptance_of :terms_of_service, on: :create
validates_presence_of :terms_of_service, on: :create
/app/controllers/application_controller.rb
Devise::ParameterSanitizer::DEFAULT_PERMITTED_ATTRIBUTES[:sign_up] << :terms_of_service
# see /vendor/bundle/ruby/*/gems/devise-*/lib/devise/parameter_sanitizer.rb
Explanation
In the User model, on: create guarantees it is read only in creation. If you need to reevaluate the condition in updating, too, specify it accordingly, like on: %i(create update).
In the User model, I add validates_presence_of to play safe. The reason is, validates_acceptance_of will not be executed when the parameter terms_of_service is nil, in which case validates_presence_of will catch it and set an error. Admittedly, if the data are always submitted via the web-interface you have built AND your implementation is working perfectly, the value should be always either true or false and never be nil. So, validates_presence_of should not be necessary in this sense. It does no harm, though (except you'd need to be a little careful in manual user creation, bypassing the web-interface, such as from the Console).
The last one is neccesary for use with Devise for the same reason as in the answer by #vladCovaliov; that is, to prevent Devise from sanitizing your custom parameter, which is not a column in the database table. The one-liner in the example above can be stated in any files as long as you are sure it is read at the run-time and after Devise Ruby code. application_controller.rb is one of the sure places (though I guess there is a better-fitting place). Make sure the sentence is put out of the class ApplicationController block.

Rails, Mongoid, Devise User profiles

I'm new to rails (rails 3) and I am learning in practice.
I want to create a User-profile relation. I have created a User model with devise, and that is working well. Then I created a Profile model. The idea is to register an user and the show information about his profile and if the user wants, complete the profile.
But, the profile is related with posts. So, I need to create an empty profile with the register action of the user.
How can I do that?
My idea is to change the UsersController#create method to build the empty profile, but i don't know how.
My models
class User
include Mongoid::Document
devise :database_authenticatable, :registerable, :token_authenticable,
:omniauthable,
:recoverable, :rememberable, :trackable, :validatable
field :username
key :username
embeds_one :profile
attr_accessible :username,:password,:password_confirmation,:remember_me
class Profile
include Mongoid::Document
field :name
field :lastname
...
...
embedded_in :user, :inverse_of => :profiles
referenced_many :posts
Some idea?
It looks like you're only embedding one profile (embeds_one :profile). It should be user.profile, not user.profiles. Also, user.profile will return an instance of that document, not an array of many documents.
You could do something like this in your controller.
user.profile.create(... put any params here ...)
In your view you would then display
<h2>Welcome <%=#user.profile.username %></h2>
You also need to change
embedded_in :user, :inverse_of => :profiles
to
embedded_in :user, :inverse_of => :profile
To see if the user has a profile or not, just see if user.profile returns nil.