need a way to use sort_by with possible nil values

In my view, I do a

<%= render :partial => 'person', :collection =>
@household.people.sort_by(&:birthday) %>

household has a has_many relationship with person, and this works fine
until...

an errant user creates a new person and tries to save without filling
the fields(day, month, and year). After this the birthday field is
created and fails horribly. Is there any way to delete blank records
as part of the validation??

Thanks

Bob <bsm2th@gmail.com>

What do you mean "as part of the validation"? Which validation? What
records do you want to delete? Why allow them to save if they're not
valid?

There are lots of ways you can stop the errors though - it just
depends which direction you want to approach it:
* You could add validation to the Person model to make birthday mandatory.
* You could add a method to Person called "birthday" which returns
the birthday attribute or a dummy date (you could call this method
"birthday_for_sort" - to make it clear what its purpose is, and to
maintain the AR method for )
* you could remove records from the people collection before the sort_by:
     @household.people.delete_if { |p| p.birthday.blank? }.sort_by(&:birthday)
* you could add a fake dob value before the sort_by:
     @household.people.each { |p| p.birthday = "1 Jan 1900" if
p.birthday.bllank? }.sort_by(&:birthday)

and more ways to crack the nut...
Some of them smell more than others - depends, as ever, on what you
actually want to achieve... but maybe you can get some idea of how to
sort your problem.

HTH

You could use 'accepts_nested_attributes_for' in your parent model:

accepts_nested_attributes_for :children_models,
    :allow_destroy => true,
    :reject_if => proc {|attributes|
attributes['your_attribute'].blank?}

The 'reject_if' is what does the trick.

While I'm not contradicting the responses from Michael and pepe, I'm going to lead you a different way.

First, I'll suggest that you don't have this level of code in your view. Put a method on your Household model that returns the people in the proper order. Your view code then becomes:

<%= render :partial => 'person', :collection => @household.people_by_birthday %>

(Which in later version of Rails can be
  just <%= render @household.people_by_birthday %> )

Second, use one of the methods given by Michael or pepe to keep persons having invalid (or missing) birthdays from being created.

Finally, as a possible implementation of the #people_by_birthday method (note that I'm assuming that there's a #name method on which to sort the persons having no birthday):

class Household
   def people_by_birthday
     list = self.people.partition {|person| person.birthday.blank?}
     list[1].sort_by(&:birthday) + list[0].sort_by(&:name)
   end
end

-Rob

Rob Biedenharn
Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/
rab@GaslightSoftware.com http://GaslightSoftware.com/

Michael Pavling wrote:

Is there any way to delete blank records as part of the validation??

What do you mean "as part of the validation"? Which validation? What
records do you want to delete? Why allow them to save if they're not
valid?

There are lots of ways you can stop the errors though - it just
depends which direction you want to approach it:
* You could add validation to the Person model to make birthday
mandatory.
* You could add a method to Person called "birthday" which returns
the birthday attribute or a dummy date (you could call this method
"birthday_for_sort" - to make it clear what its purpose is, and to
maintain the AR method for )
* you could remove records from the people collection before the
sort_by:
     @household.people.delete_if { |p| p.birthday.blank?
}.sort_by(&:birthday)
* you could add a fake dob value before the sort_by:
     @household.people.each { |p| p.birthday = "1 Jan 1900" if
p.birthday.bllank? }.sort_by(&:birthday)

and more ways to crack the nut...
Some of them smell more than others - depends, as ever, on what you
actually want to achieve... but maybe you can get some idea of how to
sort your problem.

HTH

Sorry, not enough information.. again..

My view has 4 fields for new records: sex month, day, and year. It also
has a new person link that creates as many new empty records as needed.
After the 'Save Changes' link is clicked, my controller then validates
these fields and makes a birthday field using whatever is entered (
Sounds like I should put this action in the model ). The problem comes
if a new person record is left without any data. It looks like the model
isn't saving these empty records, but they are still in the
@household.people collection, killing a call to sort_by. All this
trouble to put the birthdays in order..

Thanks

Bob <bsm2th@gmail.com>

After the 'Save Changes' link is clicked, my controller then validates
these fields and makes a birthday field using whatever is entered

Your controller shouldn't be doing any "validation" - the model should
be doing that (but maybe you mean the controller is ensuring
"Person.valid?" ?)

Sounds like I should put this action in the model

ah... yes, you should really

if a new person record is left without any data. It looks like the model
isn't saving these empty records, but they are still in the
@household.people collection

So try to see how my suggestion of using .delete_if (or .reject) on
the collection to remove invalid items works for you:
   @household.people.reject { |person| !person.valid? }

Rob Biedenharn wrote:

class Household
   def people_by_birthday
     list = self.people.partition {|person| person.birthday.blank?}
     list[1].sort_by(&:birthday) + list[0].sort_by(&:name)
   end
end

-Rob

This is the method I ended up with, almost.. I did

  def people_by_birthday
     list = self.people.partition {|person| person.birthday.blank?}
     list[1].sort_by(&:birthday)# + list[0].sort_by(&:name)
     return list[1]
  end

I had no use for the empty part of the partition, do it left.. Works
perfectly.
Only problem now is that clearing empty dates trips the error message
from failed validations.

Thanks a lot

Bob