views:

143

answers:

3

I have an array of ActiveRecord objects, each one which has its own respective errors array. I want to flatten it all out and get only the unique values into one array. So the top level array might look like:

foo0 = Foo.new
foo1 = Foo.new
foo2 = Foo.new
foo3 = Foo.new

arr = [foo0, foo1, foo2, foo3]

Each one of those objects could potentially have an array of errors, and I'd like to get just the unique message out of them and put them in another array, say called error_arr. How would you do it the "Ruby" way?

+1  A: 
require 'set'
error_arr = [foo0, foo1, foo2, foo3].reduce(Set.new) do |set, arr|
  set.merge(arr.errors)
end.to_a

EDIT: This answer works if each foo has an errors array, which is apparently not the case. I'll leave the answer in case someone has a similar issue with real arrays.

Matthew Flaschen
ActiveRecord.errors is not a true array. Merge function will throw an exception if it is merged with a set.
KandadaBoggu
A: 

Try this:

If you want to get the error messages simply in an array then do the following:

def merge_errors(arr)
  [].tap do |errors|
    arr.each{|m| errors += m.errors.full_messages}
  end
end

If you want to get the error messages in ActiveRecord::Errors class, then do the following:

def merge_errors(arr)
  ActiveRecord::Errors.new({}).tap do |all_error|
    arr.each{|model| model.errors.each_full{|m| all_error.add_to_base(m)}
  end
end

Now you can use the function as follows:

arr = [foo0, foo1, foo2, foo3]
errors = merge_errors(arr) 
unless errors.empty?
  # handle error
end
KandadaBoggu
+2  A: 

Code:

arr = [foo0, foo1, foo2, foo3]
arr.map{|record| record.errors.full_messages }.flatten.uniq

I hope this is what you want. The method calls match your description very closely ("flatten", "uniq").

Ragmaanir