Rails4 422 (Unprocessable Entity) in devise model AJAX call - ruby-on-rails

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

Related

Issue creating a User through an Account model Rails 5 with Devise

What I'm trying to accomplish:
When a user registers with my app they are taken to a new account creation page. This is where they enter their desired subdomain. from this form I also want to create the owner (a user class).
The problem:
As it sits right now, when i fill out the generated form (below)
<%= form_for #account do |f| %>
<%= fields_for :owner do |o| %>
<p>
<%= o.label :f_name %>
<%= o.text_field :f_name %>
</p>
<p>
<%= o.label :m_name %>
<%= o.text_field :m_name %>
</p>
<p>
<%= o.label :l_name %>
<%= o.text_field :l_name %>
</p>
<p>
<%= o.label :email %>
<%= o.email_field :email %>
</p>
<p>
<%= o.label :password %>
<%= o.password_field :password %>
</p>
<p>
<%= o.label :password_confirmation %>
<%= o.password_field :password_confirmation %>
</p>
<% end %>
<p>
<%= f.label :subdomain %>
<%= f.text_field :subdomain %>
</p>
<%= f.submit %>
<% end %>
and try to submit the form, I get the following rails server output:
Started POST "/accounts" for 127.0.0.1 at 2018-04-08 21:52:57 -0600
Processing by AccountsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"4yUhk6N40udNBMoBJz/sFzbjC/RUtU7FVyHe9NlhtBkmpGEMZE0+xMcD7E6GLOjgp02hbkrbuMNLQ5gBjh+kvA==", "owner"=>{"f_name"=>"xxxxx", "m_name"=>"xxxxx", "l_name"=>"xxxxx", "email"=>"xxxxx#xxxxxnltd.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "account"=>{"subdomain"=>"testinga"}, "commit"=>"Create Account"}
(0.2ms) BEGIN
Account Exists (0.6ms) SELECT 1 AS one FROM "accounts" WHERE LOWER("accounts"."subdomain") = LOWER($1) LIMIT $2 [["subdomain", "testinga"], ["LIMIT", 1]]
(0.1ms) ROLLBACK
Rendering accounts/new.html.erb within layouts/application
Rendered accounts/new.html.erb within layouts/application (2.4ms)
Completed 200 OK in 49ms (Views: 21.5ms | ActiveRecord: 8.3ms)
Now when I read the output I cant seem to find why this is rolling back and not saving. I do see it telling me an account already exists whit that subdomain, however this is a CLEAN database and there are no accounts saved in it! When I run byebug just before the #account.save in the accounts controller (below) there are no error messages or details I can find.
My AccountController: (I've left the byebug in the controller, perhaps im putting it in the wrong place?)
class AccountsController < ApplicationController
def index
end
def show
end
def new
#account = Account.new
#account.build_owner
end
def create
#account = Account.new(account_params)
byebug
if #account.save
redirect_to root_path, notice: 'Account creates successfully.'
else
render action: 'new'
end
end
def edit
end
def update
end
def destroy
end
private
def account_params
params.require(:account).permit(:subdomain, :owner_id, :plan_id, :account_verified, :account_status, owner_attributes: [:id, :email, :password, :password_confirmation, :f_name, :m_name, :l_name, :office_country_code, :office_phone_number, :mobile_country_code, :mobile_phone_number])
end
end
My Account model
class Account < ApplicationRecord
RESTRICTED_SUBDOMAINS = %w(www admin loadlead)
belongs_to :owner, class_name: 'User'
has_many :users
validates :owner, presence: true
validates :subdomain, presence: true,
#uniqueness: { case_sensitive: false },
format: { with: /\A[\w\-]+\Z/i, message: 'contains invalid characters'},
exclusion: { in: RESTRICTED_SUBDOMAINS, message: 'restricted name'}
before_validation :downcase_subdomain
accepts_nested_attributes_for :owner
protected
def downcase_subdomain
self.subdomain = subdomain.try(:downcase)
end
end
My User model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
belongs_to :account
end
Any assistance here would be greatly appreciated! I have no idea where I'm going wrong with this? Thanks in advance.
Try to call fields_for on f builder instead:
<%= form_for #account do |f| %>
<%= f.fields_for :owner do |o| %>
<p>
<%= o.label :f_name %>
<%= o.text_field :f_name %>
</p>
# ....
<% end %>
# ....
<%= f.submit %>
<% end %>
And you can remove :owner_id, this attribute value will be set automatically by Rails when we're using :accepts_nested_attributes_for.
You are calling #account.save which does not raise an exception. It returns true if everything is fine, or returns false when the validation fails (if #account.valid? returns false).
If there are any validation errors, you can check them by calling:
pry(main)> #account.valid?
pry(main)> false
pry(main)> #account.errors
That should help you debug the issue.

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 %>

rails 4 Devise 4 Invitable - Params Sanitizer not working

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.

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

Adding data to nested model rails 4.0

New to rails and can't figure out how to do this. I have implemented a user log in system using devise and I am trying to let a user create multiple "listings". Sort of like a craigslist type site. I can populate the database from the rails console but I cant figure out how to put it on the site.
I have the following models:
listing.rb
class Listing < ActiveRecord::Base
belongs_to :user
default_scope -> { order('created_at DESC') }
#add validations
validates :user_id, presence: true
end
user.rb (used devise)
class User < ActiveRecord::Base
has_many :listings, dependent: :destroy
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
I am trying to create a page which allows a user to create a new listing. I am not exactly sure how to go about doing this. This is what I have currently:
listings_controller.rb
class ListingsController < ApplicationController
def index
#users = User.all
end
def show
#listing = Listing.find(params[:id])
end
def new
#listing = Listing.new
end
def create
#listing = Listing.new(listing_params)
if #listing.save
flash[:success] = "Success"
redirect_to #listing
else
render 'new'
end
end
private
def listing_params
params.require(:listing).permit(:id, :user_id, :title, :general_info)
end
end
models/views/listings/new.html.erb
<h1> POST A NEW LISTING </h>
<%= form_for #listing do |f| %>
Title: <%= f.text_field :title %> <br />
General Info: <%= f.text_field :general_info %> <br />
<%= f.submit %>
<% end %>
Ive been working on this for quite a while with no luck getting the database to populate. Currently the form once submits hits the "else" in def create and just renders the same page.
Here is the log output when I run this:
Started POST "/listings" for 127.0.0.1 at 2013-07-04 17:37:53 -0600
Processing by ListingsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"mlyDb24OMQkniOCFQ1JTvzxjplHk7kMgzEBEFBH8hGw=", "listing"=>{"title"=>"title should go here", "general_info"=>"hope this works"}, "commit"=>"Create Listing"}
[1m[35m (0.1ms)[0m begin transaction
[1m[36m (0.1ms)[0m [1mrollback transaction[0m
[1m[35mUser Load (0.3ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Rendered listings/new.html.erb within layouts/application (4.4ms)
Completed 200 OK in 17ms (Views: 10.4ms | ActiveRecord: 0.5ms)
The following got this to work for anyone who comes across this problem:
In routes.db I put the listings in a block:
resources :users do
resource :listings
end
For the new/show/create methods I made sure to search for the user first (note since I am using devise the current_user.id)
def show
#listing = Listing.find(current_user.id)
end
def new
#user = User.find(current_user.id)
#listing = #user.listings.build
end
def create
#user = User.find(current_user.id)
#listing = #user.listings.build(listing_params)
if #listing.save
flash[:success] = "Success"
redirect_to root_path
else
render :action => 'new'
end
end
then finally, changed the form_for in new.html.erb to this:
<%= form_for [#user, #listing] do |f| %>
<%= f.label :title, 'Title' %> <br />
<%= f.text_field :title %>
...
<%= f.submit "submit" %>
<% end %>

Resources