Checking whether any of some large collection of attributes has changed I have to check a large number of attributes and do something if any of them have changed. However, right now there are way too many or statements. Is there a better way to do this?   

def check_updates
  if self.post_code_changed? || self.preferred_gender_changed?
    # do something
  elsif self.occupation_changed? || self.date_of_birth_changed? 
        || self.religion_changed? || self.smoke_changed? 
        || self.drink_changed? || self.drugs_changed? 
        || self.diet_changed? || self.looking_for_changed? 
        || self.edu_status_changed? || self.edu_type_changed?
    # do something else
  end
end
(In the following, I'm assuming this is a regular ActiveRecord-derived model class, you're dealing with.)

I'd do something like this for a 1st pass (note that I've elided some of the many attribute names in the array):

def bio_updated?
  [:occupation, :date_of_birth, :religion, ...].any? do |attribute|
    __send__(:"#{attribute}_changed?")
  end
end


after which you can just call self.bio_updated?.

A second pass would be add some more declarative way of handling this at the model class level. E.g. implement something that'd let you write:

class SomeModel &lt; ActiveRecord::Base
  # idea is to write something like
  #
  #   tracked_attributes [group name], [array of attributes]
  #
  # to define stuff
  tracked_attributes :bio, [:occupation, :date_of_birth, :religion, ...]
  tracked_attributes :something_else, [...]
end


Which would do some meta-programming magic to give you a bio_updated? method and a something_else_updated? method (like seen above) you can call. (you may want to stick to *_changed? instead of *_updated? to keep to the Rails convention, though you can also argue that it'd be more confusing, since you're dealing with groups of attributes not single ones. Your call.)

There's probably a gem somewhere that does something like this already.

A middle way would be to abstract the any? matching into a generic method, just to stay DRY:

def bio_updated?
  any_attributes_changed? :occupation, :date_of_birth, :religion, ...
end

def something_else_updated?
  any_attributes_changed? ...
end

private

def any_attributes_changed?(*attrs)
  attrs.any? do |attribute|
    __send__(:"#{attribute}_changed?")
  end
end