Orphanage is a super lightweight library for persisting orphan records. Let's say you have some data but don't yet know all of its foreign keys. Orphanage streamlines the process of keeping it in a temporary table and then, when all foreign keys become available, transferring it to the proper table in the database.
gem 'orphanage'
Let's say you are have a database with students
having many exams
. Exam results come in to your database via an external source, but sometimes you can't match them up perfectly. A person may have a different last name due to marriage for example. When exam
records can not be identified to a student
they should be stored in the table exam_temps
. Later when an an admin user audits the ambiguous records and provides a student
, the record is transferred fromexam_temps
to exams
.
Assuming your home model already exists and its corresponding table exists in the database run rails generate orphanage:init <HomeModelName>
. For example:
rails generate orphanage:init Exam
generates a model for your orphan table as well as a migration file that will give you all of the columns existing in the home model. You might want to add additional columns that will help you identify the orphan record. Using the exam example above, you might add first_name
and last_name
to the ExamTemp
model as a temporary identifier. You'll also get any other files you would expect when running rails generate model
(such as tests, factories, fixtures, etc as the case may be)
Creating an orphan model by hand isn't much more work. By default orphanage expects the model to have Temp
appended to the original, so for example an orphan model to Exam
would be ExamTemp
.
Then inside that model:
require 'orphanage'
class ExamTemp < ActiveRecord::Base
include Orphanage
orphan
end
From there you can add temporary records to this orphan table like you normally would.
Transferring a model to its home table is done by calling the adopt
method. For example:
# record can't be stored in exam table because it has no student_id
exam_temp = ExamTemp.create!({:score => 150,
:taken_on => Date.today,
:first_name => "Jacob",
:last_name => "Stoebel"
})
#later, a student_id is provided for this record
exam_temp.adopt({:student_id => 1})
Calling adopt
, if successful, will return the created permanent record. The temporary record will stick around unless you explicitly ask for it to be destroyed (see below)
You can customize the behavior at the model level and/or the instance level with instance level customizations taking precedence. To do so, pass in a hash with any of the following keys.
- home The ActiveRecord model to which orphan records will be transferred to when made permanent. By default the value is generated by removing
Temp
from the orphan model (example:ExamTemp
->Exam
) - destroy_on_adopt (boolean) if the orphan record should be destroyed after successful transfer of record. Defaults to
false
. - update_time_stamps a hash of booleans with the following keys
- created if the
created_at
timestamp should be persisted from the orphan record. Defaults totrue
. - updated if the
updated_at
timestamp should be persisted from the orphan record. Defaults totrue
.
- created if the
Let's say our orphan model is ExamTemp
# define a different home class throughout the orphan class...
orphan :home => Examination
# ... or inside just this instance
temp_exam.adopt({:student_id => 1}, {:home => Examination})
# don't destroy temp records after adoption
orphan :destroy_on_adopt => false
# for this instance, don't update the timestamps after adoption
temp_exam.adopt({:student_id => 1}, {:update_timestamps => {:created => false, :updated => false}})