How to create a profile for devise user? - ruby-on-rails

I'm new to rails and trying to create a profile for devise users when they signup, using nested form in devise signup. I've gone through
Creating Profile for Devise users,
Profile model for Devise users?
and few other articles to achieve the same but after a day in vain, I'm still trying to make it work. Here is my code.
Model - user.rb
class User < ActiveRecord::Base
has_one :user_profile
accepts_nested_attributes_for :user_profile
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Model - user_profile.rb
class UserProfile < ActiveRecord::Base
belongs_to :user
end
Controller - controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) {|u|
u.permit(:email, :password, :password_confirmation, :remember_me,
user_profile_attributes: [:first_name, :last_name])}
end
end
end
View - views/devise/registrations/new.html.erb
<h2>Sign up</h2>
<% resource.build_user_profile %>
<%= 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 %>
</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>
<%= f.fields_for :user_profile do |profile_form| %>
<%= profile_form.label :first_name %><br/>
<%= profile_form.text_field :first_name %><br/>
<%= profile_form.label :last_name %><br/>
<p><%= profile_form.text_field :last_name %><br/>
<% end %>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
Server Log
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"utf8"=>"√", "authenticity_token"=>"rLuFXwISxiJpWPjpmKzjnjhKr41F5
56sWbtT+8gslAMsFDWRbl7MSitSXUESjLdZccCBGBGvVv+JbhW7G5py5g==", "user"=>{"email"=>
"zebandz#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTER
ED]", "user_profile_attributes"=>{"first_name"=>"Zeban", "last_name"=>"Dezend"}}
, "commit"=>"Sign up"}
Unpermitted parameter: user_profile_attributes
I think, I'm missing the code to fetch the values from params and create a new record. Can someone suggest me the fix ?

please follow the below steps.
devise> reg > new
<div class="row">
<div class="col-md-5 col-md-offset-4">
<h2>Sign up</h2>
<% resource.build_user_profile if resource.user_profile.nil? %>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="row">
<%= f.fields_for :user_profile do |profile_form| %>
<div class="col-md-6">
<div class="form-group">
<%= profile_form.label :first_name %>
<%= profile_form.text_field :first_name, class: "form-control" %>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<%= profile_form.label :last_name %>
<%= profile_form.text_field :last_name, class: "form-control" %>
</div>
</div>
<% end %>
</div>
<div class="form-group">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, class: "form-control" %>
</div>
<%= f.fields_for :user_profile do |profile_form| %>
<div class="form-group">
<%= profile_form.label :business_name %>
<%= profile_form.text_field :business_name, class: "form-control" %>
</div>
<div class="form-group">
<%= profile_form.label :business_category %>
<%= profile_form.collection_select :business_category_id, BusinessCategory.all, :id, :name, {prompt: "Select Category"}, {class: "form-control"} %>
</div>
<div class="form-group">
<%= profile_form.label :website %>
<%= profile_form.url_field :website, class: "form-control" %>
</div>
<div class="form-group">
<%= profile_form.label :address %>
<%= profile_form.text_area :address, class: "form-control" %>
</div>
<div class="form-group">
<%= profile_form.label :personal_number %>
<%= profile_form.text_field :phone_number, class: "form-control" %>
</div>
<div class="form-group">
<%= profile_form.label :office_number %>
<%= profile_form.text_field :office_number, class: "form-control" %>
</div>
<% end %>
<div class="form-group">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off", class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %>
</div>
<div class="actions">
<%= f.submit "Sign up", class: "btn btn-primary" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
</div>
</div>
user reg controller
def new
# Override Devise default behaviour and create a profile as well
build_resource({})
resource.build_user_profile
respond_with self.resource
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u|
u.permit(:email, :password, :password_confirmation, :user_profile_attributes => [:first_name, :last_name, :business_name, :business_category_id, :website, :address, :phone_number, :office_number])
}
end

Have you tried following these steps from their github page?
They set the permitted parameters in the ApplicationController. Also the structure is a little different. The parameters go into keys.
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
added_attrs = [:username, :email, :password, :password_confirmation, :remember_me]
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
end
end

Related

Problem with nested attributes for Devise registration page

I need to add Address nested attributes for User.
But only user_id hits the addresses table when I submit, and not country city street and zip_code
user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates_presence_of :name, :age, :email
has_one :address, dependent: :destroy
accepts_nested_attributes_for :address
address.rb
attr_accessor :country, :city, :zip_code, :street
belongs_to :user
appication_controller.rb
before_action :configure_permitted_parameters, if: :devise_controller?
...
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :age,
address_attributes: [:country, :city, :zip_code, :street]])
end
The form
<% resource.build_address %>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="form-group">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :name %><br />
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :age %><br />
<%= f.number_field :age, class: 'form-control' %>
</div>
<h4>Address</h4>
<%= f.fields_for :address do |address| %>
<div class="form-group">
<%= address.label :country %>
<%= address.text_field :country, class: 'form-control' %>
</div>
<div class="form-group">
<%= address.label :city %>
<%= address.text_field :city, class: 'form-control'%>
</div>
<div class="form-group">
<%= address.label :street %>
<%= address.text_field :street, class: 'form-control'%>
</div>
<div class="form-group">
<%= address.label :zip_code %>
<%= address.text_field :zip_code, class: 'form-control' %>
</div>
<% end %>
<div class="form-group">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password", class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control' %>
</div>
<div class="form-group">
<%= f.submit "Sign up", class: 'btn btn-success' %>
</div>
<% end %>

TypeError in Devise::RegistrationsController#create

For Devise with Rails 4.2., I am able to sign up users when I turn off confirmation required in my user model but when I turn it back on I get this error.
no implicit conversion of Array into String <
# i.e. OpenSSL::Digest::SHA1#block_length
def generate_key(salt, key_size=64)
OpenSSL::PKCS5.pbkdf2_hmac_sha1(#secret, salt, #iterations, key_size)
end
end
referring to this line
devise (3.5.10) lib/devise/token_generator.rb:50:in `pbkdf2_hmac_sha1'
I am using mailtrap for my development settings and I am able to get mail in my contact page.
In my user.rb I have
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
My devise initalizer is set exactly the same as another project that works.
In my application controller, I have set parameters
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:firstname, :lastname, :email, :avatar, :password, :password_confirmation) }
end
My views/devise contain the folders (confirmations, mailer, passwords, registrations, sessions, shared, and unlocks.
My devise registrations new is below:
<div class="row">
<%= bootstrap_devise_error_messages! %>
<div class="panel panel-default devise-bs">
<div class="panel-heading">
<h4><%= t('.sign_up', :default => "Sign up") %></h4>
</div>
<div class="panel-body">
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: { role: "form" }) do |f| %>
<div class="form-group">
<%= f.label :firstname %>
<%= f.text_field :firstname, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :lastname %>
<%= f.text_field :lastname, 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 :avatar %><br>
<%= f.file_field :avatar, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off", class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %>
</div>
<%= f.submit t('.sign_up', :default => "Sign up"), class: "btn btn-primary" %>
<% end %>
</div>
<div class="panel-footer">
<%= render "devise/shared/links" %>
</div>
</div>
Any tips on what I could be doing wrong, I have spun my wheels for a couple of days.
Thanks :)
Check that your to_json/as_json in your user.rb is working properly.

Ruby on rails: can't save profile model associated with Devise user

I have Devise user model and associated profile model. Here it is:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile, autosave: true
accepts_nested_attributes_for :profile
before_create :build_profile
end
Profile model:
class Profile < ActiveRecord::Base
belongs_to :user
end
Next, I include profile fields in default Devise view:
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<%= f.fields_for :profile do |profile_form| %>
<div class="field">
<%= profile_form.label :username %><br />
<%= profile_form.text_field :username %>
</div>
<div class="field">
<%= profile_form.label :address %><br />
<%= profile_form.text_field :address %>
</div>
<div class="field">
<%= profile_form.label :pin %><br />
<%= profile_form.text_field :pin %>
</div>
<% end %>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><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="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
<%= link_to "Back", :back %>
Now, when I update form, Devise field is updated, but profile fields - not. If I trying to update profile thru rails console, everything works just great.
u = User.find_by(id: 2)
u.profile.pin = 123
u.save
Solved! Just override Devise permitted_parameters in ApplicationController like this:
before_action :configure_devise_permitted_parameters, if: :devise_controller?
protected
def configure_devise_permitted_parameters
registration_params = [:email, :password, :password_confirmation, profile_attributes: [:username, :address, :pin]]
if params[:action] == 'update'
devise_parameter_sanitizer.for(:account_update) {
|u| u.permit(registration_params << :current_password)
}
elsif params[:action] == 'create'
devise_parameter_sanitizer.for(:sign_up) {
|u| u.permit(registration_params)
}
end
end
Thanks #max for answer.

Validates "presence true" works with edit page but wont work with sign up page

This is my first question here and im a newbie in rails. I have a weird problem.
I was following One Month Rails course and I added :name column to DB for user and wanted each new user to have Name while registering and also beign able to change his name while accessing the Edit Page. I added that to devise and wanted to validate so it can't be blank.
The problem is that Edit page works fine (says properly when it's blank and allows for name change) but the Sign Up page ALWAYS says "Name can't be blank" and forbids from creating new user. I have no idea why it is happening, anyone could help?
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) << :name
end
end
Here i added Validates in user class:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :vins, dependent: :destroy
validates :name, presence: true
end
This is sign up page:
<div class="panel panel-default">
<div class="panel-heading">
<h2>Sign up</h2>
</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 %><br />
<%= 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 :password %>
<% if #validatable %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off", class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Sign up", class: "btn btn-primary" %>
</div>
<% end %>
<div class="btn btn-default btn-sm">
<%= render "devise/shared/links" %>
</div>
</div>
</div>
And edit page:
<div class= "panel panel-default">
<div class="panel-heading">
<h2>Edit <%= resource_name.to_s.humanize %></h2>
</div>
<div class= "panel-body">
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.label :name %><br />
<%= f.text_field :name, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, class: "form-control" %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="form-group">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "off", class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off", class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Update", class: "btn btn-primary" %>
</div>
<% end %>
<div class= "panel-footer">
<%= link_to "Back", :back %>
</div>
</div>
</div>
Your problem seems to be that you're defining the configure_permitted_parameters twice in your ApplicationController. So the first definition gets overwritten by the second, and thus the :name parameter is not passed to the sign_in method through the sanitation. So simply combining the method definition should get rid of the problem.
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
devise_parameter_sanitizer.for(:account_update) << :name
end

Devise user model not updating

When I submit the user update form, I don't get any errors, but the info doesn't update.
Here is my RegistrationsController
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:username, :email, :password, :password_confirmation, :firstname, :lastname, :displayname)
end
def account_update_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password)
end
end
Here is part of my routes.rb
devise_for :users, :controllers => { registrations: 'registrations' }
Finally here is the devise/registrations/edit.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= render 'shared/error_messages' %>
<h1>Edit Your Profile</h1>
<div class="row">
<div class="col-md-4">
<h3>Social</h3>
<hr>
<div class="form-group">
<%= f.label :displayname, "Display Name" %><br>
<%= f.text_field :displayname, autocomplete: "off", class: "form-control" %>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<%= f.label :firstname, "First Name" %><br>
<%= f.text_field :firstname, class: "form-control" %>
</div>
<div class="col-md-6">
<%= f.label :lastname, "Last Name" %><br>
<%= f.text_field :lastname, class: "form-control" %>
</div>
</div>
</div>
<%= f.label :twitter, "Twitter" %><br>
<div class="input-group">
<div class="input-group-addon">twitter.com/</div>
<%= f.text_field :twitter, class: "form-control" %>
</div>
<br>
<%= f.label :facebook, "Facebook" %><br>
<div class="input-group">
<div class="input-group-addon">facebook.com/</div>
<%= f.text_field :facebook, class: "form-control" %>
</div>
<br>
<%= f.label :reddit, "Reddit" %><br>
<div class="input-group">
<div class="input-group-addon">reddit.com/u/</div>
<%= f.text_field :reddit, class: "form-control" %>
</div>
<br>
<%= f.label :github, "Github" %><br>
<div class="input-group">
<div class="input-group-addon">github.com/</div>
<%= f.text_field :github, class: "form-control" %>
</div>
<br>
<%= f.label :youtube, "Youtube" %><br>
<div class="input-group">
<div class="input-group-addon">youtube.com/user/</div>
<%= f.text_field :youtube, class: "form-control" %>
</div>
<br>
<%= f.label :twitch, "Twitch" %><br>
<div class="input-group">
<div class="input-group-addon">twitch.tv/</div>
<%= f.text_field :twitch, class: "form-control" %>
</div>
</div>
<div class="col-md-4">
<h3>Login Info</h3>
<hr>
<div class="form-group">
<%= f.label :email %><br>
<%= f.email_field :email, autofocus: true, class: "form-control" %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div class="alert alert-warning">Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="form-group">
<%= f.label :password %><br>
<%= f.password_field :password, autocomplete: "off", class: "form-control" %>
<span class="help-block">Leave blank if you don't want to change it</span>
</div>
<div class="form-group"><%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %>
</div>
<div class="form-group"><%= f.label :current_password %>
<%= f.password_field :current_password, autocomplete: "off", class: "form-control" %></div>
<span class="help-block">Please enter your current password to confirm your changes</span>
</div>
<div class="col-md-4">
<h3>Your Stats</h3>
<hr>
</div>
</div>
<br>
<div class="form-group"><%= f.submit "Update", class: "btn btn-success" %></div>
<% end %>
<%= link_to "Back", :back %>
User Model:
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :timeoutable, :lockable
#ROLES = "%w[default plus moderator administrator suspended banned]"
# BEGIN HAS_MANYS
has_many :posts
has_many :assignments
has_many :evaluations, class_name: "RSEvaluation", as: :source
has_reputation :votes, source: {reputation: :votes, of: :posts}, aggregated_by: :sum
# BEGIN METHODS
def voted_for?(post)
evaluations.where(target_type: post.class, target_id: post.urlid).present?
end
# def has_role?(role_sym)
# roles.any? { |r| r.name.underscore.to_sym == role_sym }
# end
end
I have face same problem while updating user account with rails 4, but there is problem with parameter permitted .
Please update your controller like
class RegistrationsController < Devise::RegistrationsController
before_filter :update_sanitized_params, if: :devise_controller?
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:username, :email, :password, :password_confirmation, :firstname, :lastname, :displayname)}
devise_parameter_sanitizer.for(:account_update) {|u| u.permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password)}
end
end
It will work :)

Resources