views:

423

answers:

2

In a similar vein to a previous question of mine

I need to validate a group of select inputs for order of voting preference. This time I've had to change it slightly.

The options to a user would be something like:

Choose in order of preference
1: [select with options]
2: [select with options]
3: [select with options]

The hash that this would produce could be something like:

["1" => "option-3", "2" => "option-1", "3" => "0"]

Where the 0 is a choice of no preference.

I have two questions:

  1. How do I validate for the unique presence of the options selected - so there can't be multiple "option-2", but there can be multiple "0"'s (no preference)?

  2. How would I validate to make sure that if someone selects 0 for the second select, they can't have an option in the third select (so with data like: ["1" => "option-3", "2" => "0", "3" => "option-1"])?

I've been trying all kinds of array manipulation but can't quite work it out.

A: 

I would do something like this:

valid = true
votes = (1..3).map{|x| params["select#{x}"]}
# Pass first condition
valid = false unless votes.uniq.length == votes.length
# Pass second condition
previous_is_zero = false
votes.each do |x| 
  unless x == 0 
   if previous_is_zero == true
     valid = false
     break
   else
     previous_is_zero = true
  end
end
khelll
Thanks for that - it's looking pretty useful - but where you have params["select#{x}"] - does that mean I need to pass in the hash from the params here? Or do I need to pass in each select item? the actual hash is params[:votes]
Les
What i could understand is that you have 3 html selects, i considered them to be named select1,select2 and select3, you get them from params hash.
khelll
A: 

This sounds like a job for virtual attributes and nested forms as seen in this railscast.

Assuming your form is for a Ballot model that has multiple votes you should be able to do something like:

<%= form_for @ballot do %>
  Choose in order of preference:
  <% for votes in @ballot.votes %>
    <% fields_for "ballot[votes][]", vote do |vote_form| %>
      <%= vote_form.collection_select(:choice, vote.choices, :id %>
    <% end %>
  <% end %>
<% end %>

If everything is active record you could just use that to establish uniqueness via Ballot has_many :votes, :through => :castings, :uniq => true or Casting validates_uniqueness_of. If not I would use select rather than collection_select and then you can remove duplicates by way of #uniq in Ballot#votes=.

Hopefully this is enough to get you started. The full implementation would vary depending on how normalized your data model currently is.

matschaffer