Rails4 + bootstrap3 modal form to a different model not displaying ajax errors - ajax

I'm using an example from Eric London http://ericlondon.com/2014/03/13/rails-4-submit-modal-form-via-ajax-and-render-js-response-as-table-row.html
And have adapted it slightly to my scenario:
While editing a Team (model) I want to pop a modal form to Add a new User. I can get this working i.e. when all fields are correct, the record is saved and the modal closes, but I am not getting errors back into the modal when there is a problem.
I also am uncertain how to structure the Create controller action correctly - this is definitely not right.
In the Users controller, create action (below) I can save the record as I expect, I have commented out the original code (I still need this - its the defaults for normal user management)
def create
#if params[:modal].nil? || params[:modal] == ''
# create! { users_url }
#else
respond_to do |format|
password = Devise.friendly_token.first(6)
#user.password = password
#user.password_confirmation = password
#user.external = true
if #user.save!
format.js { render action: 'show', status: :created, location: #user }
else
format.js { render json: #user.errors, status: :unprocessable_entity }
end
end
#end
end
the show.js.erb view
$('#new_user_modal').modal_success();
and the application.js code:
$(document).ready(function(){
$(document).bind('ajaxError', 'form#new_user', function(event, jqxhr, settings, exception){
// note: jqxhr.responseJSON undefined, parsing responseText instead
$(event.data).render_form_errors( $.parseJSON(jqxhr.responseText) );
});
});
(function($) {
$.fn.modal_success = function(){
// close modal
this.modal('hide');
// clear form input elements
// todo/note: handle textarea, select, etc
this.find('form input[type="text"]').val('');
// clear error state
this.clear_previous_errors();
};
$.fn.render_form_errors = function(errors){
$form = this;
this.clear_previous_errors();
model = this.data('model');
// show error messages in input form-group help-block
$.each(errors, function(field, messages){
$input = $('input[name="' + model + '[' + field + ']"]');
$input.closest('.form-group').addClass('has-error').find('.help-block').html( messages.join(' & ') );
});
};
$.fn.clear_previous_errors = function(){
$('.form-group.has-error', this).each(function(){
$('.help-block', $(this)).html('');
$(this).removeClass('has-error');
});
}
}(jQuery));
in the teams form I have the link and the modal definition:
<%# Added Bootstrap data modal attribute %>
<%= link_to 'Add an External User', '#new_user_modal', 'data-toggle' => 'modal', class: 'btn btn-default' %>
<%# Bootstrap modal markup. #see: http://getbootstrap.com/javascript/#modals %>
<div class="modal fade" id="new_user_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Create new User</h4>
</div>
<div class="modal-body">
<%# Render the new person form (passing modal => true to enable remote => true) %>
<%= render 'users/new', modal: true %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
in the users/_new.html.erb view I have:
<% #user = User.new %>
<%= simple_form_for #user, remote: true, input_html: {role: :form, 'data-model' => 'user'} do |f| -%>
<% if #user.errors.any? %>
<div id="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 %>
<fieldset>
<!-- username -->
<%= f.input :remote_id, label: "Payroll Code / Username" %>
<!-- basic settings -->
<div class="row">
<div class="col-md-6">
<%= f.input :first_name %>
</div>
<div class="col-md-6">
<%= f.input :last_name %>
</div>
</div>
<%= f.input :email %>
</fieldset>
<div class="actions">
<%= f.submit 'Submit', class: 'btn btn-primary' %>
</div>
<% end -%>
So, to sum up where I am at:
I want to add new users from a modal form while editing another
model
The approach above mostly works...
But is heinously ugly - it
feels wrong/messy and I am not happy with it.

It seems you don't have any 'help-block' classes on your form.
Try:
$.each(errors, function(field, messages){
$input = $('input[name="' + model + '[' + field + ']"]');
$span_error = $("<span></span>").addClass('help-block').html( messages.join(' & ') );
$form_input = $input.closest('.form-group').addClass('has-error').find('.form-control');
$span_error.insertAfter($form_input);
});
Instead of:
// show error messages in input form-group help-block
$.each(errors, function(field, messages){
$input = $('input[name="' + model + '[' + field + ']"]');
$input.closest('.form-group').addClass('has-error').find('.help-block').html( messages.join(' & ') );
});

Related

Ruby on Rails Ajax with Remote Forms

Hello when I add the comment in my application in the form that I have with ajax, I have to reload the browser to upload the comment. In the browser I get this error that I supposedly have in this file:
(function() {
$(document).on("ajax:success", "form#comments-form", function(ev, data) {
console.log(data);
$(this).find("textarea").val("");
return $("#comments-box").append("<li> " + data.body + " - </li>");
});
$(document).on("ajax:error", "form#comments-form", function(ev, data) {
return console.log(data);
});
}).call(this);
I have this file in comments.coffe like this:
$(document).on "ajax:success", "form#comments-form", (ev,data)->
console.log data
$(this).find("textarea").val("")
$("#comments-box").append("<li> #{data.body} - </li>")
$(document).on "ajax:error", "form#comments-form", (ev,data)->
console.log data
If you can help me, I thank you.
I had the same problem and, solve it by doing the following
In the folder app/asset/javascripts/application.js look for the next line
//= require rails-ujs and change for // require rails-ujs
In this way that library is not called and will not generate conflict with jquery.
I hope it helps you
<%=
form_for([#article,#comment], remote: true, html: { id: "comments-form", :"data-
type" =>
"json" }) do |f| %>
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(comment.errors.count, "error") %> prohibited this comment
from
being saved:</h2>
<ul>
<% comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :body %>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

Rails 4: Receiving the following error: First argument in form cannot contain nil or be empty

I am receiving the following error on a project of mine: First argument in form cannot contain nil or be empty. I am trying to create an edit page for my code. Fairly new with Rails and trying to learn without scaffolding.
Controller:
class BooksController < ApplicationController
def new
#book = Book.new
#authors = Author.all
end
def edit
#book = Book.find(params[:id])
end
def show
#Notice how the #books is plural here.
#books = Book.all
#authors = Author.all
##books = Book.where(id: params[:id])
end
#Create method will save new entries
def create
#book = Book.new(book_params)
#authors = Author.all
if #book.save
flash[:success] = "Book Added to Databse!"
redirect_to #book
else
render 'new'
end
end
private
#Note that this method will go up into the create method above.
def book_params
params.require(:book).permit(:title, :pub_date, :publisher, :author_id)
end
end
Model Page: (For Book)
class Book < ActiveRecord::Base
validates :title, :pub_date, :publisher, presence: true
validates :title, uniqueness: true
belongs_to :author
end
Model Page: (For Author)
class Author < ActiveRecord::Base
validates :name, presence: true
validates :name, uniqueness: true
has_many :books
end
Edit page:
<h1>Update a book entry</h2>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#book) do |f| %> **ERROR SEEMS TO BE RIGHT HERE!!!**
<%= render 'form' %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :pub_date %>
<%= f.text_field :pub_date, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :publisher %>
<%= f.text_field :publisher, class: 'form-control' %><br />
</div>
<div class="form-group">
<%= f.select(:author_id,
#authors.collect {|a| [ a.name, a.id ]},
{:include_blank => 'Please select an author'},
class: "form-control") %><br />
</div>
<%= f.submit 'Save Changes', class: "btn btn-primary" %>
<% end %>
</div>
</div>
Render form page (_form.html.erb)
<% if #book.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
<h2><%= pluralize(#book.errors.count, "error") %>
prohibited this entry from being saved:</h2>
<ul>
<% #book.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
SHOW PAGE:
<div class="move">
<h1>Showing Book Titles:</h1>
</div><br />
<div class="row">
<% #books.each do |book| %>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-body">
<h2><%= book.title %></h2>
<h2><%= book.publisher %></h2>
<h2><%= book.pub_date %></h2>
<h2><%= book.author.name %></h2>
<h2><%= link_to "Edit", edit_path, class: "btn btn-primary" %>
</div>
</div>
</div>
<% end %>
Here is my Log telling me what is wrong:
Started GET "/edit" for ::1 at 2015-08-14 16:49:17 -0400
Processing by BooksController#edit as HTML
Rendered books/edit.html.erb within layouts/application (2.2ms)
Completed 500 Internal Server Error in 9ms (ActiveRecord: 0.0ms)
ActionView::Template::Error (First argument in form cannot contain nil or be empty):
3: <div class="row">
4: <div class="col-md-6 col-md-offset-3">
5:
6: <%= form_for(#book) do |f| %>
7: <%= render 'form' %>
8:
9: <div class="form-group">
app/views/books/edit.html.erb:6:in `_app_views_books_edit_html_erb___525891009649529081_70260522100960'
I will say that I have deleted the first 14 books from my data base and so the first book start on ID 14. Not sure if that matters.
Finally, I have tried adding all of these different instance variables to my controller in the edit method:
##book = Book.where(id: params[:id])
##book = Book.find_by_id(params[:id])
##book = Book.all
##book = Book.find_by_id(params[:id])
#book = Book.new(book_params)
#When I use the two below lines,
there are no error pages but create a new entry.
##book = Book.new
##authors = Author.all
Any Help will be appreciated! Thank you for your time!!!
This error means that the first argument to form_for is a nil value (in this case #book). Most of the times I've seen this, it's due to malformed controller actions, but that doesn't look to be the case here. From what I can tell, it's one of two things:
You're trying to edit a Book that doesn't exist. Do a .nil? check on it before deciding to render the form, and render an error message (or redirect) instead.
Your routes are broken, and the edit action is not rendering the edit view. This is most likely not the case.
EDIT:
After updating with your template for show, this looks like your problem:
<%= link_to "Edit", edit_path, class: "btn btn-primary" %>
I see two problems with this (though I'll need to see the output of rake routes to verify). Firstly, you need to pass an argument to the edit path (without them, where would your params come from?). Secondly, the default route for this would be edit_book_path.
Try this:
<%= link_to "Edit", edit_book_path(book), class: "btn btn-primary" %>
Assuming book ID 14 is in your database, you should be able to navigate to localhost:3000/books/14/edit if you created it with something like resources :books (documentation here). If this doesn't work, either your routes are not defined correctly or book with ID 14 does not exist in your database.
On your show view, change the link_to line to:
<%= link_to 'Edit', edit_book_path(book), class: "btn btn-primary" %>
So two changes:
Again, assuming book is a Restful resource, when you run rake_routes, you should see the path to edit is edit_book_path.
You need to pass the book instance with the path so Rails knows which object you wish to edit.
I found the correct syntax here.
Hope this helps.

Ransack Search Ajax in Application Layout Rails

I have a Rails 4.2 app in which I'm using Ransack mixed with Geocoder for search. I want to use an Ajax (remote: true) for my search to avoid pageloads and changing of the URL.
When I implement this in my index view it works great, but I want to abstract the search box to the application layout file so it's available site wide instead of just on the index view. When I do this (see code example) I'm able to search just fine, but the problem is I can't seem to figure out how to get the Ajax/Remote: True to work. Here is my code:
application.html.erb
<%= search_form_for(#search, url:"/resources", :method => :get, remote: true) do |f| %>
<%= text_field_tag :location, params[:location], placeholder: "Houston, TX", class: "input-sm form-control" %>
<%= f.submit "Find", class:'btn btn-sm btn-info' %>
<% end %>
application_controller.rb
before_action :build_search
private
def build_search
if params[:location].present?
#search = Resource.near(params[:location], 100).search(params[:q])
else
#search = Resource.search(params[:q])
end
end
resources/index.js.erb
$("#mapdisplay").html("<%= escape_javascript render("map") %>");
$("#results").html("<%= escape_javascript render("results") %>");
resources/index.html.erb
<div id="mapdisplay">
<%= render 'map' %>
</div>
<div id="results">
<%= render 'results' %>
</div>
resources_controller.rb
before_action :set_search_results, only: [:show, :index, :new]
def index
#hash = Gmaps4rails.build_markers(#resources) do |resource, marker|
marker.lat resource.latitude
marker.lng resource.longitude
end
respond_to do |format|
format.html {}
format.js {}
end
end
private
def set_search_results
#resources = #search.result(distinct: true)
end
resources/_map.html.erb
<script src="//maps.google.com/maps/api/js?v=3.13&sensor=false&libraries=geometry" type="text/javascript"></script>
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js' type='text/javascript'></script>
<h4>Resources</h4>
<div id="search">
<%= render 'search' %>
</div>
<div class="pull-right">
<%= link_to "Add", new_resource_path, class: 'btn btn-info btn-medium' %>
</div>
<div style='width: 800px;'>
<div id="map" style='width: 800px; height: 400px;'></div>
</div>
<script>
handler = Gmaps.build('Google');
handler.buildMap({
provider: {
disableDefaultUI: true
// pass in other Google Maps API options here
},
internal: {
id: 'map'
}
},
function(){
markers = handler.addMarkers(<%=raw #hash.to_json %>);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
}
);
</script>
resources/_search.html.erb
<div class="form-group">
<%= search_form_for(#search, :id => "resource_search", remote: true) do |f| %>
<%= text_field_tag :location, params[:location], placeholder: "Houston, TX", class: "input-sm form-control" %>
<%= f.submit "Find", class:'btn btn-sm btn-info' %>
<% end %>
</div>
resources/_results.html.erb
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<% #resources.each do |r| %>
<tr>
<td><%= link_to "#{r.name}", r %></td><td><%= r.address %></td><td><%= r.notes %></td>
</tr>
<% end %>
</tbody>
</table>
Again, I can get this working in the index view/controller with js and remote: true but when I implement the search box sitewide in the application layout file I cannot use JS/remote: true.
I'm sure I'm missing something simple in my implementation so if anyone has any advice, please let me know. If my question and/or code examples are not clear let me know and I'll explain in further detail.

Else part is not working in Rails ajax form

I have a Rails ajax form to submit.When user will give the correct data it will search the database and do the operation accordingly.If user is giving the Wrong data it should display user to alert message.But it is not happening like that.
I am explaining my codes below.
home.html.erb
<% if current_admin %>
<p class="flash-message"><%=flash[:notice]%></p>
<div class="col-md-6" style="float:none; margin:auto;">
<%= form_for :sdf ,:url => {:action => "scan_report" },remote: true do |f| %>
<% if params[:receipt_no] %>
<div class="input-group bmargindiv1 col-md-12"> <span class="input-group-addon text-left">Receipt No. Scan :</span>
<%= f.text_field :Receipt_No,:class => "form-control", :value => params[:receipt_no] %><%= f.submit "Scan Report" %>
</div>
<% else %>
<div class="input-group bmargindiv1 col-md-12"> <span class="input-group-addon text-left">Receipt No. Scan :</span>
<%= f.text_field :Receipt_No,:class => "form-control",placeholder:"Receipt No. scan" %><%= f.submit "Scan Report" %>
</div>
<% end %>
<% end %>
<% end %>
controller/homes_contorller.rb
class HomesController < ApplicationController
def home
#sdf=TSdf.new
respond_to do |format|
format.html
format.js
end
end
def scan_report
if #sdf=TSdf.find_by_Receipt_No(params[:sdf][:Receipt_No])
if #sdf && #sdf.HCSY_Status=='YES'
#hcsy=THcsy.find_by_Sdp_Id(#sdf.Sdp_Id)
#hcsy_deatils=THcsyDetails.find_by_HCSY_ID(#hcsy.id)
#woods=THcsyFundTypeMaster.find_by_Fund_Type_Code(1)
#burn=THcsyFundTypeMaster.find_by_Fund_Type_Code(2)
#good=THcsyFundTypeMaster.find_by_Fund_Type_Code(3)
#swd=THcsyFundTypeMaster.find_by_Fund_Type_Code(5)
#photo=THcsyFundTypeMaster.find_by_Fund_Type_Code(6)
end
else
flash[:notice]="Not Found"
end
end
end
In this form its only taking the correct input but if user is trying to give the wrong input the else part is not executing.Please help me to resolve this error and let me to know how can i make this ajax call in below format.
$('form').submit(function() {
var valuesToSubmit = $(this).serialize();
$.ajax({
type: "POST",
url: $(this).attr('action'), //sumbits it to the given url of the form
data: valuesToSubmit,
dataType: "JSON" // you want a difference between normal and ajax-calls, and json is standard
}).success(function(json){
console.log("success", json);
});
return false; // prevents normal behaviour
});
Please help me.I am using Rails version 3.2.19.
Here you send AJAX POST request to scan_report, and if it is successful it should render template scan_report.js.erb, and rendered template will appear in json variable in success callback.
But if params are not valid, the same template is rendered, but all instance variables are missing. And probably empty json is returned or an error appears in log.
Anyway, if you'd like to change flash in remote form, you should put custom code in fail callback. Something like
$("#flash").html('<%= j render flash[:notice] %>');

Partner() expected, got String()

I have a course model and there is a many to many relationship with category, i am using a multi select on my form to get an array of objects, A course also can have a partner and the user can select this from a single select, but when i want to save to the database I call the params then I get a string instead of an object. not to sure how I can solve this
<%= form_for #course do |f| %>
<section class="new_course">
<div class="row collapse">
<div class="medium-5 small-centered column">
<%= f.label :course_title, :class=>"custom-prefix-class" %>
<%= f.text_field :title, :autofocus => true, :class=>"custom-input-class" %>
</div>
</div>
<div class="row collapse">
<div class="medium-5 small-centered column">
<%= f.label :start_date, :class=>"custom-prefix-class" %>
<%= f.text_field :start_date, :class=>"custom-input-class" %>
</div>
</div>
<div class="row">
<div class="medium-5 column with_chosen">
<%= f.collection_select :categories,
Category.all ,:id,:name,
{ include_blank: true},
{ class: 'chosen-select', :multiple=>true, :data => { :placeholder => ' ' }}
%>
</div>
</div>
<div class="row">
<div class="medium-5 column">
<%= f.collection_select :partner,
Partner.all.collect, :id,:name ,
{ include_blank: true },
{ class: 'chosen-select', :multiple=>false, :data => { :placeholder => ' Brand Partner' }}
%>
</div>
</div>
In my controller
def create
#course = Course.new(course_params)
end
if #course.save
render :action=>'new'
end
end
private
def course_params
params.require(:course).permit(:title, :start_date,:duration,:partner,:categories => [])
end
//rails server output
Started POST "/courses" for 127.0.0.1 at 2014-02-07 16:45:28 +0200
Processing by CoursesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"sKhAF2X6VOXTxZC9Pt51RFQfZSKdzXVWji6x4uwg+rI=", "course"=>{"title"=>"Marketing ", "start_date"=>"14-02-2014", "categories"=>["", "1", "2"], "partner"=>"1", "duration"=>"2-weeks"}, "commit"=>"Add new course"}
Completed 500 Internal Server Error in 3ms
ActiveRecord::AssociationTypeMismatch (Partner(#70274068591140) expected, got String(#70274066607160)):
app/controllers/courses_controller.rb:24:in `create'
try this out:-
it seems as that partner is a model and course has_one partner, so you
have to assign partner class object instead of id as string
actually as you can see in in question above value of
params[:course][:partner]
=> "1"
is a string now if you try to do something like #course.partner
= '1' it will raise an error like above, as on left hand side we have parter association and right and side a string.
just do this
def course_params
params.require(:course).permit(:title, :start_date,:duration,:partner,:categories => [])
if params[:course][:partner].present?
params[:course][:partner] = Partner.find params[:course][:partner]
end
end

Resources