rails 4 Devise 4 Invitable - Params Sanitizer not working - ruby-on-rails

I am using Devise Invitable in my rails 4 app, I have some extra fields that the user needs to fill out when they set their password.
I have created the invitation controller and added the extra fields to the update_sanitized_params method in the controller. When I fill out the form the server out put gives me:
Started PUT "/users/invitation" for 127.0.0.1 at 2016-10-11 12:57:34 -0600
Processing by InvitationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"c0c75noldd9hB6pHjLh1A74KWsWGrIc/K4s7PUJkmtnCG9Uz3YMEJMiBKSpC8Fk+ObC67oBx6E5AxS0R/xZlUA==", "user"=>{"f_name"=>"Steve", "l_name"=>"Jenkinson", "date_of_birth"=>"1975-01-01", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Accept Invitation"}
Account Load (1.0ms) SELECT "public"."accounts".* FROM "public"."accounts" WHERE "public"."accounts"."subdomain" = $1 LIMIT $2 [["subdomain", "10-106security"], ["LIMIT", 1]]
Rendering devise/invitations/edit.html.erb within layouts/application
Rendered devise/invitations/edit.html.erb within layouts/application (2.9ms)
Rendered shared/_signed_out_nav.html.erb (1.4ms)
Completed 200 OK in 60ms (Views: 53.1ms | ActiveRecord: 2.0ms)
However the user attributes are not being saved. This was verified in rails console.
Console Output after submitting the Invitation Edit form:
User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<User id: 3, email: "test1#test.com", f_name: nil, l_name: nil, date_of_birth: nil, employee_number: nil, system_id: nil, created_at: "2016-10-11 19:33:33", updated_at: "2016-10-11 19:33:33", invitation_token: "d7024926f142aeeec1d23781f1832f74317b592f5bcdd5e6a3...", invitation_created_at: "2016-10-11 19:33:33", invitation_sent_at: "2016-10-11 19:33:33", invitation_accepted_at: nil, invitation_limit: nil, invited_by_type: "User", invited_by_id: 1, invitations_count: 0>
my application controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
# Before Actions
before_filter :configure_permitted_parameters, if: :devise_controller?
before_action :load_schema, :authenticate_user!, :set_mailer_host
# Custom Methods
private
def load_schema
Apartment::Tenant.switch!('public')
return unless request.subdomain.present?
if current_account
Apartment::Tenant.switch!(current_account.subdomain)
else
redirect_to root_url(subdomain: false)
end
end
def current_account
#current_account ||= Account.find_by(subdomain: request.subdomain)
end
helper_method :current_account
def after_sign_out_path_for(resource_or_scope)
new_user_session_path
end
def set_mailer_host
subdomain = current_account ? "#{current_account.subdomain}." : ""
ActionMailer::Base.default_url_options[:host] = "#{subdomain}lvh.me:3000"
end
def after_invite_path_for(resource)
users_path
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:accept_invitation, keys: [:f_name, :l_name, :date_of_birth, :password, :password_confirmation, :invitation_token])
end
end
and here is the form:
<%= bootstrap_form_for resource, :as => resource_name, :url => invitation_path(resource_name), method: :put do |f| %>
<%= f.text_field :f_name, label: 'First Name' %>
<%= f.text_field :l_name, label: 'Last Name' %>
<%= f.date_field :date_of_birth, label: 'Date Of Birth' %>
<%= f.password_field :password, label: 'Password' %>
<%= f.password_field :password_confirmation, label: 'Confirm Password' %>
<%= f.submit "Accept Invitation", :class => 'btn btn-primary' %>
<% end %>
here is the User model:
class User < ApplicationRecord
# Before Actions
# Devise Modules
devise :invitable, :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :timeoutable
# Relationships
# Validations
validates :f_name, presence: true
validates :l_name, presence: true
validates :date_of_birth, presence: true
# Custom Methods
def full_name
l_name.upcase + ", " + f_name
end
end
any assistance here would be greatly appreciated!

the problem here was that upon editing the devise_invitable form the user would fill out, I did not add the authentication token.

Related

Nested form won't display for has_one relationship Simple_Form (Rails 4)

I set my user model up to build the user_profile before being created. The user_profile itself is being shown in the console when I load the user object. #user = User.find(1) -> #user.user_profile -> UserProfile Load. The relationship works correctly. The issue is I am unable to make changes to the user profile with the edit user_profile action. The edit page is empty, even though the attributes for the user_profile exist. How can I get the form to load in the edit view, so that the user is able to make changes to his/her profile after logging into their account? Side note: The user does not edit their normal profile during registration.
user.rb
class User < ApplicationRecord
# Include default devise modules.
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable
include DeviseTokenAuth::Concerns::User
before_create :build_user_profile
extend FriendlyId
after_validation :geocode
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
friendly_id :username, use: :slugged
has_one :user_profile
accepts_nested_attributes_for :user_profile
protected
def confirmation_required?
false
end
end
user_profile.rb
class UserProfile < ApplicationRecord
mount_uploader :avatar, UserAvatarUploader
belongs_to :user, :dependent => :destroy
validates_integrity_of :avatar
validates_processing_of :avatar
end
_form.html.erb
<%= simple_form_for(#user_profile, :html => {:multipart => true}) do |f| %>
<%= f.error_notification %>
<div class="form-group">
<% f.simple_fields_for :user_profile do |user_profile| %>
<div class="col-md-4">
<% if current_user.user_profile.avatar.url.present? %>
<%= image_tag(current_user.user_profile.avatar.url) %>
<%= user_profile.label :remove_avatar do %>
<%= user_profile.input :remove_avatar, as: :boolean, checked_value: true, unchecked_value: false %>
<% end %>
<%= user_profile.input :avatar, as: :file, class: 'form-control' %>
<%= user_profile.input :birthday, label: false, id: 'datepicker', class: 'form-control' %>
<% end %>
<div class="form-group">
<div class="col-md-4">
<%= f.button :submit %>
</div>
</div>
<% end %>
<% end %>
schema.rb
create_table "user_profiles", force: :cascade do |t|
t.date "birthday"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "avatar"
t.index ["user_id"], name: "index_user_profiles_on_user_id"
end
user_profiles_controller.rb
class UserProfilesController < ApplicationController
#before_action :set_user_profile, only: [:show, :edit, :update]
before_action :authenticate_user!
before_action :load_profile, only: [:edit, :update]
def show
end
# GET /user_profiles/1/edit
def edit
end
# PATCH/PUT /user_profiles/1
# PATCH/PUT /user_profiles/1.json
def update
respond_to do |format|
if #user_profile.update(user_profile_params)
format.html {redirect_to #user_profile, notice: 'User profile was successfully updated.'}
format.json {render :show, status: :ok, location: #user_profile}
else
format.html {render :edit}
format.json {render json: #user_profile.errors, status: :unprocessable_entity}
end
end
end
private
def load_profile
#user_profile = current_user.user_profile
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_profile_params
params.require(:user).permit(user_profile: [:birthday, :avatar, :user_id])
end
end
Rails Console
#user = User.find(5)
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 5], ["LIMIT", 1]]
#<User id: 5, email: "colejohn#hotmail.com", username: "johnny", first_name: "John", last_name: "Woo">
>> #user.user_profile
UserProfile Load (2.0ms) SELECT "user_profiles".* FROM "user_profiles" WHERE "user_profiles"."user_id" = $1 LIMIT $2 [["user_id", 5], ["LIMIT", 1]]
#<UserProfile id: 2, birthday: nil, user_id: 5, created_at: "2017-08-17 20:47:12", updated_at: "2017-08-17 20:47:12", avatar: nil>
The edit page is empty, even though the attributes for the
user_profile exist.
This line
<% f.simple_fields_for :user_profile do |user_profile| %>
should be
<%= f.simple_fields_for :user_profile do |user_profile| %>
You are missing =, which is the reason for the form being empty.
Misplaced if statement termination <% end %> in simple_form
<% if current_user.user_profile.avatar.url.present? %>
<%= image_tag(current_user.user_profile.avatar.url) %>
<%= user_profile.label :remove_avatar do %>
<%= user_profile.input :remove_avatar, as: :boolean, checked_value: true, unchecked_value: false %>
<% end %>
<% end %>

Save a has_one model with a nested form with Devise - Rails 4

I'm stuck in a rails project trying to save a has_one model when the user signs up with Devise.
My app is saving the child model as well as the new user but the issue is that it doesn't save the child id in the user table.
I've tried plenty of options found on Stackoverflow without success.
Am I doing something wrong?
User model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:linkedin]
# Associations
has_one :build, inverse_of: :user
# Allow saving of attributes on associated records through the parent,
# :autosave option is automatically enabled on every association
accepts_nested_attributes_for :build, allow_destroy: true
end
build model
class Build < ActiveRecord::Base
belongs_to :user, inverse_of: :build
has_one :template
# validates_presence_of :user
end
Registrations Controller
class Users::RegistrationsController < Devise::RegistrationsController
before_action :sign_up_params, only: [:create]
before_action :account_update_params, only: [:update]
# before_filter :configure_permitted_parameters
# GET /resource/sign_up
def new
# super
# Override Devise default behaviour and create a build as well
build_resource({})
resource.build_build
respond_with self.resource
# #build = #user.builds.build(template_id: params[:template_id], domain_url: params[:domain_url])
end
# POST /resource
def create
super
# #build = current_user.build.build(params[:post])
# #build = #user.build.build(template_id: sign_up_params[:template_id], domain_url: sign_up_params[:domain_url])
# #build.save
UserMailer.welcome_email(#user).deliver unless #user.invalid?
end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
# def update
# super
# end
# DELETE /resource
# def destroy
# super
# end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
# def cancel
# super
# end
# protected
#
# def configure_permitted_parameters
# devise_parameter_sanitizer.for(:sign_up) { |u|
# u.permit(:first_name, :last_name, :email, :password, :password_confirmation, :builds_attributes => [:template_id, :domain_url])
# }
# end
# If you have extra params to permit, append them to the sanitizer.
# def configure_sign_up_params
# devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
# end
# If you have extra params to permit, append them to the sanitizer.
# def configure_account_update_params
# devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
# end
# The path used after sign up.
# def after_sign_up_path_for(resource)
# super(resource)
# end
# The path used after sign up for inactive accounts.
# def after_inactive_sign_up_path_for(resource)
# super(resource)
# end
private
def sign_up_params
devise_parameter_sanitizer.sanitize(:sign_up)
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, build_attributes: [:template_id, :domain_url])
end
def account_update_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password)
end
end
New User Form - View
<div class="container">
<h4 class="center-align">Sign up</h4>
<div id="signup-row" class="row z-depth-2">
<div id="signup" class="col s6">
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :first_name %><br/>
<%= f.text_field :first_name, autofocus: true %>
</div>
<div class="field">
<%= f.label :last_name %><br/>
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :email %><br/>
<%= f.email_field :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="actions">
<%= f.submit "Sign up", :class => 'btn black' %>
<%= render "devise/shared/links" %>
</div>
<%= f.fields_for :build do |o| %>
<%= o.hidden_field :template_id, value: params["template"] %>
<%= o.hidden_field :domain_url, value: params["domain"] %>
<% end %>
<% end %>
</div>
<div id="linkedin-signup" class="col s6">
<div class="center-align">
<h5>Sign up with LinkedIn </h5> <br>
<%= image_tag('linkedin.png', :class => "linkedIn-logo" ) %>
</div>
</div>
</div>
</div>
Server /post log
Started POST "/users" for 127.0.0.1 at 2016-08-03 13:31:22 +1000
Processing by Users::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"11DgWCU07EXLJKXbhWah0gREdBiN2PLkF/WxWsuqW5rgQdCUrRH9rLBrKpbusRhtsCzSAQT0ADlxhQxMvWAD6A==", "user"=>{"first_name"=>"john", "last_name"=>"maksksk", "email"=>"jofff#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "build_attributes"=>{"template_id"=>"1", "domain_url"=>"dddddd.com.au"}}, "commit"=>"Sign up"}
(0.1ms) BEGIN
User Exists (0.6ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'jofff#gmail.com' LIMIT 1
SQL (0.5ms) INSERT INTO "users" ("first_name", "last_name", "email", "encrypted_password", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["first_name", "john"], ["last_name", "maksksk"], ["email", "jofff#gmail.com"], ["encrypted_password", "$2a$11$WgJJ.uM2DfaqQhUYatUZnuIJmaqIDVfIuYEkl/U3zSbm.h/OH/yGa"], ["created_at", "2016-08-03 03:31:22.796589"], ["updated_at", "2016-08-03 03:31:22.796589"]]
SQL (0.2ms) INSERT INTO "builds" ("template_id", "domain_url", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["template_id", 1], ["domain_url", "dddddd.com.au"], ["user_id", 30], ["created_at", "2016-08-03 03:31:22.800033"], ["updated_at", "2016-08-03 03:31:22.800033"]]
(1.3ms) COMMIT
(0.1ms) BEGIN
SQL (0.4ms) UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "last_sign_in_ip" = $3, "current_sign_in_ip" = $4, "sign_in_count" = $5, "updated_at" = $6 WHERE "users"."id" = $7 [["last_sign_in_at", "2016-08-03 03:31:22.804259"], ["current_sign_in_at", "2016-08-03 03:31:22.804259"], ["last_sign_in_ip", "127.0.0.1/32"], ["current_sign_in_ip", "127.0.0.1/32"], ["sign_in_count", 1], ["updated_at", "2016-08-03 03:31:22.805380"], ["id", 30]]
(1.2ms) COMMIT
Thanks for your help!!
ps: build wasn't a smart name for a table I guess...
Thomas
The problem is that user saved first and then you saved build for relationship purpose you can save user_id to build table instead of saving build_id to user
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, build_attributes: [:id, :template_id, :domain_url])
build_attributes should has :id
making a test
def create
user = User.new(sign_up_params)
user.save
end
model User.rb
has_one :build
accepts_nested_attributes_for :build, allow_destroy: true
rails console
user = User.new(name: 'example', build_attributes:{template_id:1, domain_url: 'test'})
user.save # this will create user and after that will create has_one build association
user.errors unless user.save

Rails won't properly assess conditional before_save callback

I have my app schema defaulting the User.role attribute to "new". My goal for my before_save callback is for the User model to change the user.role attribute to "admin" if the user being created is the first one, otherwise it leaves it alone.
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
ROLES = %w[admin moderator member new]
after_save :assign_role
def assign_role
if self == User.first
self.role = "admin"
self.touch
end
end
def is?(requested_role)
self.role == requested_role.to_s
end
end
Rails console
vagrant#vagrant-ubuntu-trusty-64:/vagrant$ rails c
Loading development environment (Rails 4.2.1)
2.1.5 :001 > User.any?
(0.3ms) SELECT COUNT(*) FROM "users"
=> false
2.1.5 :002 > User.last
User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC
LIMIT 1
=> #<User id: 1, email: "**************", encrypted_password: "$
2a$10$FEOjKX1UAZwiEVPbXXW.TOCyh2d7iwIuIRKn8YmYWk....", reset_password_token: nil
, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, curre
nt_sign_in_at: "2015-08-20 14:23:31", last_sign_in_at: "2015-08-20 14:23:31", cu
rrent_sign_in_ip: #<IPAddr: IPv4:10.0.2.2/255.255.255.255>, last_sign_in_ip: #<I
PAddr: IPv4:10.0.2.2/255.255.255.255>, created_at: "2015-08-20 14:23:31", update
d_at: "2015-08-20 14:23:31", confirmation_token: nil, confirmed_at: nil, confirm
ation_sent_at: nil, role: "new">
2.1.5 :003 > User.last
User Load (1.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC
LIMIT 1
=> #<User id: 2, email: "***********.com", encrypted_password: "$2a$10$OtjtlW
BAcrqlws1q5N/ICe6Hjytb0GhKGrVmdcin.Op...", reset_password_token: nil, reset_pass
word_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_a
t: "2015-08-20 14:24:44", last_sign_in_at: "2015-08-20 14:24:44", current_sign_i
n_ip: #<IPAddr: IPv4:10.0.2.2/255.255.255.255>, last_sign_in_ip: #<IPAddr: IPv4:
10.0.2.2/255.255.255.255>, created_at: "2015-08-20 14:24:44", updated_at: "2015-
08-20 14:24:44", confirmation_token: nil, confirmed_at: nil, confirmation_sent_a
t: nil, role: "new">
2.1.5 :004 >
The first user created in the console should have role:"admin" instead of role:"new"
EDIT:
save new user form
<div class="border-form-div">
<h2 class="text-center">Create a new account</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<%= f.email_field :email, :autofocus => true, :placeholder => 'Email address' %>
<%= f.hidden_field :role, :value => "new" %>
<%= f.password_field :password, :placeholder => 'Password' %>
<%= f.password_field :password_confirmation, :placeholder => 'Password confirmation' %>
<%= f.submit "Sign up", :class => 'btn btn-primary center-block' %>
<% end %>
</div>
user_controller.rb
class UserController < ApplicationController
before_action :authenticate_user!
params.require(:user).permit(:username, :email, :password, :encrypted_password, :role)
end
The controller is fairly empty because I'm using devise to handle all the account management
before_save {|user| user.role = "admin"}, unless: :user_exists?
def user_exists?
User.any?
end

Rails 4 and Devise: nested attributes validations not working

I am using Devise in my rails 4 app. I have a member model (for devise) and a user model that contains all the profile info for each member. A member accepts nested attributes for user. See the form below for a new registration as well as the custom routes in my routes.rb file.
My problem is this - everything works fine except validation of the user attributes. If I leave first name and last name blank, then it validates (but crashes like this:
But all the other validations for Member (the devise model) work - they end up on the /members page with the error message displayed as it should. I am unsure as to what is going on - shouldn't devise show the error messages for the invalid nested attributes?
class Members::RegistrationsController < Devise::RegistrationsController
# GET /resource/sign_up
def new
build_resource({})
self.resource.user = User.new
respond_with self.resource
end
# POST /resource
def create
super
resource.user.ip_address = request.remote_ip
resource.user.email = resource.email
resource.user.save!
end
private
def sign_up_params
allow = [:provider, :uid, :email, :password, :password_confirmation, user_attributes: [:member_id, :email, :first_name, :last_name, :institution, :city, :country, :job_title, :about, :tag_list, :picture, :ip_address]]
params.require(resource_name).permit(allow)
end
end
Member.rb
class Member < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :trackable
has_one :user, dependent: :destroy, autosave: true
accepts_nested_attributes_for :user
end
User.rb
class User < ActiveRecord::Base
belongs_to :member
validates :first_name, presence: true
validates :last_name, presence: true
end
In my routes.rb
devise_for :members, controllers: {registrations: 'members/registrations',
omniauth_callbacks: 'members/omniauth_callbacks',
sessions: 'members/sessions' }
In my members/registrations/new.html.erb
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: { role: "form" }) do |f| %>
<%= f.fields_for(:user) do |user_fields| %>
<%= user_fields.text_field :first_name, autofocus: true, class: 'form-control', :placeholder => "First name" %>
<%= user_fields.text_field :last_name, class: 'form-control', :placeholder => "Last name" %>
<% end %>
<%= f.email_field :email, autofocus: true, class: "form-control", :placeholder => "Email" %>
<%= f.password_field :password, class: "form-control", :placeholder => "Password" %>
<%= f.submit t('.sign_up', :default => "Sign up"), class: "btn btn-danger" %>
<% end %>
Here is the log for this
Started POST "/members" for ::1 at 2015-07-16 15:18:54 +0100
Processing by Members::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"sIxK1PTvrxNHUBdDXAtKFLLG27FvqypQ3mUvo398tHOMomi1S3I2o3vBM GwrF6PVN1NFBR5vnr8ezKP6XnMzqw==", "member"=>{"user_attributes"=>{"first_name"=>"", "last_name"=>""}, "email"=>"slfwalsh#gmail.com", "password"=>"[FILTERED]"}, "commit"=>"Sign up"}
(0.2ms) begin transaction
Member Exists (0.3ms) SELECT 1 AS one FROM "members" WHERE "members"."email" = 'slfwalsh#gmail.com' LIMIT 1
(0.1ms) rollback transaction
Rendered devise/shared/_links.erb (9.9ms)
Rendered members/registrations/new.html.erb within layouts/static_home_page (19.8ms)
Rendered layouts/_static_login_header.html.erb (4.1ms)
(0.1ms) begin transaction
(0.1ms) rollback transaction
Completed 422 Unprocessable Entity in 1499ms
The reason why you are seeing that page is because save! triggers validation errors if the validation for any of the attributes is failed and those errors are displayed in the page. On the other hand save doesn't display the validation errors but just cancels the transaction from being saved if any of the validations are failed. Changing your create method like below should solve your problem.
def create
super
resource.user.ip_address = request.remote_ip
resource.user.email = resource.email
resource.user.save
end

Rails4 422 (Unprocessable Entity) in devise model AJAX call

I have a form_for that uses AJAX to update custom fields I added to the devise user model. However, upon submit (with valid input), I get a POST 422 (Unprocessable Entity) error. This occurs because of the validations in my user model below:
class User < ActiveRecord::Base
validates_presence_of :annual_income, :current_savings, :retirement_savings, :if => :enable_strict_validation
validates_numericality_of :annual_income, :current_savings, :retirement_savings, :if => :enable_strict_validation
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Here is the form:
<div class="main_form">
<h1>Income & Savings First...</h1>
<%= form_for #user, url: { action: :persist_data }, method: :post, remote: true, html: { id: "insurance_form" } do |f| %>
<%= f.label "Total Annual Income" %>
<%= f.text_field :annual_income, autofocus: true, placeholder: "Enter $" ,value: "", class: "format_me" %><br/>
<%= f.label "Savings" %>
<%= f.text_field :current_savings, placeholder: "Enter $", value: "", class: "format_me" %><br/>
<%= f.label "Saved for Retirement?" %>
<%= f.text_field :retirement_savings, placeholder: "Enter $", value: "", class: "format_me" %><br/>
<%= f.submit "Calculate", class: "btn btn-primary" %>
<% end %>
</div>
The call is made to the HomeController below:
class HomeController < ApplicationController
before_filter :authenticate_user!
def index
#user = current_user
end
# TODO: refactor as update in a custom devise controller for user
def persist_data
user_params.each {|key, val| val.gsub!("$", "") }
# Make sure user model validations are run
current_user.enable_strict_validation = true
current_user.save!
current_user.update_attributes( user_params )
render json: {status: "OK"}
end
private
def user_params
params.require(:user).permit(:annual_income, :current_savings, :retirement_savings, :recommended_insurance)
end
end
And lastly, here is the server log with the error:
Started POST "/home/persist_data" for 127.0.0.1 at 2014-03-12 12:11:34 -0400
Processing by HomeController#persist_data as JS
Parameters: {"utf8"=>"✓", "user"=>{"annual_income"=>"$4.00", "current_savings"=>"$4.00", "retirement_savings"=>"$4.00"}, "commit"=>"Calculate"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 ORDER BY "users"."id" ASC LIMIT 1
(0.1ms) begin transaction
(0.1ms) rollback transaction
Completed 422 Unprocessable Entity in 35ms
ActiveRecord::RecordInvalid (Validation failed: Annual income can't be blank, Annual income is not a number, Current savings can't be blank, Current savings is not a number, Retirement savings can't be blank, Retirement savings is not a number):
app/controllers/home_controller.rb:13:in `persist_data'
Thanks for the help.
Update persist_data as below:
def persist_data
## Set the user_params value
user_params = user_params.each {|key, val| val.gsub!("$", "") }
# Make sure user model validations are run
current_user.enable_strict_validation = true
## Remove below line, as you are updating in the very next line with user_params
## current_user.save!
current_user.update_attributes( user_params )
render json: {status: "OK"}
end

Resources