How to make ajax call and show error messages - ruby-on-rails

Two of the action of My registration controller is new and create.
def new
#regist = Regist.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #regist }
end
end
def create
#regist = Regist.new(regist_params)
respond_to do |format|
if #regist.save
format.html { redirect_to #regist, notice: 'Regist was successfully created.' }
format.json { render json: #regist, status: :created, location: #regist }
else
format.html { render action: "new" }
format.json { render json: #regist.errors, status: :unprocessable_entity }
end
end
end
And the new form contain following code.
<%= form_for(#regist) do |f| %>
<% if #regist.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#regist.errors.count, "error") %> prohibited this regist from being saved:</h2>
<ul>
<% #regist.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.collection_select :student_id, Student.all, :id, :name %><br />
</div>
<div class="field">
<%= f.collection_select :semester_id, Semester.all, :id, :name %><br />
</div>
<div class="field">
<% for subject in Subject.find(:all) %>
<%= check_box_tag "regist[subject_ids][]", subject.id %>
<%= subject.name %><br>
<% end %>
</div>
<div class="field">
<%= f.label :date_of_birth %><br />
<%= f.text_field :date_of_birth %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Now, when someone click on submit button I want to make ajax call using remote true if there are validation errors and show the errors without reloading the page. And if there are no validation errors I want the user to be redirected to show page. How can I do this?

First of all you should add a remote: true to your existing form to allow remote action.
TODO this just add on the first line of your form the remote: true,
<%= form_for(#regist, remote: true) do |f| %>
the rest leave it as it is. Then you need to make your controller to respond to remote calls, therefore you need to alter the responds_to block of create action:
respond_to do |format|
if #regist.save
format.html { redirect_to #regist, notice: 'Regist was successfully created.' }
format.json { render json: #regist, status: :created, location: #regist }
format.js { render js: "window.location.href='"+regists_path+"'"}
else
format.html { render action: "new" }
format.json { render json: #regist.errors, status: :unprocessable_entity }
format.js
end
end
The last step you have to do is to add a file to your app/views/regists/ directory
where you should add a create.js.erb file:
<% if #regist.errors.any? %>
$('#new_regist').effect('highlight', { color: '#FF0000'}, 1000); // for highlighting
// or add here whatever jquery response you want to have to your views.
<% end %>
You will get your validation errors displayed like before above the form.
You have to add the redirect to your controller to the desirable action of your choice. I have added for you a window.location.href as a response to the regists_path.

Related

Not able to save form data into database in rails

I have created a scaffold name project and created another scaffold named
stage. There is one to many associate between project and stage. like each project will have multiple stages. I am able to render stage form but i am not able to save data into stage table of the database.
this error i get on saving stage form
stage form.html.erb
<%= form_with(model: stage, url: [#project, stage], local: true) do |form| %>
<% if #stage.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(stage.errors.count, "error") %> prohibited this stage from being saved:</h2>
<ul>
<% stage.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="row select-date-wrapper">
<div class="field columns large-6">
<%= form.label :stage %>
<%= form.text_field :stage %>
</div>
<div class="field columns large-3">
<%= form.label :planned_start_date %>
<%= form.date_select :planned_start_date, class: 'select-date' %>
</div>
<div class="actions">
<%= form.submit 'Create', :class=>"button primary small" %>
</div>
<% end %>
stage_controller.rb
def index
#stages = Stage.all
end
def new
#stage = Stage.new
#project = Project.find(params[:project_id])
end
def create
#project = Project.find(params[:project_id])
#stage = #project.stages.build(stage_params)
respond_to do |format|
if #stage.save
format.html { redirect_to #stage, notice: 'Stage was successfully created.' }
format.json { render :show, status: :created, location: #stage }
else
format.html { render :new }
format.json { render json: #stage.errors, status: :unprocessable_entity }
end
end
end
model project.rb
has_many :stages
model stage.rb
#belongs_to :project
has_many :tasks
routes.rb
resources :projects do
resources :stages
end
Have you tried this?
if #stage.save
format.html { redirect_to project_stage_path(#project, #stage), notice: 'Stage was successfully created.' }
format.json { render :show, status: :created, location: #stage }
else
format.html { render :new }
format.json { render json: #stage.errors, status: :unprocessable_entity }
end
please change url: [#project, stage] to url: stages_path
always try to make controller name plural. stages_controller

Why Ajax call is responding after a page refresh in rails 4?

Suppose I have defined my create action like this:
def create
#appointment = Appointment.find(params[:appointment_id])
#note = #appointment.notes.new(notes_params)
#note.user_id = current_user.id
respond_to do |format|
if #note.save
format.html { redirect_to appointment_path(#appointment), notice: "Saved successfully" }
format.js
else
format.html { render 'new', notice: "Try again" }
format.js
end
end
end
My create.js.erb is like this:
$("#note_field").html("<%= j render partial: 'note', locals: {note: #note} %>");
Here is my form:
<%= form_for([#appointment, #appointment.notes.build({user: current_user})], remote: true) do |f| %>
<div>
<% if #note && #note.errors.any? %>
<% #note.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
</div>
<div class="field">
<%= f.label :Description %><br>
<%= f.text_area :description, required: true %>
</div>
<div>
<%= f.submit class: "note-button" %>
</div>
<% end %>
Here, note is partial form. How to make it work without a page refresh?

presence validation causes "undefined method `map' for nil:NilClass" error

I want people to define a course name before writing a spotlight. I did this by adding following code to the spotlight model
class Spotlight < ActiveRecord::Base
validates :name, presence: true
end
Before adding the validation I could write spotlights without any name. If I try that now I get following error message:
undefined method `map' for nil:NilClass
Extracted source (around line #29):
</div>
<div class="field">
<%= f.label :name, "Opleiding" %><br>
<%= f.collection_select(:name, #colli, :name, :name, {prompt: 'Selecteer een opleiding'}, {id: 'collis_select'}) %>
</div>
<div class="field">
<%= f.label :teaser %><br>
What is going on here? The collection select is the base for an ajax call I do to fill up other fields.
View
<%= form_for(#spotlight) do |f| %>
<% if #spotlight.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#spotlight.errors.count, "error") %> prohibited this spotlight from being saved:</h2>
<ul>
<% #spotlight.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :spotlight, "In de kijker" %><br>
<%= f.check_box :spotlight %>
</div>
<div class="field">
<%= f.label :start, "Start in de kijker" %><br>
<%= f.datetime_select :start %>
</div>
<div class="field">
ruby-on-rails
<%= f.label :stop, "Stop in de kijker" %><br>
<%= f.datetime_select :stop %>
</div>
<div class="field">
<%= f.label :name, "Opleiding" %><br>
<%= f.collection_select(:name, #colli, :name, :name, {prompt: 'Selecteer een opleiding'}, {id: 'collis_select'}) %>
</div>
<div class="field">
<%= f.label :teaser %><br>
<%= f.text_area :teaser, size: "85x10", id: 'teasers_select' %>
</div>
<div class="field">
<%= f.label :coursedate, "Startdatum opleiding" %><br>
<%= f.datetime_select :coursedate, id: 'startdate_select' %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<script>
$(document).ready(function() {
$('#collis_select').change(function() {
$.ajax({
url: "<%= update_teasers_path %>",
data: {
name : $('#collis_select').val()
},
dataType: "script"
});
});
});
</script>
Update teaser view
$('#teasers_select').val("<%= escape_javascript(#teaser) %>");
Controller
class SpotlightsController < ApplicationController
before_action :set_spotlight, only: [:show, :edit, :update, :destroy]
before_action :load_colli, only: [:new, :edit]
def index
#spotlights = Spotlight.all.order('spotlight DESC, start, stop')
end
def show
end
def new
#spotlight = Spotlight.new
end
def edit
end
def create
#spotlight = Spotlight.new(spotlight_params)
respond_to do |format|
if #spotlight.save
format.html { redirect_to #spotlight, notice: 'Spotlight was successfully created.' }
format.json { render action: 'show', status: :created, location: #spotlight }
else
format.html { render action: 'new' }
format.json { render json: #spotlight.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #spotlight.update(spotlight_params)
format.html { redirect_to #spotlight, notice: 'Spotlight was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #spotlight.errors, status: :unprocessable_entity }
end
end
end
def update_teasers
# updates artists and songs based on genre selected
colli = Colli.where(name: params[:name])
# map to name and id for use in our options_for_select
#teaser = colli.first.teaser
end
def destroy
#spotlight.destroy
respond_to do |format|
format.html { redirect_to spotlights_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_spotlight
#spotlight = Spotlight.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def spotlight_params
params.require(:spotlight).permit(:spotlight, :start, :stop, :name, :teaser, :coursedate)
end
def load_colli
#colli = Colli.select(:name).distinct.order('name')
end
end
Can somebody explain what seems to be the problem? What is the "map" function the error is referring to?
It looks like your #colli object is nil.
<%= f.collection_select(:name, #colli, :name, :name, {prompt: 'Selecteer een opleiding'}, {id: 'collis_select'}) %>
This has nothing to do with the presence validation. Make sure the collection_select method is receiving a #colli instance variable. Right now it's receiving nil.
The map function is an instance method in the class Array. It receives a block, iterates over an array, and returns a new array with elements returned from the block. You can't call map on nil; you will get the error you are seeing above.
You can check if #colli is nil by raising it:
def load_colli
#colli = Colli.select(:name).distinct.order('name')
raise #colli.to_s
end
If you change the update_teasers function to:
def update_teasers
# updates artists and songs based on genre selected
#colli = Colli.where(name: params[:name])
# map to name and id for use in our options_for_select
#teaser = #colli.first.teaser
end
that should fix the issue. This isn't an issue with the presence validation.
EDIT:Sorry, that didn't work. Next I would try to set the #colli variable in the create function as follows. That way the variable is still set when it renders the new action upon a failed save.
def create
#spotlight = Spotlight.new(spotlight_params)
#colli = Colli.where(name: params[:name])
respond_to do |format|
if #spotlight.save
format.html { redirect_to #spotlight, notice: 'Spotlight was successfully created.' }
format.json { render action: 'show', status: :created, location: #spotlight }
else
format.html { render action: 'new' }
format.json { render json: #spotlight.errors, status: :unprocessable_entity }
end
end
end

view incorrectly reloads after uniqueness validation error

After you try to submit a new guideline and you see an error message on the form (due to the guidelines correctly failing validation)...the list of #specialties does not reload correctly (ie. it just says yes/no rather than the proper list you could see before you submitted with an error). I can't work out which part is wrong here...
VIEWS _form.html.erb
<%= simple_form_for(#guideline, html: {class: "form-horizontal"}) do |f| %>
<% if #guideline.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#guideline.errors.count, "error") %> prohibited this guideline from being saved:</h2>
<ul>
<% #guideline.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.input :title, label: 'Title (e.g. Asthma for under 12 months)' %>
<%= f.input :specialty, as: :select, collection: #specialties %>
<%= f.input :hospital %>
<%= f.input :content, as: :string, label: 'Link' %>
<div class="form-actions">
<%= f.button :submit, :class => "btn btn-info btn-large" %>
</div>
<% end %>
guidelines_controller.rb
def new
#guideline = Guideline.new
#specialties = Guideline.order(:specialty).uniq.pluck(:specialty)
respond_to do |format|
format.html # new.html.erb
format.json { render json: #guideline }
end
end
def create
#guideline = current_user.guidelines.new(params[:guideline])
respond_to do |format|
if #guideline.save
format.html { redirect_to #guideline, notice: 'Guideline was successfully created.' }
format.json { render json: #guideline, status: :created, location: #guideline }
else
#specialties = Guideline.order(:specialty).uniq.pluck(:specialty)
format.html { render action: "new" }
format.json { render json: #guideline.errors, status: :unprocessable_entity }
end
end
end
this is a common error. in your create action you should declare #specialties if the validation fails since that is needed in the new template.
def create
#guideline = Guideline.new params[:guideline]
if #guideline.save
else
# you need to declare #specialties here since it is needed in the new template
# which you want to render
#specialties = Specialty.all
render :new
end
end

Rails 3.2 - Nested Resource Passing ID

Okay so my associations are:
Outlet -> has_many :monitorings
Monitoring -> belongs_to :outlet
My Routes:
resources :outlets do
resources :monitorings
end
View:
<%= link_to new_outlet_monitoring_path(#outlet) %>
When I click the link, the logs show that the outlet_id is passed as a parameter to the new page correctly.
But when saving the monitoring record, the outlet_id becomes nil.
Any help?
UPDATE:
# views/monitorings/_form.html.erb
<%= form_for(#monitoring) do |f| %>
<h2>Type of Monitoring</h2>
<fieldset data-role="controlgroup" >
<div class="radio-group">
<%= f.radio_button :mtype, "Full" %><%= f.label :mtype, "Full", value: "Full" %>
<%= f.radio_button :mtype, "Partial" %><%= f.label :mtype, "Partial", value: "Partial" %>
<%= f.radio_button :mtype, "None" %><%= f.label :mtype, "None", value: "None" %>
</div>
</fieldset>
<hr>
<%= f.submit "Next Step" %>
<% end %>
And the controller:
# controllers/monitoring_controller.rb
def new
#monitoring = Monitoring.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #monitoring }
end
end
def create
#monitoring = Monitoring.new(params[:monitoring])
respond_to do |format|
if #monitoring.save
format.html { redirect_to #monitoring, notice: 'Monitoring was successfully created.' }
format.json { render json: #monitoring, status: :created, location: #monitoring }
else
format.html { render action: "new" }
format.json { render json: #monitoring.errors, status: :unprocessable_entity }
end
end
end
This is most likely an issue with the way you are creating the new monitoring record. Can we see your form and your create controller action?

Resources