views:

24

answers:

1

I'm facing a problem where I cannot permanently decide which columns one of my models will have. A use case will be this:

An admin creates a new dataset, he wants users to answer. In the dataset the admin defines several data points of different format and units.

I could imagine the classes to look similar to this:

class Dataset < ActiveRecord::Base
 has_many :measurements
 has_many :profiles, :through => :measurements
 has_many :datapoints, :through => :dataset_datapoint
end

# Join table
class Dataset_datapoint < ActiveRecord::Base
 belongs_to :dataset
 belongs_to :datapoint
end

class Datapoint < ActiveRecord::Base
 has_many :dataset, :through => :dataset_datapoint
 has_many :data
 # create_table "datapoints" do |t|
 # t.string :name
 # t.string :format  # e.g. string, decimal etc.
 # t.string :unit # e.g. CM, pounds etc.
end

class Data < ActiveRecord::Base
 belongs_to :datapoint
 # create_table "data" do |t|
 # t.integer :datapoint_id
 # t.string :value # This column could be anything from string to decimal
end

In my head, this seems pretty dynamic, but still quite easy to implement. What I'm worried about, is how to do the validation on every Data model that is created? Since I cannot hardcode the validation in the model? And to make it even more complicated, what if some datapoints require extra validations, such as minimum and maximum value?

Thanks in advance, Jonas

A: 

You'll have to enumerate the list of available validations.

Then you can create a validation model and table (and maybe a join table if you want users to be able to reuse their validations - depends on your use cases):

class Validation < ActiveRecord::Base
  belongs_to :dataset
  # create_table 'validations' do |t|
  # t.references :dataset
  # t.string :type
  # ... and columns for each restriction you could apply, ie:
  # t.integer :max_value      
  # t.integer :min_value
  # t.string :regexp
  # ...etc...
end

Then, in your data model, add a before_save filter to call your custom validation method:

class Data < ActiveRecord::Base
  belongs_to :datapoint
  has_many :validations, :through => :datapoint
  before_save :custom_validation

private
  def custom_validation
    validations.each do |validation|
      if validation.type == 'integer_range'
        unless value < validation.max_value and value > validation.min_value
          # return false, or add an error on the value attribute, or whatever
        end
      # More validations here - use a case statement probably
    end
  end
end

Not sure if I've got your relationships exactly figured out, but something like that should give you a starting point.

nfm
Thanks mate, it sounds like a totally reasonable solution. I actually had somewhat the same thoughts in mind, but thought of it in a much more complex way.
Jonas Nielsen