nulltek
nulltek

Reputation: 3337

Fetching last incomplete record or new in ActiveRecord

I have a Rails 3.2.21 app where I'm adding some basic timeclock functionality. I need to build a scope called current_clock_event that will look for the last record for a user where clock_out: nil so in essence, the record that will be fetched is the last ClockEvent record for the user that does not have a value in clock_out. This is what I want to pass to my controller/view.

class ClockEvent < ActiveRecord::Base
  attr_accessible :clock_in, :clock_out, :total_hours, :user_id 

  scope :current_clock_event, where(clock_out: NIL).last
end

As you can see I wrote a very simple scope to pull a record where the clock_out: NIL so in theory that should pull the last incomplete record. I think this is working ok but I need to figure out how to access this in the controller and have some sort of conditional to either pull the current_clock_event or instantiate a new clock event if the last record is completed (both clock_in and clock_out are populated)

So I'm stubbing out my controller but am hitting a wall as to how to do this.

class ClockEventsController < ApplicationController

  def index
    @clock_event = current_user.current_clock_event # need to figure out this part to fetch the record or if the record is complete instantiate a ClockEvent.new for the user.
    respond_to do |format|
      format.html # index.html.erb
      format.js
    end
  end
end 

I wrote code 2 years ago that did all of this but lost the repo by accident so I have nothing to reference and am sort of brain-fogging on how to pull this off.

Any help would be appreciated. If you need more examples or further explanation, please let me know.

Upvotes: 0

Views: 77

Answers (2)

nulltek
nulltek

Reputation: 3337

I played around with some code and was able to get some refactoring help to make things cleaner. In the User model I refactored current_clock_event to just clock_event and seem to have been able to make the code a bit cleaner, although it's not tested, just stubbed out for now. Let me know what you think.

 class ClockEvent
   belongs_to :user

   scope :incomplete, -> { where(clock_out: nil) }
   scope :complete, -> { where.not(clock_out: nil) }

   def completed?
     clock_in.present? && clock_out.present?
   end
  end

  class User
    has_many :clock_events

     def clock_event
      @clock_event ||= clock_events.incomplete.last || clock_events.new
     end
   end

  class ClockEventsController < ApplicationController

    def index
      @clock_event = current_user.clock_event
      render :index
    end
  end

Upvotes: 0

Pierre-Louis Gottfrois
Pierre-Louis Gottfrois

Reputation: 17631

You might want to try something like this:

class ClockEvent

  belongs_to :user

  # you might want to add an order here...
  scope :last_clock_event, -> { where("clock_out NULL").last }

  def completed?
    clock_in.present? && clock_out.present?
  end

end

class User

  has_many :clock_events

  def current_clock_event
    ce = clock_events.last_clock_event
    ce.completed? ? ClockEvent.new : ce
  end

end

class ClockEventsController < ApplicationController

  def index
    @clock_event = current_user.current_clock_event
    render :index
  end

end

The completed? method defined on the ClockEvent instance allows you to tell if your instance is considered completed or not.

The current_clock_event method defined at the User level allows you to define the logic to return either the last clock event record or a new one if completed.

The index method is pretty straight forward.

Upvotes: 1

Related Questions