2
votes

I have three models named Metric, Entry, and Measurement:

class Metric < ActiveRecord::Base
  has_many :entries
  attr_accessible :name, :required_measurements, :optional_measurements
end

class Entry < ActiveRecord::Base
  belongs_to :metric
  has_many :measurements
  attr_accessible :metric_id
end

class Measurement < ActiveRecord::Base
  belongs_to :entry
  attr_accessible :name, :value
end

They are associated, and I can create nested instances of each this way:

bp = Metric.create(:name => "Blood Pressure", :required_measurement_names => ["Diastolic", "Systolic"])

bp_entry = bp.entries.create()

bp_entry.measurements.create({:name => "Systolic", :value =>140}, {:name => "Diastolic", :value =>90})

How do I validate the measurements for blood pressure based on the :required_measurement_names attribute in the Metric model? For example, how would I ensure that only "Systolic" and "Diastolic" are entered as measurements?

Is there a better way to about setting up these associations and validations?

Thanks!

1
Does Entry have a has_one or has_many relationship with Measurements?EmFi
Also do you want to ensure that each required measurement exists for any given metric? Do you also want to limit measurements for any metrics to only those in the required and optional list?EmFi
I want to ensure that if a Metric has an Entry, that the Entry must have the required measurements. For example, if I define a Food metric which requires "Calories", and optionally "Carbs", I'd like to be able to generate a form for a Food metric which would have fields for "Calories" and "Carbs". But I'd like to have a way to validate that a "Calories" measurement was entered.Chanpory
Also, I updated the code to show a has_many relationship with MeasurementsChanpory

1 Answers

1
votes

Looks like entry is a join model between Measurement and Metric. so it makes sense for your validation to go there.

To ensure that all metrics required metrics are covered

def validate_required_measurements
  metric.required_measurements.each{ |requirement| 
     unless (measurements.map{|measurement| measurement.name}.includes requirement)
       errors.add_to_base "required measurement #{requirement} is missing"  
     end
  }
end

To ensure that only accepted metrics are included (assuming optional metrics are accepted too).

def validate_accepted_measurements
  measurements.each{ |measurement| 
     unless ((metric.required_measurements + metric.optional_measurements).include measurement.name )
       errors.add_to_base "invalid measurement #{measurement.name} for metric"  
     end
  }
end

Putting it all together add the above and following to the Entry model

validate: validate_accepted_measurements, :validate_required_measurements

N.B. my Ruby is a little rusty so this isn't guaranteed to work after copying and pasting, but it should get you close enough to fix the syntax errors that slipped through.