How can I display errors using Rails form_with (remote form with Ajax) helper?
I have this code:
def create
#incoming_package = IncomingPackage.new(tracking: params[:tracking])
if #incoming_package.save
redirect_to admin_incoming_packages_path, notice: "created"
else
flash.now[:danger] = "error" # not displayed
end
end
Here is my form:
<%= form_with url: admin_incoming_packages_path do |form| %>
<%= form.text_field :tracking, required: true, autofocus: true, autocomplete: :off %>
<%= form.submit "Add" %>
<% end %>
If there is no errors rails-ujs + Turbolinks works fine and new package is automatically added on page.
How can I display errors (or anything) if a package failed to save?
Here's a simple way to get you started:
On your form's view page:
<% if #incoming_package.errors.any?
<ul>
<% #incoming_package.errors.each do |error| %>
<li><%=error.full_messages%></li>
<% end %>
</ul>
<% end %>
Then on your create action do:
def create
#incoming_package = IncomingPackage.new(tracking: params[:tracking])
respond_to do |format|
if #incoming_package.save
flash[:success] = "The package was saved."
format.html { redirect_to admin_incoming_packages_path, notice: "created" }
format.json { render json: {success: true}
else
#errors = #incoming_package.errors.add(:base, "Some custom message here if you like")
flash.now[:danger] = "error" # not displayed
format.html { render 'new' }
format.json { render json: #incoming_package.errors, status: :unprocessable_entity }
end
end
end
You must also make sure your new action has:
#incoming_package = IncomingPackage.new
If you want to check any errors ruby give a very easy way to do it
#incoming_packages.errors.full_messages will show all errors related to your model. also you can interact with all these errors
`<%if #incoming_packages.errors.any?%>
<% #incoming_packages.errors.full_messages.each do |message| %>
<%= message %>
<%end%>
<%end%>`
Related
This is just a general question about the helper "form_for". I'm working on a program out of a textbook which has a form file using <%= form_for(#product) do |f| %>. The form is shared by the new and edit template. However, I've seen a lot of tutorials using a symbol (:product) instead of the instance variable. So, I tried swapping them to see what would happen. As it happens it gives me a routing error when trying to submit a form:
No route matches [POST] "/products/new"
and
No route matches [POST] "/products/5/edit"
Here's the code:
<%= form_for(:product) do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.text_field :price %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and in the product_controller
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
I thought I had read that "form_for :product" would search for an instance variable of the same name and use the same route, product_path, but it seems I was mistaken. I've looked at other posts on this site, but they don't seem to mention the routes. Why I'm getting this error?
EDIT: I added the option "url: products_path" to the form_for :product line and it works now. I'm guessing the symbol doesn't know to use the routes in resources like #product does?
If you have a routing error, please check the file confg/routes.rb it must include resources :products. If not, add it and restart the server.
And yes at routes we use a symbol with the table name (plural of model) for define resources.
edited:
With form_for use an instance variable: #product that was initialized on controller with an empty new product, or the finded product to update.
model
class Clip < ActiveRecord::Base
validates_length_of :description, maximum: 160
end
controller
def update
#clip = #film.clips.find_by_permalink(params[:id])
respond_to do |format|
if #clip.update(clip_params)
format.html { redirect_to saas_admin_studio_film_path(#studio, #film), notice: 'Clip was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #clip.errors, status: :unprocessable_entity }
end
end
end
view
<%= render 'saas_admin/shared/errors', resource: resource %>
<%= resource %> generates #<Clip:0x0000010c6c64e0> so resource is loaded. However, <%= resource.errors.any? %> returns false. If I change in controller #clip.update(clip_params) to #clip.update!(clip_params) I get:
Validation failed: Description is too long (maximum is 160 characters)
So the validation works, it's just that it's not taken by .errors to display it.
_errors
<% if resource.errors.any? %>
<ul>
<% resource.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
Any ideas why this is happening? Thank you.
I don't think resource is the same Clip object as #clip.
Where in the code are you assigning #clip to be resource? I can't see where you have defined resource at all.
If you change it to be <%= render 'saas_admin/shared/errors', resource: #clip %> does the problem resolve?
As you have seen, though it probably seems backwards, the main difference between update and update! is how failed saves are handled.
When updating an ActiveRecord class the ! version will raise an exception if the record is invalid.
More info at http://api.rubyonrails.org/classes/ActiveRecord/Base.html
I have a page called /add that you can add a Dog on and the form is in its own partial. I'm using Simple Form and Twitter Bootstrap. I added the files for the main Bootstrap but use a gem for simple_form to work with it just so you know.
DogsController
# new.js.erb (deleted new.html.erb)
def new
#dog = Dog.new
respond_to do |format|
format.js
end
end
# create.js.erb
def create
#dog = current_user.dogs.new(params[:dog])
respond_to do |format|
if #dog.save
format.html { redirect_to add_url, notice: 'Dog was successfully added.' }
format.json { render json: #dog, status: :created, location: #dog}
format.js
else
format.html { render 'pages/add' }
format.json { render json: #dog.errors, status: :unprocessable_entity }
end
end
end
dogs/_form.html.erb
<%= simple_form_for(#dog, :remote => true) do |f| %>
<%= render :partial => "shared/error_message", :locals => { :f => f } %>
<%= f.input :name %>
<%= f.button :submit, 'Done' %>
<% end %>
This line: <%= render :partial => "shared/error_message", :locals => { :f => f } %>
Is for bootstrap so it renders the errors html correctly.
PagesController
def add
respond_to do |format|
format.html
end
end
pages/add.html.erb
<div id="generate-form">
</div>
dogs/new.js.erb
$("#generate-form").html("<%= escape_javascript(render(:partial => 'dogs/form', locals: { dog: #dog })) %>");
Now how would I get this to render the error partial as if it was still on my dogs/new.html.erb since its being created through AJAX? I don't need client side validations do I?
EDIT
shared/_error_message.html.erb
<% if f.error_notification %>
<div class="alert alert-error fade in">
<a class="close" data-dismiss="alert" href="#">×</a>
<%= f.error_notification %>
</div>
<% end %>
Through our chat you mentioned you also had a create.js.erb and that file was clearing out the form.
making the the create.js the same as new.js.erb :
$("#generate-form").html("<%= escape_javascript(render(:partial => 'dogs/form', locals: { dog: #dog })) %>");
made it work.
You don't have to do client side validations. But should,it is common to disable the submit button via js until client side validation is met.
also I would not delete the new.html.erb incase a client doesn't.have js turned on.
I think your add may need format.js to your add and
remote = true to your shared errors partial call
I have a issue with flash message in my application. Actually in my application i have used the devise for users authentication and my application with ruby 1.9.3 and rails 3.2.2.
When an user is login, logout and sign up for new account the devise flash[:notice] is working fine.
In Rails flash[:notice] and flash[:alert] are the default flash messages.
The flash messages are display only once when page reload or when the user negative from one page to other page
The issue is when user is login the devise flash[:notice] is displaying but when i reload the page the flash[:notice] is displaying, but in rails the flash[:notice] will display only once
Actually the issue is when i try to create a new post i have redirect to the show page and i have write helper method for flash message this method i have call from the application layout for displaying the flash messages.
In controller create method
def create
#asset = Asset.new(params[:asset])
#asset.user_id = current_user.id
respond_to do |format|
if #asset.save
format.html { redirect_to #asset, alert: 'Asset was successfully created.' }
format.json { render json: #asset, status: :created, location: #asset }
else
format.html { render action: "new" }
format.json { render json: #asset.errors, status: :unprocessable_entity }
end
end
end
The Helper method for displaying flash messages
FLASH_TYPES = [:error, :warning, :success, :message,:notice,:alert]
def display_flash(type = nil)
html = ""
if type.nil?
FLASH_TYPES.each { |name| html << display_flash(name) }
else
return flash[type].blank? ? "" : "<div class=\"#{type}\"><p>#{flash[type]}</p> </div>"
end
html.html_safe
end
i have call this method form the application layout
= display_flash
I have tried with the flash[:alert], flash[:error],flash[:message] but no message display on the view page and i have tried with gem called flash_message this also displays only the
flash[:notice]
Please help me to solution this issue
Hy i am using using this approach to show flash message.First i make partial
_flash.html.erb in shared.The code of this partial
<% [:alert, :notice, :error].select { |type| !flash[type].blank? }.each do |type| %>
<p>
<% if flash[:notice] %>
<div class="alert-message error">
<h2 style="color: #ffffff;">Notice:</h2> <br/>
<%= flash[type] %>
</div>
<% elsif flash[:error] %>
<div class="alert-message error">
<h2 style="color: #ffffff;">Errors</h2> <br/>
<% flash[:error].each_with_index do |error, index| %>
<%= index+1 %>. <%= error %> <br/>
<% end %>
</div>
<% end %>
</p>
<% end %>
and i call it in application layout like this
<div id="flash">
<%= render :partial => 'shared/flash', :object => flash %>
</div>
And in controller use notice,alert like this
flash[:notice] = 'Admin was successfully created.'
flash[:alert] = 'Admin was successfully created.'
But for showing errors i use array because it may be more than one.Like this
def create
#user = User.new(params[:user])
#user.is_activated = true
# #user.skip_confirmation!
if #user.save
role = Role.find_by_name("admin")
RoleUser.create!(:user => #user, :role => role)
redirect_to :controller => '/administrator', :action => 'new'
flash[:notice] = 'Admin was successfully created.'
else
flash[:error]=[]
#user.errors.full_messages.each do |error|
flash[:error] << error
end
render :action => "new"
end
end
add this line in application.js
setTimeout("$('#flash').html(' ');", 10000);
Use it and enjoy!!!!!!!!!!!!!!
I can't seem to get the flow to work right here. I have a Ruby on Rails (2.3.9) application. For the purposes of this question we have only a couple of resources. Boxes and Messages.
Box has_many :messages
Message belongs_to :box
I have created a view located at /boxes/1/new_message where I have the below form_for code. I can successfully create a message from this view. The problem arrises when my validations kick in.
In this case, message.body can't be blank and is validated by message.rb. Once this validation happens, it kicks the user over to the Message.new action and upon successfully filling in the message.body the app can no longer find the #box.id to place in message.box_id.
I have tried just about everything I can think of by not sure how to allow a users to receive a validation and still successfully create a message for a box. See my code below for reference.
/views/boxes/new_message.html.erb
<% form_for [#box, Message.new] do |f| %>
<%= f.error_messages %>
<%= f.label :message_title %>
<%= f.text_field (:title, :class => "textfield-message grid_12 alpha") %>
<%= f.label :message_body %>
<%= f.text_area (:body, :class => "textarea-message grid_12 alpha ") %>
<%= f.submit "Add a Message", :class => 'input boxy' %>
<% end %>
messages_controller.rb
def create
#message = Message.new(params[:message])
#box = Box.find(params[:box_id])
#message = #box.messages.build(params[:message])
#message.user = current_user
respond_to do |format|
if #message.save
flash[:notice] = 'Message was successfully created.'
format.html {redirect_to #box }
else
format.html { render :action => "new" }
format.xml { render :xml => #flash.errors, :status => :unprocessable_entity }
end
end
end
def new
#message = Message.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #message }
end
end
I believe your
#box = Box.find(params[:box_id])
should be
#box = Box.find(params[:id])