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
Related
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%>`
In my views, I have comments/_form.html.erb, and there is another controller views for post posts/show.html. I want to render comments/_form.html.erb in posts/show.html, which shows an individual post and comments associated with that post, and it is all set and working fine.
I want to provide ability to comment and render that partial below these comments so that we can make new comment on the same posts/show.html page instead of navigating to comments/new.html.erb page. I am using nested resources like:
resources :posts do
resources :comments
end
In my comments/new.html.erb, I am doing this:
<%= form_for([:post, #comment]) do |f| %>
....
<% end %>
How should I render it in my posts/show.html.erb page?
Javascript is the missing piece in your puzzle. Essentially you'll do 3 things.
Make sure your form is using js to submit (remote)
Make sure your controller responds to js input
Create a js.erb file that will append each new comment
Implementation notes:
I would probably do something like this:
Add the form to the view, and add an element that wraps around the comments, in this case, I used ul#comments
# app/views/posts/show.html.erb
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Body:</strong>
<%= #post.body %>
</p>
<br/>
<ul id="comments">
<%= render #comments %>
</ul>
<%= form_for [#post, #new_comment], remote: true do |f| %>
<%= f.text_field :body %>
<%= f.submit %>
<%end%>
Add the js response in the controller
# app/controllers/comments_controller.rb
def create
#post = Post.find params[:post_id]
#comment = #post.comments.new(comment_params)
#new_comment = #post.comments.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to [#post, #comment], notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
format.js
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
Then add a ujs file to make your changes on the fly (this does 2 things, adds a new comment and empties the form).
# app/views/comments/create.js.erb
$('#comments').append("<%= escape_javascript(render partial: '/comments/comment', locals: { comment: #comment } ) %>");
$('form.new_comment').find("input#comment_body").val('');
Also to note::
I'm using #new_comment so there is no interference when you render a newly created comment
You'll need to add #new_comment in 2 places, first in your posts show action and also in your comments create action
Hi I am currently making an app with users, albums, and photos. I managed to make the AJAX work for the create action when I upload pics, but I can't get AJAX to work for the delete. Instead, it redirects me to an empty show page for the pic. Can anyone give me some guidance?
photos controller:
def destroy
#user = User.find(params[:user_id])
#album = #user.albums.find(params[:album_id])
#photo = #album.photos.find(params[:id])
# #photo.destroy
flash[:success] = "Photo successfully deleted."
respond_to do |format|
if #photo.destroy
format.js
# format.json { render json: #photo, status: :created, location: #photo}
# redirect_to user_album_path(#user, #album)
end
end
end
destroy.js.erb (I'm supposed to have this right?)
$('.destroypicswrapper').remove(".<%= #photo.avatar.url %>");
_photodestroy.html.erb partial:
<div class="picthumb <%= photo.avatar.url %>">
<%= link_to image_tag(photo.avatar.url ? photo.avatar.url(:small) : #album.name), root_url %>
<br>
<%= link_to "Delete", user_album_photo_path(#user, #album, photo), :remote => true, method: :delete, data: { confirm: "Are you sure? "} %>
</div>
and finally the albums/edit.html.erb page where the delete is initially happening:
<% provide(:title, "Edit album") %>
<%= render 'form' %>
<div class="destroypicswrapper">
<% if #album.photos.any? %>
<%= render :partial => 'photodestroy', :collection => #album.photos, :as => :photo %>
<% end %>
</div>
I don't think you want to render the full url of an image as a class of a div. Also, your Jquery is wrong. Try something like this:
destroy.js.erb
$('.destroypicswrapper > #photo_<%= #photo.id %>').remove();
Adjust your _photodestroy.html.erb to:
<div class="picthumb" id="photo_<%= photo.id %>">
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])
I'm really struggling with how to handle Error Handling in Rails 3. I have hacked some ideas that could work but would rather do it the proper way. If anyone can help or give guidance I would appreciate it. Here is what I have so far
ItemController
def show
#item = Item.find(params[:id])
#note = #item.notes.new
respond_with(#item)
end
NoteController
def create
#note = #item.notes.build(params[:note])
flash[:notice] = 'Your note was successfully added!' if #note.save
respond_with(#item)
end
items/show.html.erb
<%= form_for ([#item, #note]), :html => {:id => 'form-add-item-note'} do |f| %>
I have tried
<%=f.error_messages%>
<%=error_messages_for :note%>
<%=error_messages_for :item,:note%>
and even have a template for handling errors
<%= render "global/error_messages", :target => #item %>
which contains
<% if target.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
<ul>
<% target.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I believe I'm losing the errors to the redirect but I can't seem to quite get how to redirect or render the item controller from the failed save in the note create and I would love to be able to pass the error global template the #note and it render the errors
If you redirect, you'll lose any error messages. You need to render a view, instead of redirecting if your object isn't valid and does not save. I'm not sure yet of the best way to do it in rails3 with the respond_with method, but if you look at the scaffolding rails3 generates, you see how handling failed saves works.
respond_to do |format|
if #post.save
format.html { redirect_to(#post, :notice => 'Post was successfully created.') }
format.xml { render :xml => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end