How to model an AR object with an array attribute?

What is the correct way to set up an ActiveRecord model that has an attribute that is essential an array of strings?

I have a model called PropertyDescriptor. It has a name, token, and 0…n string values. The name is what the app user might call the descriptor. The token isn’t important in the context of this question. And the values are various words or phrases one might use for that descriptor. For example, you might have descriptors like this:

apartment_attributes = {
  name: "Apartment",
  token: "apt",
  values: %w(apartment apartments apts apartment\ complex flat flats)
}

beds_attributes = {
  name: "Beds",
  token: "bed",
  values: %w(1\ bed 2\ bed 2\ beds loft)
}

Each descriptor should have a value appear only once in its array of values. But it is possible for different descriptors to have the same value. In the example above, “loft” could appear in both apartment_attributes#values and in beds_attributes#values but not twice in either.

I’m struggling with how to model the relationship between the descriptor and values. I’m also struggling with how to ensure the uniqueness of a value within a descriptor#values.

Currently I have the PropertyDescriptor model that has many PropertyDescriptorValues.

The models as I have them now are:

class PropertyDescriptor < ActiveRecord::Base
  # attribute: name:string
  # attribute: token:string
  has_many :values, class_name: 'PropertyDescriptorValue', dependent: :destroy
  accepts_nested_attributes_for :values, allow_destroy: true
end
class PropertyDescriptorValue < ActiveRecord::Base
  # attribute: value:string
  belongs_to :property_attribute
end

I want a user to be able to create a new value when creating or editing a PropertyDescriptor and ensure the descriptor does not already have that value.

Is the right way to handle this a join table using has_many: through:? Or do I make a values:text attribute on the descriptor and serialize it to an array? Any help is greatly appreciated.

I would personally decide to do a polymorphic association. Your Problem seems to be that you have a Property object that you need to describe with many different values. You describe your models as Property Descriptor and PropertyDescriptorValue but the problem with that is, you will ultimately have to store the data about a value as an array. Thats not good design. Instead you should break up the PropertyDescriptorValues into their own PropertyValue Models (ie AptValue , BedValue etc… ) and then link the PropertyDescriptor to them polymorphically. And then when you are going to do validations, you can make the validations for each PropertyValue Model based on what you think you want. Every piece of PropertyValue data will then be able to relate back to one PropertyDescriptorValue in a clean way.

And as far as saving this data to your DB. I think it would be easier to use a FormObject in order to do the work in your own unique way as opposed to going through the hassle of using accepts_nested_attributes_for. Hope this helps.

Thank you for the advice. I’ll look into the Polymorphic associations. My only initial hesitation is that users will be creating PropertyDescriptors and their values on the fly, which implies the creation of models and db tables through the UI. You’ve given me a lot of good stuff to look into though, so I’ll dig around in those areas.

1 Like