I have a multistep form. It's a bit complicated, cause basically first the user gets created through registrations controller, then get's redirected to a form. Speaking precisely, it's not a multistep form, but more of a two-step registration. To do validations with those is quite triky, but I figured the way, which works. In my User.rb I defined validations as follows:
validates :first_name, presence: true, :on => :create
validates :last_name, presence: true, :on => :create
validates :street, presence: true, :on => :update
But now I am having issues, with showing the errors to a user on that update step. I have the update action in my UserStepsController:
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :address
#respond_to :html, :js
def show
#user = current_user || User.from_omniauth(request.env["omniauth.auth"])
render_wizard
end
def update
#user = current_user || User.from_omniauth(request.env["omniauth.auth"])
if #user.update!(user_params)
render_wizard #user
else
render :show
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :street, :house_number, :city, :zip_code)
end
def redirect_to_finish_wizard(options = nil, params = nil)
redirect_to new_user_profile_path(current_user)
end
end
So, if the User can't be updated, cause the validations have failed, I would love to show error messages about what went wrong. For this in my address.html.erb I defined this behaviour:
<%= form_for #user, url: wizard_path do |f| %>
<% if #user.errors.any? %>
<div class="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prevented this record from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="row second 1">
<div class="column">
<div class="field wizard">
<%= f.label :street %><br />
<%= f.text_field :street, class: 'form-control' %>
</div>
</div>
This won't show the errors, but throws active record error instead:
ActiveRecord::RecordInvalid in UserStepsController#update
Validation failed: Street can't be blank
Extracted source (around line #14):
12 def update
13 #user = current_user || User.from_omniauth(request.env["omniauth.auth"])
14 if #user.update!(user_params)
15 render_wizard #user
16 else
17 render :show
What am I doing wrong?
update vs update!. If I remember update! runs save! instead of save on model. It means that it runs exception if record is not valid. update will try to call save method which runs validations
The problem was the update action. I changed it as follows.
def update
#user = current_user || User.from_omniauth(request.env["omniauth.auth"])
if #user.update_attributes(user_params)
render_wizard #user
else
render :address
end
end
I also could change my view, to lead the the shared error messages:
<%= form_for #user, url: wizard_path do |f| %>
<%= render "devise/shared/error_messages" %>
This works for both creating and updating a #user:
<% if #user.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
<%= pluralize(#user.errors.count, "error") %>.
</div>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li>* <%= message %></li>
<% end %>
</ul>
</div>
<% end %>
Related
I'm new to rails 7 and I'm following this guide:
https://guides.rubyonrails.org/getting_started.html
I'm currently at section:
7.3.3 Validations and Displaying Error Messages
The validations I made on the model seems to be working as it doesn't allow me to save empty values, but the
#model.errors.full_messages_for(:attribute_name)
doesn't look like it gets some errors because it doesn't display anything on the browser.
My model code is this:
class Article < ApplicationRecord
validates :title, presence: true
validates :body, presence: true, length: {minimum: 10}
end
My view code is this:
<h1>Create an Article</h1>
<%= form_with model: #article do |form| %>
<div>
<%= form.label :title, "Article Name: " %>
<div>
<%= form.text_field :title %>
</div>
<ul>
<% #article.errors.full_messages_for(:title).each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<div>
<%= form.label :body, "Content" %>
<div>
<%= form.text_area :body %>
</div>
<ul>
<% #article.errors.full_messages_for(:body).each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
And this is my controller
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render :new, status: "unprocessable_entity"
end
end
def show
#article = Article.find(params[:id])
end
private
def article_params
params.require(:article).permit(:title, :body)
end
end
Also, when I correctly place data on the form, it loads so fast, but if try to trigger the error by submitting the form empty, it loads so slow and when it finish to load, it doesn't display any error. But I know that the validation kicks in because it renders again the :new form.
This is the screenshot about I meant about the form that is loading so slow when error is expected on the form
Hi I have a simple app that I am building and am having trouble getting the error messages to appear when someone inputs invalid information or no information at all into a field.
The form I am using is to sign up a new user, the code associated with the user and form are below;
users_controller.rb
Class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
#country = Country.all
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to #user
else
redirect_to '/signup'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password)
end
end
user.rb
class User < ApplicationRecord
before_save { self.email = email.downcase }
validates :first_name, presence: true, length: { maximum: 25 }
validates :first_name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
has_many :trips
has_many :countries, through: :trips
end
new.html.erb
<div class="container">
<h1 class="text-center">Sign up</h1>
<div class="row">
<div class="col-md-6 offset-md-3 ">
<%=form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :first_name %>
<%= f.text_field :first_name, class: "form-control" %>
<%= f.label :last_name %>
<%= f.text_field :last_name, class: "form-control" %>
<%= f.label :email %>
<%= f.email_field :email, class: "form-control" %>
<%= f.label :password %>
<%= f.password_field :password, class: "form-control" %>
<%= f.submit "Create an account", class: 'form-control btn btn-primary' %>
<% end %>
</div>
</div>
</div>
_error_messages.html.erb
<% if #user.errors.any? %>
<div class="alert alert-danger">
The form contains <%= pluralize(#user.errors.count, "error") %>.
</div>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% else %>
<h3>test</h3>
<% end %>
When I load the form I do see the "Test" string, which I put in my _error_messages.html.erb for visibility. However when I enter data in the signup page, it reloads the page (as it should rather than sending it to the user page when all fields are valid). However, the "Test" string still appears at the top rather than the error messages that should.
My assumption is I need some sort of session or something to remember what the errors were, as right now it reloads a completely new page with nothing in memory, however, I cannot find the solution to this anywhere at the moment.
Any help would be much appreciated!
As I said, you need to change
redirect_to '/signup'
to
render 'new'
From the Guides
The render method is used so that the #user object is passed back
to the new template when it is rendered. This rendering is done within
the same request as the form submission, whereas the redirect_to will
tell the browser to issue another request.
That said, so as the redirect_to issues a new request to the browser, the values of #user is lost, in other words #user is a new instance that is instantiated again. That is why <% if #user.errors.any? %> always returns false as if there are no errors in #user.
When I clicked on "display your data" link it is showing me the following error.
Error:
NoMethodError in Users#show
Showing C:/Site/new/app/views/users/show.html.erb where line #10 raised:
undefined method `email' for #<User::ActiveRecord_Relation:0x2bd81e8>
My code snippets are given below.
views/users/index.html.erb
<h1>Choose your option</h1>
<%= link_to "Enter your data",users_new_path %>
<%= link_to "Display your data",users_show_path %>
views/users/new.html.erb
<h1>Enter your data here</h1>
<%= form_for #user,:url => {:action => 'create'} do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field:name,placeholder:"Enter your name" %><br>
<%= f.email_field:email,placeholder:"Enter your email" %><br>
<%= f.text_field:message,placeholder:"Enter your message"%><br>
<%= f.submit "Submit" %>
<% end %>
views/users/show.html.erb
<h1>Display your data</h1>
<ul>
<li>
<p>
<strong>Name:</strong>
<%= #user.name %>
</p>
<p>
<strong>Email:</strong>
<%= #user.email %>
</p>
<p>
<strong>Message:</strong>
<%= #user.message %>
</p>
</li>
</ul>
<%= link_to "Edit",users_edit_path(:id => t.id) %><%= link_to "Delete",users_delete_path(:id => t.id),data: { confirm: 'Are you sure to delete it ?' } %>
<%= link_to "Back",users_index_path %>
controller/users_controller.rb
class UsersController < ApplicationController
def index
end
def new
#user=User.new
end
def create
#user=User.new(users_params)
if #user.save
flash[:notice]="Your data is saved succesfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="You are entering wrong data"
flash[:color]="invalid"
render :new
end
end
def show
#user=User.all
end
def delete
#user=User.find(params[:id])
#user.delete
end
def edit
#edit=User.find(params[:id])
#user=User.new
end
def update
#user=User.find(params[:id])
if #user.update_attributes(update_params)
flash[:notice]="Your data has updated successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="Your data could not update..check it.."
flash[:color]="invalid"
render :edit
end
end
private
def users_params
params.require(:user).permit(:name, :email, :message,pets_attributes: [:name, :email,:message])
end
def update_params
params.require (:user).permit(:name,:email,:message,pets_attributes: [:name,:email,:message])
end
end
model/user.rb
class User < ActiveRecord::Base
has_many :pets
accepts_nested_attributes_for :pets
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :name, :presence => true,:length => { :minimum => 5 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :message, :presence => true
end
You should fix your show action from:
def show
#user = User.all
end
to:
def show
#user = User.find(params[:id])
end
In show action, you have
#user = User.all
which assigns relation with all users to #user variable. That's why you have this error, because you can't query whole relation for email. You should have:
#user = User.find(params[:id])
User.find(params[:id]) returns single User instance.
def show
#user=User.all
end
This will return array of users instead of user, so in order to call email on it you have to iterate loop over it.
<% user in #users %> <!-- I have change #user to #users in show method -->
<h1>Display your data</h1>
<ul>
<li>
<p>
<strong>Name:</strong>
<%= user.name %>
</p>
<p>
<strong>Email:</strong>
<%= user.email %>
</p>
<p>
<strong>Message:</strong>
<%= user.message %>
</p>
</li>
</ul>
<%= link_to "Edit",users_edit_path(:id => t.id) %><%= link_to "Delete",users_delete_path(:id => t.id),data: { confirm: 'Are you sure to delete it ?' } %>
<%= link_to "Back",users_index_path %>
<% end %>
Or just change show method
#user = User.find(params[:id])
fix your show action.
replace
#user = User.all
with
#user = User.find(params[:id])
I'm using Rails 4 to build a simple Admin interface for adding and removing users, or CRUD.
I'm currently having Devise installed and have built the basic views and actions.
However after filling out the forms myself, this is what I get:
2 errors prohibited this user from being saved:
Email can't be blank
Password can't be blank
This is what I have currently: (removed registerable since I don't want to have a public registration)
Models > user.rb
class User < ActiveRecord::Base
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
end
views > users > new.html.erb
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if #validatable %>
<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 "Create User" %>
</div>
<% end %>
routes.rb (currently I make new user through "/admin/users/new" )
Rails.application.routes.draw do
devise_for :users
scope '/admin' do
resources :users
end
end
Controllers > users_controller.rb
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[user_params])
if #user.save
redirect_to #user, :flash => { :success => 'User was successfully created.' }
else
render :action => 'new'
end
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[user_params])
sign_in(#user, :bypass => true) if #user == current_user
redirect_to #user, :flash => { :success => 'User was successfully updated.' }
else
render :action => 'edit'
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to users_path, :flash => { :success => 'User was successfully deleted.' }
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Does anyone have any thoughts as to what is causing the error?
Thanks :D
Just a note: previously, before I disabled :registerable in devise_modules in user.rb, I can actually perform sign-ups using the default devise view "users/sign_up". However what I want is still to get an admin CRUD system, so I disabled it anyway.
Is it typo in your def create/update:
#user = User.new(params[user_params])
# should be
#user = User.new(user_params)
if #user.update_attributes(params[user_params])
# should be
if #user.update_attributes(user_params)
I'm following the RailsSpace tutorial. My error form is being displayed always. It's always on! I don't know how to make it go away. I know that using #user.errors.clear will actually clear the messages. I tried using it in the view but no error messages will display at all. I appreciate your help.
Here is the error form code:
<% if #user.errors.any? %>
<div id="errorExplanation">
<h2>Please fix the following <%= pluralize(#user.errors.count, "error") %>:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Here is my controller:
class UserController < ApplicationController
def index
#title = "NubeMart Hub!"
end
def register
#user = User.new
#title = "Register"
if request.post?
#user = User.create(ad_params)
end
if #user.save
flash[:notice]="User #{#user.screen_name} created!"
redirect_to :action=>"index"
end
end
def ad_params
params.require(:user).permit(:screen_name, :email, :password)
end
end
And here is my view:
<h2>Register</h2>
<%= form_for :user do |form| %>
<%= render "shared/form_errors", :user => #user %>
<fieldset>
<legend>Enter Your Details</legend>
<div class="form_row">
<label for="screen_name">Screen name:</label>
<%= form.text_field :screen_name,
:size => User::SCREEN_NAME_SIZE,
:maxlength => User::SCREEN_NAME_MAX_LENGTH %>
</div>
<div class="form_row">
<label for="email">Email:</label>
<%= form.text_field :email,
:size => User::EMAIL_SIZE,
:maxlength => User::EMAIL_MAX_LENGTH %>
</div>
<div class="form_row">
<label for="password">Password:</label>
<%= form.password_field :password,
:size => User::PASSWORD_SIZE,
:maxlength => User::PASSWORD_MAX_LENGTH %>
</div>
<div class="form_row">
<%= submit_tag "Register!", :class => "submit" %>
</div>
</fieldset>
<% end %>
Your register method is wrong:
def register
#user = User.new
#title = "Register"
if request.post?
#user = User.create(ad_params)
end
if #user.save # <== This block should be moved!
flash[:notice]="User #{#user.screen_name} created!"
redirect_to :action=>"index"
end
end
This code if #user.save will execute even if the request isn't post. You have put this code outside of if block if request.post?.
I think the below code should solve your issue.
def register
#title = "Register"
if request.post?
#user = User.new(ad_params) # I have changed create to new
if #user.save # here your user will be saved(inly in case of post request)
flash[:notice]="User #{#user.screen_name} created!"
end
else
#user = User.new # (this is when request is not post)
end
redirect_to :action=>"index"
end