icn
icn

Reputation: 17876

Rails 5 , sqlite3 using array as column/ attribute issue

Here is how I use array in a rails 5 model in migration

  t.text :diagnoses, array: true, default: []

in model

class Patient < ApplicationRecord
  serialize :diagnoses, Array
end

in my seed method I am doing it like

  patient = Patient.create(first_name: 'John', last_name: 'Smith', admission: a)
  patient.diagnoses = [1, 2]
  patient.save!

It give an error as

ActiveRecord::SerializationTypeMismatch: can't dump `diagnoses`: was supposed to be a Array, but was a Integer. -- 0

Thanks for any help!

Upvotes: 4

Views: 1455

Answers (2)

max
max

Reputation: 101891

I would seriously consider actually using a relational database properly instead.

# since diagnosis is highly irregular we most likely need to configure rails 
# to pluralize it correctly
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular 'diagnosis', 'diagnoses'
end

class Patient < ApplicationRecord
  has_many :patient_diagnoses
  has_many :diagnoses, through: patient_diagnoses
end

# this table provides data normalization 
class Diagnosis < ApplicationRecord
  has_many :patient_diagnoses
  has_many :patients, through: patient_diagnoses
end

# this is just a join table
class PatientDiagnosis < ApplicationRecord
  belongs_to :patient
  belongs_to :diagnosis
end

This lets you use the foreign keys to ensure referential integrity and lets you use ActiveRecord Associations instead of just cobbling together something wonky. There are very few actual advantages of using an array type here.

If you still want to use your array column you should not use ActiveRecord::AttributeMethods::Serialization. Its used with plain old varchar / text columns to store YAML strings which are serialized/unserialized in Rails. It is a vestige from the dark days before we had native JSON/array types and really does not have any use today besides in legacy applications.

Upvotes: 0

user11831257
user11831257

Reputation:

A while ago, I encountered this exact issue. I found the following workaround:

  • In your migration file:

    t.text :diagnoses, array: true
    
  • Then in model:

    class Patient < ApplicationRecord
      serialize :diagnoses
    
      after_initialize do |patient|
        patient.diagnoses= [] if patient.diagnoses == nil
      end
    end
    
  • The after_initialize callback will be called whenever an Active Record object is instantiated, either by directly using new or when a record is loaded from the database.

Upvotes: 2

Related Questions