Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
Ok, so I'm trying to update an old app by rebuilding it in a seperate Rails 5 app that points to the same database (well not really the --same-- but a clone of that DB)
I've recently tried using a nested form field approach to solve my "create new record" problem for this particular form but got jammed up for some reason....
soooooo...
I've gone back and tried a different approach by building a new event in the controller new action called "add_shift" and assigning each field individually. Then in my "create" using a method called create_shift.
NOTE: this was the technique used in the old app as well so I'm trying to port it over to the newer app...here is the error I am getting
the error
Started POST "/assignments" for blah-my-ip at 2021-11-08 06:48:49 -0800
Cannot render console from blah-my-ip! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
ActiveRecord::SchemaMigration Load (0.5ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by AssignmentsController#create as JS
Parameters: {"utf8"=>"✓", "volunteer_task_type_id"=>"41", "roster_id"=>"7", "program_id"=>"9", "set_description"=>["fonso nov8 test"], "set_date"=>["2021-01-05"], "assignment"=>{"start_time(1i)"=>"2021", "start_time(2i)"=>"11", "start_time(3i)"=>"8", "start_time(4i)"=>"08", "start_time(5i)"=>"00", "end_time(1i)"=>"2021", "end_time(2i)"=>"11", "end_time(3i)"=>"8", "end_time(4i)"=>"09", "end_time(5i)"=>"00", "notes"=>"Nov888", "contact_id"=>"166574", "closed"=>"0", "lock_version"=>"0"}, "contact_element_prefix"=>"contact", "commit"=>"Submit"}
VolunteerTaskType Load (0.2ms) SELECT "volunteer_task_types".* FROM "volunteer_task_types" WHERE "volunteer_task_types"."id" = $1 LIMIT $2 [["id", 41], ["LIMIT", 1]]
Roster Load (0.1ms) SELECT "rosters".* FROM "rosters" WHERE "rosters"."id" = $1 LIMIT $2 [["id", 7], ["LIMIT", 1]]
Program Load (0.1ms) SELECT "programs".* FROM "programs" WHERE "programs"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]]
(0.1ms) BEGIN
(0.1ms) ROLLBACK
Rendering assignments/new.html.erb within layouts/application
Rendered assignments/new.html.erb within layouts/application (3.6ms)
Rendered layouts/_messages.html.erb (0.6ms)
Completed 422 Unprocessable Entity in 1202ms (Views: 269.7ms | ActiveRecord: 11.5ms)
....below are my controller, models and views related to this form...
class AssignmentsController < ApplicationController
before_action :set_assignment, only: [:show, :edit, :update, :destroy]
skip_before_action :verify_authenticity_token #TODO refactor this line to be very specific
# GET /assignments or /assignments.json
def index
#assignments = Assignment.date_range(params[:start]..params[:end])
end
# GET /assignments/1 or /assignments/1.json
def show
end
# GET /assignments/new
def new
add_shift
# #assignment.volunteer_shift.build
#my_url = {:action => "create", :id => params[:id]}
end
# GET /assignments/1/edit
def edit
end
# POST /assignments or /assignments.json
def create
# #assignment = Assignment.new(assignment_params)
create_shift
respond_to do |format|
if #assignment.save
format.html { redirect_to #assignment, notice: "Assignment was successfully created." }
format.json { render :show, status: :created, location: #assignment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #assignment.errors, status: :unprocessable_entity }
end
end
end
def add_shift # FIXME: evil brought over from old app
ve = nil
if !params["id"].blank?
ve = VolunteerEvent.find_by_id(params["id"])
else
ve = VolunteerEvent.new
end
vs = ve.volunteer_shifts.new
vs.program = Program.find_by_name("intern")
# vs.slot_count = 1
vs.volunteer_event_id = ve.id if ve.id
vs.volunteer_event = ve
a = vs.assignments.new
a.volunteer_shift = vs
vs.stuck_to_assignment = true
vs.not_numbered = true
#assignments = vs.assignments = [a]
#referer = request.env["HTTP_REFERER"]
#my_url = {:action => "create_shift", :id => params[:id]}
#assignment = a
# binding.pry
# render :partial => 'assignments/new'
# render :partial => 'assignments/edit' #<--original
end
def create_shift # FIXME: evil brought over from original code base
# #fonso = #assignment.inspect
ve = nil
# Fixme: building volunteer shifts variable "vs" and associating with assignment
if !params["id"].blank?
ve = VolunteerEvent.find(params["id"])
else
if params["roster_id"].blank? || params["set_date"].blank?
ve = VolunteerEvent.new # won't save
else
ve = Roster.find_by_id(params["roster_id"]).vol_event_for_date(params["set_date"])
end
end
vs = ve.volunteer_shifts.new
vs.stuck_to_assignment = true
vs.not_numbered = true
#fixme: volunteer shifts variable "vs" and association with assignment end
# FIXME: vs.attributes=(params["assignment"]["volunteer_shift_attributes"]) # original needs to be rebuilt 4 this system
h0 = {"volunteer_task_type_id" => params["volunteer_task_type_id"]}
h1 = {"roster_id" => params["roster_id"]}
h2 = {"program_id" => params["program_id"]}
h3 = {"set_description" => params["set_description"]}
hash_arr = [h0,h1,h2,h3]
volunteer_shift_attributes = hash_arr.reduce { |acc, h| (acc || {}).merge h }
vs.attributes = volunteer_shift_attributes
#fixme: vs.attributes fix end
#FIXME: building variable - #assignments END
assignment = vs.assignments.new
vs = assignment.volunteer_shift
assignment.attributes = (assignment_params)
#assignments = [assignment]
#fixme: building variable - #assignments END
#FIXME: wtf is it and why is it?
vs.assignments = [assignment]
vs.set_values_if_stuck #fixme: <---- drill into this one
vs.assignments = []
binding.pry
#success = assignment.valid? && vs.save #fixme: <--------what was the valid? error here?
#assignment = assignment #fixme: <-----------------------#assignment is finally built here
# fixme: the above lines are merging params from one into the other in the old app.
# fixme: to create the new volunteer_shift.
if #success
vs = vs.reload
#assignment = a = vs.assignments.new
a.volunteer_shift = vs
# a.volunteer_shift_id = vs.id
a.attributes = (params["assignment"])
#assignments = vs.assignments = [a]
if !#success
vs.destroy
end
end
end
def update # ported over from old app
unless params[:assignment]
redirect_to :action => "index"
return
end
#my_url = {:action => "update", :id => params[:id]}
last_id = nil
begin
#assignments = params[:id].split(",").map{|x| last_id = x; Assignment.find(x)}
rescue ActiveRecord::RecordNotFound
flash[:jsalert] = "The assignment (##{last_id.to_i.inspect}) seems to have disappeared or never existed. It is possible somebody else has modified or deleted it."
rt = params[:assignment].delete(:redirect_to)
redirect_skedj(rt, "")
return
end
lv = params["lock_versions"]
ac = params["assigned_contacts"] || {}
#assigned_contacts = []
#replaced_contacts = []
ret = true
#assignments.each do |as|
as.lock_version = lv[as.id.to_s]
if as.lock_version_changed?
as.errors.add("lock_version", "is stale for this assignment, which means it has been edited by somebody else since you opened it, please try again")
ret = false
end
if as.contact_id && as.contact_id.to_s != params[:assignment][:contact_id].to_s
#assigned_contacts << as.contact
unless ac[as.contact_id.to_s] && ac[as.contact_id.to_s] == "replace"
as.errors.add("contact_id", "has been changed, please confirm below that the volunteer who is already assigned to the shift should be removed")
ret = false
else
#replaced_contacts << as.contact_id
end
end
end
rt = params[:assignment].delete(:redirect_to)
js_alert = nil
if ! ret
#assignment = Assignment.new
#assignment.volunteer_shift = #assignments.first.volunteer_shift
#assignment.attributes=(params[:assignment]) # .. ? .delete("volunteer_shift_attributes")
end
#assignments.each{|x|
if ret
#assignment = x
bc = x.contact_id
ret = !!(x.update_attributes(params[:assignment]))
if bc != x.contact_id and x.first_time_in_area?
alert = "#{x.contact.display_name} (##{x.contact_id}) has never logged hours for the #{x.volunteer_shift.volunteer_task_type.description} task type. Please remind the volunteer of the requirements for this area."
if x.volunteer_shift.volunteer_event and x.volunteer_shift.volunteer_event.notes and x.volunteer_shift.volunteer_event.notes.length > 0
alert += "\n\nSome suggested notes saved in the database for this event are:\n" + x.volunteer_shift.volunteer_event.notes
end
js_alert = alert
end
end
}
if ret && #assignment.contact and not #assignment.contact.is_old_enough?
msg = "This volunteer is not yet #{Default['minimum_volunteer_age']} years old (based on their saved birthday: #{#assignment.contact.birthday.to_s}).\nPlease remind the volunteer that they must have an adult with them to volunteer."
if js_alert == nil
js_alert = msg
else
js_alert = msg + "\n\n" + js_alert
end
end
flash[:jsalert] = js_alert if js_alert
if ret
flash[:notice] = 'Assignment was successfully updated.'
redirect_skedj(rt, #assignment.volunteer_shift.date_anchor)
else
#referer = rt
render :action => "edit"
end
end
# DELETE /assignments/1 or /assignments/1.json
def destroy
#assignment.destroy
# NOTE: comment original out 4 now
# respond_to do |format|
# format.html { redirect_to assignments_url, notice: "Assignment was successfully destroyed." }
# format.json { head :no_content }
# end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_assignment
#assignment = Assignment.find(params[:id])
end
# Only allow a list of trusted parameters through.
def assignment_params
#fixme: ,volunteer_shift_attributes: [:???, :???, :???] <--- insert this below?
params.require(:assignment).permit(:title, :date_range, :set_date, :date, :volunteer_shift_id, :contact_id, :start_time, :end_time, :start, :end, :attendance_type_id, :notes, :call_status_type_id, :closed, :lock_version, :color, :description)
# params.require(:assignment).permit(:title, :redirect_to, :set_date, :date_range, :contact_id, :start_time, :end_time, :start, :end, :attendance_type_id, :notes, :call_status_type_id, :closed, :lock_version, :color, volunteer_shift_attributes: [:volunteer_task_type_id,:roster_id,:program_id,:set_description,:set_date,:id,:destroy])
end
end
Model assignment
class Assignment < ApplicationRecord
# attr_accessor :volunteer_event ,:contact_id #why is this volunteer_event and not volunteer_shift???
belongs_to :volunteer_shift
has_one :volunteer_task_type, :through => :volunteer_shift, :source => :volunteer_task_type
belongs_to :contact ,optional: true
validates_presence_of :volunteer_shift #belongs_to takes care of this now
validates_associated :volunteer_shift
belongs_to :attendance_type
belongs_to :call_status_type
validates_presence_of :set_date, :if => :volshift_stuck #belongs_to takes care of this now??
accepts_nested_attributes_for :volunteer_shift, allow_destroy: true
delegate :set_date, :set_date=, :to => :volunteer_shift
delegate :set_description, :set_description=, :to => :volunteer_shift
has_one :contact_volunteer_task_type_count, lambda{||
{:conditions => 'contact_volunteer_task_type_counts.contact_id = #{defined?(attributes) ? contact_id : "assignments.contact_id"}', :through => :volunteer_shift, :source => :contact_volunteer_task_type_counts}
}
scope :date_range, lambda { |range|
joins(volunteer_shift: :volunteer_event)
.where(volunteer_shifts: { volunteer_events: { date: range } })
}
scope :is_after_today, lambda {||
{ :conditions => ['(SELECT date FROM volunteer_events WHERE id = (SELECT volunteer_event_id FROM volunteer_shifts WHERE id = assignments.volunteer_shift_id)) > ?', Date.today] }
}
scope :on_or_after_today, lambda {||
{ :conditions => ['(SELECT date FROM volunteer_events WHERE id = (SELECT volunteer_event_id FROM volunteer_shifts WHERE id = assignments.volunteer_shift_id)) >= ?', Date.today] }
}
scope :not_cancelled, -> { where('(attendance_type_id IS NULL OR attendance_type_id NOT IN (SELECT id FROM attendance_types WHERE cancelled = \'t\'))')}
scope :roster_is_limited_by_program, -> {where("roster_id IN (SELECT id FROM rosters WHERE limit_shift_signup_by_program = 't')").joins(:volunteer_shift)}
def real_programs
return [] unless self.volunteer_shift&.roster
return [] unless self.volunteer_shift.roster.limit_shift_signup_by_program
self.volunteer_shift.roster.skeds.select{|x| x.category_type == "Program"}.map{|x| x.name}
end
attr_accessor :attendance_type_id
# TODO: find all time_range_s methods and either pull out to DRY or give unique names
def time_range_s
return "" unless start_time and end_time
(start_time.strftime("%I:%M") + ' - ' + end_time.strftime("%I:%M")).gsub( ':00', '' ).gsub( ' 0', ' ').gsub( ' - ', '-' ).gsub(/^0/, "")
end
def description
return unless volunteer_shift
self.volunteer_shift.volunteer_event.date.strftime("%D") + " " + self.time_range_s + " " + self.slot_type_desc
end
def roster_title
return unless volunteer_shift
self.volunteer_shift.roster.name
end
def date
return unless volunteer_shift
volunteer_shift.date
end
#full calendar uses this method name....see the assignment.json.jbuilder
def event_date
return unless volunteer_shift
self.date
end
def contact_display
if self.closed
"(closed)"
elsif contact_id.nil?
return "(available)"
else
self.contact.display_name + "(#{self.voltask_count})"
end
end
before_validation :set_values_if_stuck
def set_values_if_stuck
return unless (volshift_stuck || volunteer_shift)
volunteer_shift.set_values_if_stuck(self)
end
after_destroy { |record| if record.volunteer_shift&.stuck_to_assignment; record.volunteer_shift.destroy; else VolunteerShift.find_by_id(record.volunteer_shift_id).fill_in_available; end}
after_save {|record| if record.volunteer_shift&.stuck_to_assignment; record.volunteer_shift.save; end}
after_save { |record| VolunteerShift.find_by_id(record.volunteer_shift_id).fill_in_available }
def volunteer_shift_attributes=(attrs)
return unless volunteer_shift
self.volunteer_shift.attributes=(attrs) # just pass it up
end
def volshift_stuck
return unless volunteer_shift
self.volunteer_shift&.stuck_to_assignment
end
#for fullcalendar
def all_day_event?
self.start_time == self.start_time.midnight && self.end_time == self.end_time.midnight ? true : false
end
end
model volunteer_shift
class VolunteerShift < ApplicationRecord
validates_presence_of :roster_id
validates_presence_of :end_time
validates_presence_of :start_time
has_many :assignments
belongs_to :volunteer_default_shift
belongs_to :volunteer_task_type
belongs_to :roster
belongs_to :volunteer_event
belongs_to :program
has_many :contact_volunteer_task_type_counts, :primary_key => 'volunteer_task_type_id', :foreign_key => 'volunteer_task_type_id' #:through => :volunteer_task_type
def validate
errors.add("end_time", "is before the start time") unless self.start_time && self.end_time && self.start_time < self.end_time
end
...
def set_description
self.description
end
def set_description=(desc)
self.description=(desc)
end
def set_date_set
#set_date_set
end
def set_date=(val)
#set_date_set = true
#set_date = val
end
def set_date
#set_date_set ? #set_date : self.volunteer_event.date
end
def set_values_if_stuck(assn_in = nil)
return unless self.stuck_to_assignment #<---it's a boolean in the database
assn = assn_in || self.assignments.first
return unless assn
self.start_time = assn.start_time
self.end_time = assn.end_time
return unless self.volunteer_event_id.nil? or self.volunteer_event.description.match(/^Roster #/)
return unless set_date_set <----SOMETHING BREAKS HERE on these two lines
roster = Roster.find_by_id(self.roster_id)
if roster and !(set_date == nil || set_date == "")
ve = roster.vol_event_for_date(set_date)
ve.save! if ve.id.nil?
self.volunteer_event = ve
self.volunteer_event_id = ve.id
else
if self.volunteer_event.nil?
self.volunteer_event = VolunteerEvent.new
end
end
end
def shift_display
time_range_s + ((!(self.description.nil? or self.description.blank?)) ? (": " + self.description) : "")
end
def time_range_s
return unless self.read_attribute(:start_time) and self.read_attribute(:end_time)
(self.my_start_time("%I:%M") + ' - ' + self.my_end_time("%I:%M")).gsub( ':00', '' ).gsub( ' 0', ' ').gsub( ' - ', '-' ).gsub(/^0/, "")
end
def my_start_time(format = "%H:%M")
read_attribute(:start_time).strftime(format)
end
def self._parse_time(time)
Time.mktime(2000, 01, 01, *time.split(":").map(&:to_i))
end
def my_start_time=(str)
write_attribute(:start_time, VolunteerShift._parse_time(str))
end
def my_end_time(format = "%H:%M")
read_attribute(:end_time).strftime(format)
end
def my_end_time=(str)
write_attribute(:end_time, VolunteerShift._parse_time(str))
end
def self.range_math(*ranges)
... # have to edit this post down
end
def fill_in_available
return if self.stuck_to_assignment #<-- it's a boolean in the database
Thread.current['volskedj_fillin_processing'] ||= []
if Thread.current['volskedj_fillin_processing'].include?(self.id)
return
end
begin
Thread.current['volskedj_fillin_processing'].push(self.id)
Assignment.where(volunteer_shift_id: self.id).select{|x| x.contact_id.nil? and !x.closed}.each{|x| x.destroy}
inputs = [[(self.read_attribute(:start_time)), (self.read_attribute(:end_time))]]
Assignment.where(volunteer_shift_id: self.id).select{|x| !x.cancelled?}.each{|x|
inputs.push([(x.start_time), (x.end_time)])
}
results = self.class.range_math(*inputs)
results.each{|x|
a = Assignment.new
a.volunteer_shift_id, a.start_time, a.end_time = self.id, x[0], x[1]
a.volunteer_shift = self
a.closed = self.volunteer_event.nowalkins
a.save!
}
ensure
Thread.current['volskedj_fillin_processing'].delete(self.id)
end
end
after_save :fill_in_available
def date
self.volunteer_event.date
end
def date_display
self.date.strftime('%A, %B %d, %Y').gsub( ' 0', ' ' )
end
def date_anchor
self.date ? self.date.strftime('%Y%m%d') : ''
end
def time_shift(val)
self.start_time += val
self.end_time += val
end
def left_method_name
[self.volunteer_task_type_id.nil? ? self.volunteer_event.description : self.volunteer_task_type.description, self.slot_number].select{|x| !x.nil?}.join(", ")
end
def left_unique_value
left_method_name
end
def description_and_slot
((self.volunteer_task_type_id || -1) * 1000) + (self.not_numbered ? 0 : self.slot_number)
end
def weekday
Weekday.find_by_id(self.date.strftime("%w"))
end
end
And the views
_new.html.erb <----- NOTE this name...this is the modal
<div class="modal fade" id="add_event">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<div class="col-sm-12 left ">
<h4 class="modal-title">Add New Assignment - _new.html.erb</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
</div>
<%=#my_url %>
<%#= render 'assignments/form', assignment: #assignment %>
</div>
</div>
</div>
_form.html.erb
<!--This is NEW action form-->
<%= form_for #assignment, :url => #my_url, remote: true do |f| %>
<!-- #FIXME need a fields_for 4 the volunteer_event-->
<div class="">
<div class="modal-body d-flex">
<div class="col-sm-8 border-right">
<section id="location-date-time-notes" class="flex">
<% if #assignment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#assignment.errors.count, "error") %> prohibited this assignment from being saved:</h2>
<ul>
<% #assignment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<!--VOLUNTEER SHIFT-->
<!--TODO: make this a partial under field_for-->
<%= f.fields_for :volunteer_event do |builder| %>
<%= render 'assignments/volunteer_shift_fields', vs: builder %>
<% end %>
<!--TODO: Volunteer Shift end -->
<div id="time-row" class="d-flex flex-row">
<label for="assignment_time" class="col-sm-3 p-2">
<i class="fa fa-clock-o fa-lg" aria-hidden="true"></i> Time:
</label>
<div class="col- p-2">
<div class="myStartTime" id="start_time_<%= #assignment.id %>">
<%= f.time_select :start_time %>
</div>
</div>
<div class="col- p-2"><i class="fa fa-arrows-h fa-lg" aria-hidden="true"></i></div>
<div class="col-sm-3 p-2">
<div class="myEndTime" id="end_time_<%= #assignment.id %>">
<%= f.time_select :end_time %>
</div>
</div>
</div>
<div class="d-flex flex-row">
<label for="assignment_notes" class="col-sm-3 p-2">
<i class="fa fa-clipboard fa-lg" aria-hidden="true"></i> Notes:
</label>
<div class="col-sm-9 p-2">
<div class="d-flex flex-row">
<span> Notes only get saved if a contact is assigned the shift, and get removed when the contact is removed from the shift.</span>
<div class="">
<%= f.label :notes %>
<%= f.text_area :notes %>
</div>
</div>
</div>
</div>
</section>
</div>
<div class="col-sm-4">
<!-- Contact Section-->
<div id="contact_section">
<% if #assigned_contacts && #assigned_contacts.length > 0 %>
<h2>Previously Assigned Contacts</h2>
<% #assigned_contacts.each do |c| %>
<%= label_tag "assigned_contacts[#{c.id}]", "Are you sure you want to remove the currently scheduled volunteer, #{c.display_name} (##{c.id}), from the assignment(s)?" %>
<%= check_box_tag "assigned_contacts[#{c.id}]", "replace", #replaced_contacts.include?(c.id) %>
<% end %>
<% end %>
<input id="contact_element_prefix" name="contact_element_prefix" type="hidden" value="contact">
<div class="name large flex-row">
<%= f.label :contact_id %><%= f.text_field :contact_id %>
</div>
<div id="display-contact" class="d-flex flex-row">
<p>_form</p>
<% if f.object.contact_id %>
<%= render partial: 'contacts/contact_display', locals: { contact:f.object.contact} %>
<% else %>
<div>no contact - _form.html called</div>
<%#= link_to 'Show Contact', contact_path(f.object.contact_id), remote: true %>
<% end %>
</div>
<!-- FIXME: replace this logic stack with AJAX-->
<%#= contact_field("#obj", "contact_id",
:locals => {:options => {
:object_name => f.object_name.to_s,
:field_name => 'contact_id',
:on_display => 'display_disciplinary_notes(); display_contact_notes();'
}}
) %>
<%= f.label :closed, "Is this slot closed?" %>
<%= f.check_box :closed %>
<!--Contact Section END-->
<!--Attendance / Call Status End-->
<% if f.object.id && f.object.contact_id %>
<div class="flex-row">
<div class="col-25"><label for="assignment_attendance_type_id">Attendance:</label></div>
<div class="col-75"><%= select(f.object_name,
"attendance_type_id",
AttendanceType.all.sort_by(&:id).collect {|p| [ p.name, p.id ] },
:include_blank => true) %></div>
</div>
<div class="flex-row">
<div class="col-25"><label for="assignment_call_status_type_id">Call status:</label></div>
<div class="col-75"><%= select(f.object_name,
"call_status_type_id",
([["not called yet", ""]] + CallStatusType.all.sort_by(&:id).collect {|p| [ p.name, p.id ] }),
:include_blank => false) %></div>
</div>
<% end %>
<!-- Attendance / Call Status End-->
<!-- LOCK VERSION-->
<div class="flex-row">
<div class="col-25">
<%= f.label :lock_version %>
</div>
<div class="col-75">
<%= f.number_field :lock_version %>
</div>
</div>
<!-- LOCK end-->
</div>
</div>
</div>
<div class="modal-footer d-flex justify-content-between">
<div class="edit_icons d-flex flex-row">
<div class="d-flex flex-column">
</div>
<div class="d-flex flex-column">
<%#= link_to '<i class="fa fa-pencil-square-o fa-lg" aria-hidden="true"></i>Edit'.html_safe, edit_assignment_path, remote: true%>
</div>
</div>
<div>
<button type="button" class="btn btn-secondary mr-2" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary"><%= f.submit "Submit" %></button>
</div>
</div>
</div>
<% end %>
_volunteer_shift_fields.html.erb
<!--<div class="name large flex-row">-->
<%#= vs.label :volunteer_shift %>
<!--</div>-->
<div id="volunteer_shift" class="d-flex flex-row">
<div class="col-sm-12 p-2">
<div id="volunteer_shift" class="text-right">
<!-- old if: if class is assignment show volunteer shift else show default shift -->
<!-- we need default shift here...NO assignment is attached-->
<div class="field">
<%= vs.label :volunteer_task_type_id %>
<%= select_tag 'volunteer_task_type_id', options_from_collection_for_select([VolunteerTaskType.new(:description => ""), VolunteerTaskType.instantiables.effective_on(Date.today)].flatten, "id", "description") %>
</div>
<div class="field">
<%= vs.label :roster_id %>
<%= select_tag 'roster_id', options_from_collection_for_select([Roster.new(:name => ""), Roster.all].flatten, "id", "name") %>
</div>
<div class="field">
<%= vs.label :program_id %>
<%= select_tag 'program_id', options_from_collection_for_select([Program.new(:name => ""), Program.where(:volunteer => true)].flatten, "id", "name")%>
</div>
<div class="field">
<%= vs.label :set_description %>
<%= text_field(:set_description, nil) %>
</div>
<div class="field">
<%= vs.label :set_date, "Date" %>
<%= text_field(:set_date, nil) %>
</div>
</div>
</div>
</div>
assignments/new.html.erb
Why is it coming here????
I just want the modal "_new.html.erb" to disapear after the form post but rails is sending me here. And I am confused as to why (something simple I'm sure)
<%= render 'form_old', assignment: #assignment %> <---this old form no longer exist
<!--
<%= link_to 'Back', assignments_path %>
volunteer_shift method set_values_if_stuck (see above also)
def set_values_if_stuck(assn_in = nil)
...
return unless self.volunteer_event_id.nil? or self.volunteer_event.description.match(/^Roster #/)
binding.pry
return unless set_date_set #fixme:<--- pry me
roster = Roster.find_by_id(self.roster_id)
...
end
Somewhat straightforward to me if I'm not mistaken your question as to "why _new is rendered".
def create
# #assignment = Assignment.new(assignment_params)
create_shift
respond_to do |format|
if #assignment.save
format.html { redirect_to #assignment, notice: "Assignment was successfully created." }
format.json { render :show, status: :created, location: #assignment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #assignment.errors, status: :unprocessable_entity }
end
end
end
Here, whatever happens in create_shift method, #assignment is being saved; if successfully, then render the :show page, if not, :new page, which by default _new.html.erb in this code.
As to "why the save fails", you could print or use one of those pry gems to see #assignment.errors right before #assignment.save.
I am using filterrific gem to add filters in my app. I have parents table and children table. On the children_list page which displays list of all the children with their firstname and their parent's firstname. The issue I am facing is in the search query I want to add the parent.firstname search as well for filterrific. I tried adding a join as below:-
num_or_conds = 2
joins(child: :parent).where(
terms.map { |term|
"(LOWER(children.firstname) LIKE ?) OR (LOWER(parents.firstname) LIKE ?) "
But this didnt do the job. Any idea how this can be achieved.
parent.rb
has_many :children
child.rb
belongs_to :parent
filterrific(
available_filters: [
:search_query,
:with_clinic_date
]
)
scope :search_query, lambda { |query|
return nil if query.blank?
terms = query.downcase.split(/\s+/)
terms = terms.map { |e|
(e.gsub('*', '%') + '%').gsub(/%+/, '%')
}
num_or_conds = 2
where(
terms.map { |term|
"(LOWER(children.firstname) LIKE ?) OR (LOWER(parents.firstname) LIKE ?)"
}.join(' AND '),
*terms.map { |e| [e] * num_or_conds }.flatten
)
}
scope :with_clinic_date, lambda { |ref_date|
where('children.clinic_date = ?', ref_date)
}
end
_children.html.erb
<h1>Children</h1>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>Parent First Name</th>
<th>Child firstname</th>
</tr>
</thead>
<tbody>
<% #children.each do |child| %>
<tr>
<td><%=child.parent.firstname %></td>
<td><%=child.firstname %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
children-list.html.erb
<%= form_for_filterrific #filterrific do |f| %>
<div class="row">
<div class="col-sm-3">
Search
<%= f.text_field(
:search_query,
class: 'filterrific-periodically-observed form-control'
) %>
</div>
<div class="col-sm-3">
Request Date
<%= f.date_field(:with_clinic_date, class: 'js-datepicker form-control') %>
</div>
<div class="col-sm-3">
<br>
<%= link_to(
'Reset filters',
reset_filterrific_url,
) %>
</div>
</div>
<%= render_filterrific_spinner %>
<% end %>
<%= render( partial: 'children/children_list') %>
children.js.erb
<% js = escape_javascript(
render(partial: 'children/children_list')
) %>
$("#filterrific_results").html("<%= js %>");
AFAIK, you can't filter two separate classes on the same page. It will use the last defined filterrific instance. When I ran into this problem, I used remote forms with custom action/routes
# routes.rb
resources :parent do
get :filter_parents
resources: children do
get :filter_children
end
end
And then the controllers..
# parents_controller.rb
def index
parents_filter # this would be a helper method running your filter queries
end
def filter_parents
parents_filter # this would be a helper method running your filter queries
end
The children's controller would look similar, just different named helper method/custom action.
And then use a partial for the table. Target the table's container, and use a filter_parents.js.erb and filter_childrens.js.erb file
$('#parents-table').html('<%= escape_javascript render 'path/to/partial'%>')
// same in childrens.js.erb, just target the appropriate table
I need to find the average of multiple columns based on a params search across several tables in my VPC controller, but i'm having trouble displaying the average results in the view and also the search is very slow to read from the database. Wondering the best method to do below would be. Would it be best to do the averages in the model? (not sure how this is done though)
Models
class Vpc < ActiveRecord::Base
has_many :results
end
class Result < ActiveRecord::Base
attr_accessible :trial_id, :variety_id, :year, :lint, :turnout, :length_decimal, :length_imperial, :strength, :uniformity, :micronaire, :manual_class
belongs_to :trial, :primary_key => 'trial_id'
belongs_to :variety, :primary_key => 'variety_id'
belongs_to :vpc
has_many :sites, :through => :trial
has_many :growers, :through => :trial
has_many :regions, :through => :sites
end
Controller
class VpcController < ApplicationController
add_breadcrumb "Home", :root_url
add_breadcrumb "Variety Performance Comparison", :vpc_index_path
def index
all = Result.select(:variety_id)
#variety = Variety.where(:variety_id => all).order('variety_name DESC')
#years = Result.select('DISTINCT year')
#regions = Region.all
#irrigations = Trial.select('DISTINCT irrigated').order('irrigated ASC')
end
def search
if params[:variety_one] != params[:variety_two]
#comparison = Result.group('trials.trial_id').having('COUNT(*) = 2').where(variety_id: [params[:variety_one], params[:variety_two]]).
joins(:trial).where('trials.irrigated' => params[:irrigated], 'year' => params[:year]).joins(:regions).where('sites.region_id' => params[:regions])
#vone = #comparison.where('variety_id = ?', params[:variety_one]).select('avg(lint) AS lintone')
#vtwo = #comparison.where('variety_id = ?', params[:variety_two]).select('avg(lint) as linttwo')
#count = #comparison.count('DISTINCT results.trial_id')
#years = #comparison.where('results.year' => params[:year]).select('DISTINCT results.year')
#region = #comparison.where('sites.region_id' => params[:regions]).joins(:regions).group('regions.region_id').select("DISTINCT regions.name")
else
redirect_to vpc_index_url, notice: "Can't compare the same variety"
end
#variety_one = Variety.where('variety_id = ?', params[:variety_one]).group('variety_name')
#variety_two = Variety.where('variety_id = ?', params[:variety_two]).group('variety_name')
add_breadcrumb "Results"
end
end
View Results
<h2>VPC</h2>
<p>We found <%= #count.count %> trials that matched your options, spanning <%= #years.length %> years (<%= #years.map{|y| y.year}.join(", ") %>) and <%= #region.length %> regions (<%= #region.map{|r| r.trial.site.region.name}.join(", ") %>).</p>
<table class="table">
<th></th>
<% #variety_one.each do |v| %>
<th><%= v.variety_name %></th>
<% end %>
<% #variety_two.each do |v| %>
<th><%= v.variety_name %></th>
<% end %>
<th>Difference</th>
<tr>
<td>Yield (bales/ha)</td>
<td><%= "%.2f" % (#vone.lintone/227) unless #vone.blank? %></td>
<td><%= "%.2f" % (#vtwo.lintwo/227) unless #vtwo.blank? %></td>
<td><%= "%.2f" % ((#vone.lintone/227) - (#vtwo.lintwo/227)) unless #lintone.blank? %></td>
</tr>
</tr>
</table>
<hr>
<div class="accordion" id="accordion2">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion2" href="#collapseOne">
<b>Overview of results</b> <span class="pull-right"><i class="icon-chevron-down"></i></span>
</a>
</div>
<div id="collapseOne" class="accordion-body collapse">
<div class="accordion-inner">
<table class="table">
<th>Year</th>
<th>Site</th>
<th>Region</th>
<th>Grower</th>
<% #comparison.each do |v| %>
<tr>
<td><%= link_to v.trial.year, trial_trials_path(trial_id: v.trial_id) %></td>
<td><%= link_to v.trial.site.site_name, trial_trials_path(trial_id: v.trial_id) unless v.trial.site.blank? %></td>
<td><%= link_to v.trial.site.region.name, trial_trials_path(trial_id: v.trial_id) unless v.trial.site.blank? %></td>
<td><%= link_to v.trial.grower.full_name, trial_trials_path(trial_id: v.trial_id) unless v.trial.grower.blank? %></td>
</tr>
<% end %>
</table>
</div>
</div>
</div>
SQL Error
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS lintone) AS count_avg_lint_as_lintone, avg(lint) AS lintone, trials.trial_id ' at line 1: SELECT COUNT(avg(lint) AS lintone) AS count_avg_lint_as_lintone, avg(lint) AS lintone, trials.trial_id AS trials_trial_id FROM `results` INNER JOIN `trials` ON `trials`.`trial_id` = `results`.`trial_id` INNER JOIN `trials` `trials_results_join` ON `trials_results_join`.`trial_id` = `results`.`trial_id` INNER JOIN `sites` ON `sites`.`site_id` = `trials_results_join`.`site_id` INNER JOIN `regions` ON `regions`.`region_id` = `sites`.`region_id` WHERE `results`.`variety_id` IN (2300, 2255) AND `trials`.`irrigated` IN (0, 1, 2) AND `results`.`year` IN (2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013) AND `sites`.`region_id` IN (1, 2, 3, 4, 5, 6, 7, 8) AND (variety_id = '2300') GROUP BY trials.trial_id HAVING COUNT(*) = 2
Looking at your massive controller, I would suggest the following:
#comparison = Result.group('trials.trial_id').having('COUNT(*) = 2').where(variety_id: [params[:variety_one], params[:variety_two]]).
joins(:trial).where('trials.irrigated' => params[:irrigated], 'year' => params[:year]).joins(:regions).where('sites.region_id' => params[:regions])
#count = #comparison.count('DISTINCT results.trial_id')
#years = #comparison.where('results.year' => params[:year]).select('DISTINCT results.year')
#region = #comparison.where('sites.region_id' => params[:regions]).joins(:regions).group('regions.region_id').select("DISTINCT regions.name")
Keep that chunk the same but create a migration to add indexes to increase the performance.
You should not call average so many times but instead do a select on the values you want
#vone = #comparison.where('variety_id = ?', params[:variety_one]).select(avg(lint) as lint, avg...
#vtwo = #comparison.where('variety_id = ?', params[:variety_two]).select(avg(lint) as lint, avg...)
Now in your views you can just get the needed attributes.
After that, have a look at the logs to see if there are any N+1 you can reduce.
I am developing an application using rails 3.2.0 and ruby 1.9 on a Mac
I have a very strange error when rendering an index view
Rails is rendering the characters us at the bottom of the screen, below an index table, and I cannot find these characters in the view.
This part of the view looks like
<section id="main">
<section id="group"></section>
<section id="content">
<section id="data_table_section">
<script>
us
</section>
</section>
The part from id=content is yield in a layout file
<section id='content'>
<%= yield %>
</section>
When I delete the content of the view template, i.e the the us is still there
When I delete <%= yield %> in the layout, the us disappears
When I search for the us in the view code it is not found
When I add my own extra characters in the bottom of the view template code, after tags the us is displayed after these characters
When I delete the layout template the us is still there
The only thing I can come up with is that us is generated by the yield function in some mysterious way, but that seems as a very strange explanation!
Anyone that has had this problem before?
Anyone that know how to find extra characters as us in the code ?
Could it be a bug in the rendering engine ?
Any advices would be great appreciated
Here follows my view code. I use tableastic gem and some other gems
<% if !#unit.nil?
header_text="Deltagarlista för #{#unit.class.model_name.human} #{#unit.name}"
else header_text='Deltagarlista för ST-Forum'
end %>
<section id='data_table_section'>
<article id='remote_clinic_article'></article>
<article id="users_article">
<%= table_for(#users) do |t| %>
<thead ><tr ><th id='table_header' colspan=17><%=header_text%></th></tr></thead>
<thead><tr style='text-align:center;' ><th colspan=15><%= render :partial=>'users/filter'%></th></tr></thead>
<% index=(params[:page].to_i-1)*#per_page%>
<%= t.data do
t.cell(:id, :heading => "Id") {|p| index+=1}
t.cell(:portrait, :heading => "Foto") {|p| image_tag(p.portrait_image,:height=>'24px')}
t.cell(:name,:heading => sort_to("Namn",users_url(:sort_field=>'surname', :sort=>#sort),#sort_field)) {|p| link_to(mark_search_hits(p.name,#search),user_path(p.id))}
t.cell(:clinic, :heading => sort_to("Arbetsplats",users_url(:sort_field=>'clinics.name', :sort=>#sort),#sort_field)) {|p| link_to(mark_search_hits(p.clinic.name,#search),clinic_path(p.clinic.id)) unless p.clinic.nil?}
t.cell(:email,:cell_html => {:class => "address"},
:heading => sort_to("Email",users_url(:sort_field=>'email', :sort=>#sort),#sort_field)) {|p| mail_to(mark_search_hits(truncate(p.email,:length =>20),#search))}
t.cell(:user_roles,:cell_html => {:style => "width:50px"},
:heading => sort_to("Roller",users_url(:sort_field=>'user_roles.role_index', :sort=>#sort),#sort_field)) {|p| mark_search_hits(p.roles(true).to_sentence,#search)}
t.cell(:groups, :heading => sort_to("Grupper",users_url(:sort_field=>'groups.name', :sort=>#sort),#sort_field)) {|p| mark_search_hits(to_sentence(p.groups),#search)}
t.cell(:forum, :heading => sort_to("ST-forum",users_url(:sort_field=>'forums.name', :sort=>#sort),#sort_field)) {|p| mark_search_hits(link_to(p.forum.name,clinic_path(p.forum.id)),#search) unless p.forum.nil?}
t.cell(:st_starts_on, :heading => sort_to("ST-start -- slut",users_url(:sort_field=>'employments.st_starts_on', :sort=>#sort),#sort_field)){|p| mark_search_hits(between_user_dates(p.employment.st_starts_on,p.employment.st_end_on),#search) unless p.employment.nil?}
t.cell(:legitimation_on,:heading => sort_to("Legitimation",users_url(:sort_field=>'employments.legitimation_on', :sort=>#sort),#sort_field)){|p| mark_search_hits(to_user_date(p.employment.legitimation_on),#search) unless p.employment.nil?}
t.cell(:employed_on,
:heading => sort_to("ST-kontrakt",users_url(:sort_field=>'employments.employed_on', :sort=>#sort),#sort_field)){|p| mark_search_hits(to_user_date(p.employment.employed_on),#search) unless p.employment.nil?}
t.cell(:last_visit,
:heading => sort_to("Inloggad senast",users_url(:sort_field=>'last_visit_at', :sort=>#sort),#sort_field)){|p| mark_search_hits(to_user_date(p.last_visit_at),#search) }
t.cell(:mail,
:heading => "Handledare / Handledd") {|p| if !p.supervisors.blank? then mail_supervisors(p) elsif !p.supervised.blank? then mail_supervised(p) end}
t.cell(:id, :cell_html => {:style => "width:30px"},:heading=>image_to('new.png',new_user_path,:class=>'no_class')) {|p| (image_to('destroy.png',user_path(p),:class=>'none',:method=>'delete', :id=>'destroy_button', :confirm => "Vill du verkligen radera vald kurs ",:title=>'Radera kurs')+' '+image_to('map.png', map_address_path(p.address.id),:method=>:get,:class=>'none', :remote=>true, :title=>'Visa en karta över bostadsområdet')).html_safe}
end%>
<tfoot>
<tr >
<td colspan="16" class='flickr_pagination'><%= will_paginate #users, :container => true %><span class="table_filter_text">
<% if #count_users==0 %>
<span class="table_filter_alert_text">
<%=" Inga användare tillgänglig för #{put_filter(#filterparams)}".html_safe%>
</span>
<%else%>
<span class="table_footer_text">
<%="Visar användare "+((params[:page].to_i-1)*#per_page+1).to_s+" till "+([(params[:page].to_i-1)*#per_page+#per_page,#count_users].min).to_s+" av #{#count_users.to_s} användare" .html_safe%>
<br/><%= "Med #{ put_filter(#filterparams)}".html_safe %>
</span>
<%end%>
</td>
</tr>
</tfoot>
<% end %>
</article>
</section>
<script>
$(document).ready(function() {
/* $('.pagination a').attr('data-remote', 'true');*/
jQuery(".best_in_place").best_in_place();
});
// Observe forum_field and filter group_options
$(document).ready(function(){
$("#forum_id").live('change',function () {
var forum = "";
forum=$("select#forum_id :selected").val()
if (forum=='') {forum=0}
jQuery.get('/users/'+forum+'/update_group_options', function(data){
$("#group_div").html(data);
})
return false;
})
.change();
$("#county_council_id").live('change',function () {
var county_council = "";
county_council=$("select#county_council_id :selected").val()
if (county_council=='') {county_council=0}
jQuery.get('/users/'+county_council+'/update_forum_options', function(data){
$("#forum_div").html(data);
})
return false;
})
.change();
});
</script>
I think the "us" is written by js.
May be you can double check the js.