I can't figure out what I am doing incorrectly when trying to load ActiveRecord validation errors with AJAX. I cannot get the ajax:error to trigger unless I have already submitted a valid form and triggered ajax:success. I have tried only binding the ajax:error to see if the success could be blocking it. I have read through the rails documentation on working with javascript in rails, and Googled my problem to no avail. I have tried to use both .bind() and .on() but I haven't seen a difference. I am sure there is something incredibly simple that I am missing, but I have been looking at this too long and I don't seem to be getting anywhere.
Here is the code.
Model
class User < ActiveRecord::Base
before_create :set_activation_key
before_save :encrypt_password
before_save :downcase_username
after_save :clear_password
validates :username,
format: {
with: /\A.*\z/,
message: 'invalid'
},
uniqueness: {message: 'already in use'},
presence: {message: 'cannot be blank'}
validates :email_address,
format: {
with: /\A.+@.+\..+\z/,
message: 'invalid'
},
uniqueness: {message: 'already in use'},
presence: {message: 'cannot be blank'}
validates :password, :confirmation => true,
presence: {message: 'cannot be blank'},
length: {:within => 6..20,
:too_long => 'too long',
:too_short => 'too short',
}
def encrypt_password
if password.present?
self.salt = BCrypt::Engine.generate_salt
self.password = BCrypt::Engine.hash_secret(password, salt)
end
end
def clear_password
self.password = nil
end
def set_activation_key
self.activation_key = SecureRandom.urlsafe_base64
end
def downcase_username
self.username = self.username.downcase
end
def self.authenticate(username, password)
user = User.find_by_username(username.to_s.downcase)
if user && user.password == BCrypt::Engine.hash_secret(password, user.salt)
user
else
nil
end
end
end
Controller
class Users::UsersController < ApplicationController
# GET /register
def new
@user = User.new
end
# POST /users
def create
@user = User.new(user_params)
respond_to do |format|
if @user.save
UserMailer.registration_email(@user.email_address).deliver
format.html { redirect_to root_path, notice: 'Check your email' }
format.js
else
format.html { render action: 'new' }
format.js { render json: @user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:username, :email_address, :password, :password_confirmation)
end
end
Partial
<%= form_for User.new, remote: true do |f| %>
<div id="registration_messages"></div>
<div id="registration_errors"></div>
<%= f.label :username %>
<%= f.text_field :username%>
<%= f.label :email_address %>
<%= f.text_field :email_address %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, 'Confirm Password' %>
<%= f.password_field :password_confirmation %>
<%= f.submit 'Register', :class => 'tiny button' %>
<a class="close-reveal-modal">×</a>
<% end %>
create.js.erb
$(document).ready(function() {
$('#new_user')
.bind("ajax:success", function(event, data, xhr, status){
var $form = $(this);
$form.find('input[type=text], input[type=password], textarea').val('');
$("div#registration_messages").append('<div data-alert class="alert-box success">Check your email</div>');
}).bind("ajax:error", function(event, data, xhr, error){
console.log(event);
console.log(data);
console.log(xhr);
console.log(error);
alert("ajax:error");
});
});
This doesn't help you with your current technique, but you could try doing it in pure JQuery and ditch the js.erb file. I've always found this way more straightforward once you get the hang of it. I would expect something like the following code not to produce the issue you're seeing.
controller
javascript.js