Skip to content

Instantly share code, notes, and snippets.

@jmoglesby
Created July 31, 2018 00:56
Show Gist options
  • Save jmoglesby/c6cd028973e7cf169ce0dfa81634749e to your computer and use it in GitHub Desktop.
Save jmoglesby/c6cd028973e7cf169ce0dfa81634749e to your computer and use it in GitHub Desktop.
Example code: The "Item" model from www.speedie.equipment
class Item < ApplicationRecord
belongs_to :item_type
belongs_to :location
delegate :campus, to: :location
has_many :item_comments, dependent: :destroy
has_many :service_events, dependent: :destroy
has_one :last_service_event, -> { order(service_date: :desc, created_at: :desc) }, class_name: "ServiceEvent"
has_many :calibration_events, dependent: :destroy
has_one :last_calibration_event, -> { order(date_performed: :desc, created_at: :desc) }, class_name: "CalibrationEvent"
has_many :location_changes, dependent: :destroy
has_one :last_location_change, -> { order(date_of_change: :desc, created_at: :desc) }, class_name: "LocationChange"
# kaminari gem paginates search results - 10 items per page
paginates_per 10
# Disallow duplicate serial_numbers
validates :serial_number, uniqueness: true, allow_blank: true
# Look into whether I need to cleanup old, uneeded
# paper_trail version records to avoid clutter
has_paper_trail
# If item is edited and location_id is changed in the edit, this hook saves the info
# to create a location_change record, unless the change in location_id comes directly
# from a location_change record creation
after_save :store_location_change, if: :location_id_changed?, unless: :skip_location_change_create
# skip_location_change_create is set to 'true' in location_changes_controller after
# creation of a new location_change record to avoid duplicating/overwriting upon item.save
attr_accessor :skip_location_change_create
# DO NOT add things to the middle of an enum list, only to the end;
# adding to the middle would change the array value of each option which
# would change the value of any option after it in the list on all items
# QUESTION: Should these values be enum'd on item_type instead of here???
enum sieve_type: ['Fine', 'Coarse']
enum fine_sieve_opening_size: ['#400', '#325', '#270', '#200', '#150', '#140', '#120', '#100',
'#80', '#60', '#50', '#45', '#40', '#35', '#30', '#25', '#20',
'#18', '#16', '#14', '#12', '#10', '#8', '#7', '#6'
]
enum coarse_sieve_opening_size: ['4"', '3"', '2 1/2"', '2"', '1 3/4"', '1 1/2"', '1 1/4"',
'1"', '7/8"', '3/4"', '5/8"', '1/2"', '7/16"', '3/8"',
'5/16"', '1/4"', '1/8"', '0.265"', '#4'
]
enum sieve_diameter: ['18 inch', '12 inch', '8 inch', '3 inch', 'Gilson']
enum flask_type: ['Rice', 'SpG', 'Other']
enum volume: ['10ml', '24ml', '25ml', '100ml', '250ml', '400ml', '450ml', '500ml', '1000ml', '2000ml', '4000ml']
enum caliper_type: ['Axial', 'Digital', 'Dial', 'Proportional']
enum caliper_size: ['(12")', '(6")']
enum gauge_type: ['(Digital)', '(Dial)']
enum thermometer_type: ['Mercury', 'PRT', 'Thermistor', 'Thermocouple', 'Infrared', 'Pocket']
enum scale_resolution: ['1kg', '5g', '1g', '0.5g', '0.1g', '0.01g', '0.001g']
enum scale_range: ['300lb', '110lb', '20kg', '15kg', '12kg', '500g', '200g', '220lb', '1000g']
enum groove_tool_type: ['AASHTO', 'ASTM']
enum operation_type: ['Manual', 'Automatic']
enum marshall_compaction_pedestal_number: ['Single', 'Double']
enum proctor_mold_type: ['Solid', 'Split']
enum proctor_mold_six_types: ['(Solid)', '(Split)']
enum proctor_hammer_weight: ['5.5lb', '10lb']
enum capping_mold_size: ['2x4', '4x8', '6x12']
enum saw_type: ['Chop', 'Lapidary', 'Tile', 'Wet']
enum penetrometer_type: ['Cone', 'Acme', 'Concrete', 'Soil']
# Items index "Item Type" filter
scope :in_type, -> (type_name) { joins(:item_type).where(types: { name: type_name }) }
# Items index "In Service Only" filter
scope :in_service, -> { joins(:last_service_event).where(service_events: { status: ServiceEvent.statuses[:in_service] }) }
# Campus index filter
scope :at_campus, -> (campus_name) { joins(:campus).where(campuses: { name: campus_name }) }
# Fix this scope to filter calibrations due soon
# scope :calibration_due_soon, -> { joins(:last_calibration_event).where(calibration_events: { :date_performed... }) }
# Items index search query
scope :search, -> (query) { joins(:item_type, location: :campus)
.where("cast(items.id as text) ILIKE ?
OR serial_number ILIKE ?
OR manufacturer ILIKE ?
OR model ILIKE ?
OR items.notes ILIKE ?
OR item_types.name ILIKE ?
OR locations.name ILIKE ?
OR campuses.name ILIKE ?",
"#{query}",
"#{query}%",
"#{query}%",
"#{query}%",
"%#{query}%",
"%#{query}%",
"%#{query}%",
"%#{query}%"
)
}
# Conversions for purchase_cost to display as currency
# (had to work around number_field limitations)
def purchase_cost
purchase_cost_in_cents.to_f / 100
end
def purchase_cost=(value)
value = value.to_f * 100
self.purchase_cost_in_cents = value
end
# When location_id of item is changed via the edit form, store
# location change info so that a location_change record can be created
def store_location_change
location_changes.create(location_id: location_id, date_of_change: DateTime.now.to_date)
end
# Check for presence of item_type variables for helper in the view
def has_item_type_variables
if
self.sieve_type? ||
self.sieve_diameter? ||
self.flask_type? ||
self.volume? ||
self.caliper_type? ||
self.caliper_size? ||
self.gauge_type? ||
self.thermometer_type? ||
self.scale_resolution? ||
self.scale_range? ||
self.groove_tool_type? ||
self.operation_type? ||
self.marshall_compaction_pedestal_number? ||
self.proctor_mold_type? ||
self.proctor_mold_six_type? ||
self.proctor_hammer_weight? ||
self.capping_mold_size? ||
self.saw_type? ||
self.penetrometer_type?
true
else
false
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment