Skip to content

Instantly share code, notes, and snippets.

@havenwood
Created March 26, 2024 03:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save havenwood/a11e14e707d67e284a36f9613494840e to your computer and use it in GitHub Desktop.
Save havenwood/a11e14e707d67e284a36f9613494840e to your computer and use it in GitHub Desktop.
Example read and append CSV ActiveModel implementation for Rails
# frozen_string_literal: true
require 'active_model'
require 'active_support/inflector'
require 'csv'
class CSVFileModel
class RecordNotFound < StandardError
def message = 'Record not found.'
end
include ActiveModel::API
include ActiveModel::Attributes
include ActiveModel::Dirty
class << self
def inherited(subclass)
headers(subclass).each do |header|
subclass.attribute(header, :string)
validates header, presence: true
end
super
end
def headers(subclass = self) = CSV.foreach(filename(subclass)).first
def filename(klass = self)
klass
.name
.underscore
.pluralize
.concat('.csv')
end
def find_by(**attributes)
found = CSV.foreach(filename, headers: true).find do |row|
attributes.all? do |attribute, value|
row[attribute.to_s] == value.to_s
end
end
return unless found
new(**found, &:persist!)
end
def find_by!(...)
record = find_by(...)
raise RecordNotFound unless record
record
end
end
attribute_method_suffix '?'
def attribute?(field) = public_send(field).present?
def save
return true if persisted?
self.id ||= next_id
return false unless valid?
append_csv
self
end
def save!
return true if persisted?
self.id ||= next_id
validate!
append_csv
self
end
def pretty_print(pp)
pp.object_address_group self do
pp.breakable
pp.seplist(attributes) do |field, value|
pp.text "#{field}=#{value.inspect}"
end
end
end
def persist!
changes_applied
@persisted = true
end
def persisted? = @persisted
private
attr_accessor :persisted
def next_id
CSV.foreach(self.class.filename, headers: true)
.reverse_each
.first
.fetch('id', -1)
.to_i
.succ
end
def append_csv
CSV.open(self.class.filename, 'a+', headers: true) do |csv|
csv << attributes.values
end
persist!
end
end
class Student < CSVFileModel
end
student = Student.new
student.name = 'shan'
student.teacher_name = 'romy'
student.subject = 'typing'
pp student.changes
student.save!
pp student
pp student.changes
pp Student.find_by(id: 4)
id name teacher_name subject
1 abbas lakshmi science
2 priya surya social
3 kiran manoj maths
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment