I am using the Jquery Steps plugin to create a wizard for the User to create an object. At first, it wasn't saved into the DB and I was told I would have to use AJAX to save the data from the JavaScript to the Rails database. After speaking to a peer we thought it might be an authenticity token issue but that was resolved and it still won't save and create the object in the database.
TLDR Jquery Steps Wizard Form won't save into DB with AJAX.
buildings form view
<%= form_for(building, html: {id: 'form', class: 'wizard-big'}, remote: true, :authentictiy_token => true) do |f| %>
<% if building.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(building.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% building.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<h1>Location Information</h1>
<fieldset>
...
</fieldset>
<h1>General Information</h1>
<fieldset>
<h2>General Information</h2>
...
</fieldset>
<h1>Remarks</h1>
<fieldset>
<h2>Remarks</h2>
...
</fieldset>
<h1>Additional Information</h1>
<fieldset>
<h2>Additional Information</h2>
<%= f.collection_check_boxes :pet_restriction_ids, PetRestriction.all, :id, :options do |b| %>
<%= b.label do %>
<%= b.check_box %>
<%= b.object.options %>
<% end %>
<% end %>
</div>
...
</fieldset>
<h1>Rental Information</h1>
<fieldset>
<h2>Rental Information</h2>
...
</fieldset>
<h1>Office Information</h1>
<fieldset>
<h2>Office Information</h2>
...
</fieldset>
<% end %>
building.js
//= require iCheck/icheck.min.js
//= require steps/jquery.steps.min.js
//= require validate/jquery.validate.min.js
//= require dropzone/dropzone.js
//= require summernote/summernote.min.js
//= require colorpicker/bootstrap-colorpicker.min.js
//= require cropper/cropper.min.js
//= require datapicker/bootstrap-datepicker.js
//= require ionRangeSlider/ion.rangeSlider.min.js
//= require jasny/jasny-bootstrap.min.js
//= require jsKnob/jquery.knob.js
//= require nouslider/jquery.nouislider.min.js
//= require switchery/switchery.js
//= require chosen/chosen.jquery.js
//= require fullcalendar/moment.min.js
//= require clockpicker/clockpicker.js
//= require daterangepicker/daterangepicker.js
//= require select2/select2.full.min.js
//= require touchspin/jquery.bootstrap-touchspin.min.js
//= require bootstrap-markdown/bootstrap-markdown.js
//= require bootstrap-markdown/markdown.js
//= require bootstrap-tagsinput/bootstrap-tagsinput.js
//= require dualListbox/jquery.bootstrap-duallistbox.js
//= require typehead/bootstrap3-typeahead.min.js
//= require codemirror/codemirror.js
//= require codemirror/mode/javascript/javascript.js
// datepicker formating for Ruby
$('.datepicker').datepicker(
{format: 'yy-mm-dd'}
);
// wizard initialization
$(function(){
$("#wizard").steps();
$("#form").steps({
bodyTag: "fieldset",
onStepChanging: function (event, currentIndex, newIndex) {
// Always allow going backward even if the current step contains invalid fields!
if (currentIndex > newIndex) {
return true;
}
// Forbid suppressing "Warning" step if the user is to young
if (newIndex === 3 && Number($("#age").val()) < 18) {
return false;
}
var form = $(this);
// Clean up if user went backward before
if (currentIndex < newIndex) {
// To remove error styles
$(".body:eq(" + newIndex + ") label.error", form).remove();
$(".body:eq(" + newIndex + ") .error", form).removeClass("error");
}
// Disable validation on fields that are disabled or hidden.
form.validate().settings.ignore = ":disabled,:hidden";
// Start validation; Prevent going forward if false
return form.valid();
},
onStepChanged: function (event, currentIndex, priorIndex) {
// Suppress (skip) "Warning" step if the user is old enough.
if (currentIndex === 2 && Number($("#age").val()) >= 18) {
$(this).steps("next");
}
// Suppress (skip) "Warning" step if the user is old enough and wants to the previous step.
if (currentIndex === 2 && priorIndex === 3) {
$(this).steps("previous");
}
},
onFinishing: function (event, currentIndex) {
var form = $(this);
// Disable validation on fields that are disabled.
// At this point it's recommended to do an overall check (mean ignoring only disabled fields)
form.validate().settings.ignore = ":disabled";
// Start validation; Prevent form submission if false
return form.valid();
},
onFinished: function (event, currentIndex) {
var form = $(this);
// Submit form input
form.submit();
}
}).validate({
errorPlacement: function (error, element) {
element.before(error);
},
rules: {
confirm: {
equalTo: "#password"
}
}
});
});
ajax
// Ajax call to submit data to DB
$("#finish").click(function() {
var submitData;
submitData = $.ajax({
type: "POST",
url: "buildings/new",
data: $([
'building_id',
'unit_no',
'floor_plan',
'num_fbaths',
'num_hbaths',
'advertising',
'move_in_special',
'commission',
'created_at',
'rent_price',
'rent_per_period',
'for_sale',
'beds',
'fbaths',
'hbaths',
'unit_floor_location',
'type_of_property',
'style',
'sqft',
'balcony',
'liv_area',
'efficiency',
'faces',
'additional_parking_info',
'furnished_information',
'available_date',
'view',
'floor',
'dinning',
'listing_type',
'list_date',
'expiration_date',
'convert_bed'
].join(', ')).serialize(),
success:
dataType:
})
post(url, function(data, textStatus, submitData) {
return console.log('i guess it worked');
});
return submitData.fail(function() {
return console.log(submitData.responseText);
});
});
building controller
class BuildingsController < ApplicationController
before_action :set_building, only: [:show, :edit, :update, :destroy]
# GET /buildings
# GET /buildings.json
def index
@buildings = Building.where(user_id: current_user)
end
# GET /buildings/1
# GET /buildings/1.json
def show
end
# GET /buildings/new
def new
@building = Building.new
end
# GET /buildings/1/edit
def edit
end
# POST /buildings
# POST /buildings.json
def create
@building = Building.new(building_params)
respond_to do |format|
if @building.save
session[:building_id] = @building.id
redirect_to listing_wizards_path
format.html { redirect_to @building, notice: 'Building was successfully created.' }
format.json { render :show, status: :created, location: @building }
else
format.html { render :new }
format.json { render json: @building.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /buildings/1
# PATCH/PUT /buildings/1.json
def update
respond_to do |format|
if @building.update(building_params)
format.html { redirect_to @building, notice: 'Building was successfully updated.' }
format.json { render :show, status: :ok, location: @building }
else
format.html { render :edit }
format.json { render json: @building.errors, status: :unprocessable_entity }
end
end
end
# DELETE /buildings/1
# DELETE /buildings/1.json
def destroy
@building.destroy
respond_to do |format|
format.html { redirect_to buildings_url, notice: 'Building was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_building
@building = Building.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def building_params
params.require(:building).permit(:list_type, :county, :area, :city, :folio, :street, :compass_point, :street_name, :state, :zip, :zip4, :unit, :legal, :zoning, :geographical, :municip_code, :township, :section, :subdivision, :parcel, :map_coordinates, :elementary_school, :middle_school, :senior_high_school, :subdivision_name, :development_name, :model_name_in_mls, :user_id, additional_room_ids: [], amenity_ids: [], approval_ids: [], construction_ids: [], cooling_description_ids: [], design_ids: [], dining_area_ids: [], equipment_ids: [], exterior_feature_ids: [], floor_ids: [], heat_ids: [], interior_feature_ids: [], leasing_term_ids: [], lot_description_ids: [], misc_ids: [], parking_restriction_ids: [], pet_restriction_ids: [], pool_description_ids: [], rental_dep_incl_ids: [], rental_pay_inc_ids: [], rental_restriction_ids: [], security_ids: [], showing_instruction_ids: [], water_access_ids: [], waterfront_desc_ids: [], window_treatment_ids: [])
end
end