Search code examples
rubysequelsti

How to reload a record where the sti_key column changes during an update to a Sequel Single Table Inheritance (STI) row


So lets say I have a table that's setup with Single Table Inheritance:

class Employee < Sequel::Model
  plugin :single_table_inheritance, :kind

  class Staff < self; end
  class Manager < self; end
end

and I create the new record and then subsequently want to update the employee role, like so:

employee = Employee::Manager.create
employee.update(kind: "staff")

The issue I'm having is that employee.class still returns Employee::Manager instead of Employee::Staff and doing a employee.reload results in a Sequel::NoExistingObject: Record not found. Looking at the resulting sql its obvious that's its still trying to find the record using the old type:

SELECT * FROM "employees" WHERE (("employees"."kind" IN ('manager')) AND ("id" = 1)) LIMIT 1

The only way I've been able to get around this is to reload the record from the id:

employee = Employee[employee.id]

Am I missing something or this the only way to refresh the updated record?

Thanks in advance!


Solution

  • First of all according to your example, you are doing your update in wrong way. It should be like

    employee = Employee::Manager.create
    employee.update(kind: "Employee::Staff")
    

    because Employee is like a namespace in your example.

    And then you can load it class, by calling sti_load on class. there is some variations

    em = em.class.sti_load(em) #=> #<Employee::Staff @values={...}>
    # or
    em = Employee.sti_load(em) #=> #<Employee::Staff @values={...}>
    # or
    em = Employee::Staff.sti_load(em) #=> #<Employee::Staff @values={...}>