views:

30

answers:

1

This rails validation code is so ugly, and there must be a better way to do it.

The short story is my user is inputting data from test results. Each specific test has 4 measurements. Usually the user inputs all 5 tests (20 measurements), but it's not always required. I just need to check that if a tester started inputting data for a test, he input all 4 measurements in that test.

(Later I will make a validation class, but I'm using this to get started)

Edit: To clarify, the 'tests' are measurements on materials (unrelated to software). the testers record the data on paper, and later it is input into this application

<pre>
def must_input_full_test

  #test Top Section
  if top_section_1 || top_section_2 || top_section_3 || top_section_4
    found_at_least_one = true
    #at least one is present; now check if any are empty
    if top_section_1.nil?
      errors.add :top_section_1, "Must fill in four values for a test"
    end
    if top_section_2.nil?
      errors.add :top_section_2, "Must fill in four values for a test"
    end
    if top_section_3.nil?
      errors.add :top_section_3, "Must fill in four values for a test"
    end
    if top_section_4.nil?
      errors.add :top_section_4, "Must fill in four values for a test"
    end
  end

  #test Bottom Section
  if bottom_section_1 || bottom_section_2 || bottom_section_3 || bottom_section_4
    found_at_least_one = true
    #at least one is present; now check if any are empty
    if bottom_section_1.nil?
      errors.add :bottom_section_1, "Must fill in four values for a test"
    end
    if bottom_section_2.nil?
      errors.add :bottom_section_2, "Must fill in four values for a test"
    end
    if bottom_section_3.nil?
      errors.add :bottom_section_3, "Must fill in four values for a test"
    end
    if bottom_section_4.nil?
      errors.add :bottom_section_4, "Must fill in four values for a test"
    end
  end

  #test Bottom
  if bottom_1 || bottom_2 || bottom_3 || bottom_4
    found_at_least_one = true
    #at least one is present; now check if any are empty
    if bottom_1.nil?
      errors.add :bottom_1, "Must fill in four values for a test"
    end
    if bottom_2.nil?
      errors.add :bottom_2, "Must fill in four values for a test"
    end
    if bottom_3.nil?
      errors.add :bottom_3, "Must fill in four values for a test"
    end
    if bottom_4.nil?
      errors.add :bottom_4, "Must fill in four values for a test"
    end
  end

  #test Middle Section
  if middle_1 || middle_2 || middle_3 || middle_4
    found_at_least_one = true
    #at least one is present; now check if any are empty
    if middle_1.nil?
      errors.add :middle_1, "Must fill in four values for a test"
    end
    if middle_2.nil?
      errors.add :middle_2, "Must fill in four values for a test"
    end
    if middle_3.nil?
      errors.add :middle_3, "Must fill in four values for a test"
    end
    if middle_4.nil?
      errors.add :middle_4, "Must fill in four values for a test"
    end
  end

  #test Top
  if top_1 || top_2 || top_3 || top_4
    found_at_least_one = true
    #at least one is present; now check if any are empty
    if top_1.nil?
      errors.add :top_1, "Must fill in four values for a test"
    end
    if top_2.nil?
      errors.add :top_2, "Must fill in four values for a test"
    end
    if top_3.nil?
      errors.add :top_3, "Must fill in four values for a test"
    end
    if top_4.nil?
      errors.add :top_4, "Must fill in four values for a test"
    end
  end

  if !found_at_least_one
    errors.add :middle_1, "Must fill in at least some test data"
  end
end
<code>
A: 

Can you change the code you're testing? It would be best to have something like this (in JSON):

{
  'top' : [section1, section2, section3, section4],
  'middle' : [section1, section2, section3, section4],
  'bottom' : [section1, section2, section3, section4]
}

So you'll have a hash with the keys :top, :middle and :bottom (or whatever you need) and each value of that hash will be an array with four values, which correspond to the _1, _2, _3, _4 you've got at the moment.

With a structure like that, you can easily iterate over it.


Edit: As you can't change your model, you'll need to bend your tests to fit. Using the technique I outlined, you can create strings that correspond to your different model attributes, then use read_attribute(attr_string) to get the attribute value. If you're having problems doing that, I think you'll need to ask a new question.

Skilldrick
What code do you mean? To clarify, the 'tests' are measurements on materials (unrelated to software). the testers record the data on paper, and later it is input into this application
Bryan
If you meant the code this is written in, yes can be changed no problem. Although I have almost no Javascript ability
Bryan
Sorry, I was just using JSON as a means of displaying the data structure you'd need. Basically, the `{ 'string' : value }` maps to a Ruby Hash, and `[value, value, value]` maps to a Ruby array.
Skilldrick
I'm saying that instead of each test value be a different variable, i.e. `bottom_section_1`, make them all elements of a data structure, as outlined above.
Skilldrick
Is there a simple way to map a db/model to a hash? I'm really hoping there is...
Bryan
@Bryan - it completely depends on the structure of your db or model. What *is* `top_section_1` (for example)? Where does it come from?
Skilldrick
these are from my model... my model has 20 decimal attributes, corresponding to all the fields you see above.
Bryan
Would love to restructure the model, but I don't know any other way to do it
Bryan