Home > Enterprise >  What is causing the rollback when I try to update a record
What is causing the rollback when I try to update a record

Time:03-08

Not understanding why my record is not being updated. Where do I look? How do I debug?

Here is the rollback message I see...

    66: def update #this is NOT working...use imported older version below
 => 67:   binding.pry
    68:   
    69:   @assignment.update(assignment_params)
    70: end

[1] pry(#<AssignmentsController>)> @assignment.update(assignment_params)
   (0.2ms)  BEGIN
  VolunteerShift Load (0.2ms)  SELECT  "volunteer_shifts".* FROM "volunteer_shifts" WHERE "volunteer_shifts"."id" = $1 LIMIT $2  [["id", 545496], ["LIMIT", 1]]
  Contact Load (0.3ms)  SELECT  "contacts".* FROM "contacts" WHERE "contacts"."id" = $1 LIMIT $2  [["id", 137424], ["LIMIT", 1]]
  VolunteerTaskType Load (0.3ms)  SELECT  "volunteer_task_types".* FROM "volunteer_task_types" WHERE "volunteer_task_types"."id" = $1 LIMIT $2  [["id", 41], ["LIMIT", 1]]
  Roster Load (0.2ms)  SELECT  "rosters".* FROM "rosters" WHERE "rosters"."id" = $1 LIMIT $2  [["id", 7], ["LIMIT", 1]]
  VolunteerEvent Load (0.2ms)  SELECT  "volunteer_events".* FROM "volunteer_events" WHERE "volunteer_events"."id" = $1 LIMIT $2  [["id", 52679], ["LIMIT", 1]]
   (0.2ms)  ROLLBACK
=> false
[2] pry(#<AssignmentsController>)> exit

Here is the model...

class Assignment < ApplicationRecord
  # attr_accessor :volunteer_event ,:contact_id #why is this here???
  # attr_accessor :redirect_to
  belongs_to :volunteer_shift, optional: true
  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??

  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

  def contact_id=(newval)
    self.write_attribute(:contact_id, newval)
    self.contact = Contact.find_by_id(newval.to_i)
  end

  def contact_id_and_by_today
    # Unless the contact id is empty, or the event date is after today.
    !(contact_id.nil? || self.volunteer_shift.volunteer_event.date > Date.today)
  end

# 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 first_time_in_area?
    if self.contact and self.volunteer_shift and self.volunteer_shift.volunteer_task_type
      return !ContactVolunteerTaskTypeCount.has_volunteered?(self.contact_id, self.volunteer_shift.volunteer_task_type_id)
    else
      return false
    end #  and self.contact_id_changed? moved outside because we use update_attributes
  end

  def slot_type_desc
    b = (self.volunteer_shift.volunteer_task_type_id.nil? ? self.volunteer_shift.volunteer_event.description : self.volunteer_shift.volunteer_task_type.description)
    b = b   " (#{self.volunteer_shift.description})" if self.volunteer_shift.description and self.volunteer_shift.description.length > 0
    b
  end

  def display_name
    ((!(self.volunteer_shift.description.nil? or self.volunteer_shift.description.blank?)) ? self.volunteer_shift.description   ": " : "")   self.contact_display
  end

  def cancelled?
    (self.attendance_type&.cancelled)
  end

  def attended?
    (self.attendance_type and !self.attendance_type.cancelled)
  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 }

  scope :for_contact, lambda{|assignment|
    tcid = assignment.contact.id
    { :conditions => ['contact_id = ?', tcid] }
  }

  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

Here is the entire controller

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.limit(20)
    # @assignments = Assignment.where(start: params[:start]..params[:end])
    @assignments = Assignment.date_range(params[:start]..params[:end])

  end

  # GET /assignments/1 or /assignments/1.json
  def show
  end

  # GET /assignments/new
  def new
    # @assignment = Assignment.new
    add_shift
    # @assignment.volunteer_shift.build
  end

  # GET /assignments/1/edit <-- ORIGINAL
  # def edit
  # end

  def edit #dumb "stuff" from older app
    logger.debug "assignments_controller EDIT called"
    if @assignment
      @assignments = [@assignment]
    else
      begin
        @assignments = params[:id].split(",").map{|x| Assignment.find(x)}
        @assignment = @assignments.first
      rescue
        flash[:error] = $!.to_s
        redirect_skedj(request.env["HTTP_REFERER"], "")
        return
      end
    end
    @referer = request.env["HTTP_REFERER"]
    @my_url ||= {:action => "update", :id => params[:id]}
    render :action => 'edit'
  end

  # POST /assignments or /assignments.json
  def create
    create_shift
    # @assignment = Assignment.new(assignment_params)
    #
    # # error wants contact.id not contact_id ???
    #
    # 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

  # PATCH/PUT /assignments/1 or /assignments/1.json
  def update #this is NOT working...use imported older version below
    binding.pry
    @assignment.update(assignment_params)
  end


  def update_from_old_code #from original garbage code
    logger.debug "assignments_controller UPDATE called"
    unless params[:assignment]
      redirect_to :action => "index"
      return
    end
    @my_url = {:action => "update", :id => params[:id]}
    last_id = nil
    begin
      # is @assignments broken here??
      @assignments = params[:id].split(",").map{|x| last_id = x; Assignment.find(x)}
      # binding.pry
    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
    # binding.pry
    lv = params["lock_versions"]
    ac = params["assigned_contacts"] || {}
    @assigned_contacts = []
    @replaced_contacts = []
    ret = true #WTF why???
    #500 error caused by ??
    @assignments.each do |as|
      as.lock_version = lv[as.id.to_s]
      # binding.pry
      if as.lock_version_changed?
        binding.pry
        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
        binding.pry
        @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
    # binding.pry
    if ! ret
      @assignment = Assignment.new
      @assignment.volunteer_shift = @assignments.first.volunteer_shift
      @assignment.attributes=(params[:assignment]) # .. ? .delete("volunteer_shift_attributes")
    end
    # binding.pry
    @assignments.each{|x|
      # binding.pry
      if ret #what does ret mean???
        @assignment = x
        bc = x.contact_id
        binding.pry
        ret = !!(x.update(params[:assignment])) #TODO not working...what is "!!" here? THIS IS THE BREAKING LINE
        binding.pry
        # how to say if updated then true ??
        if ret
          binding.pry
          flash[:notice] = 'Assignment was successfully updated.'
        else
          binding.pry
          render :action => "edit"
        end
        # when are the values x updated?
      end
    }
  end

  # DELETE /assignments/1 or /assignments/1.json
  def destroy #this is working
    @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, :set_date, :date, :date_range, :volunteer_shift_id, :contact_id, :start_time, :end_time, :start, :end, :attendance_type_id, :notes, :call_status_type_id, :closed, :lock_version, :color, :description, volunteer_shift_attributes: [:volunteer_task_type_id,:roster_id,:program_id,:set_description,:set_date,:id,:destroy])
      # params.require(:assignment).permit(:title, :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

Any help is appreciated

Thank you for your time.

CodePudding user response:

You can try update!, which should show the exact cause of rollback.

@assignment.update!(assignment_params)

CodePudding user response:

change your code in update method with ! like below so it will help you to find error with exact reason with exception

@assignment.update!(assignment_params)
  • Related