views:

54

answers:

2

Hello all,

I am having the following problem:

I have an ActiveRecord model called Widget that has some fields, we'll call them field_a and field_b, in addition to the standard Rails fields. I also have a model called Person that has many widgets through a has_many association (Person.widgets).

In the create action of my controller for Widget, I want to check to make sure that the new Widget I create from the params { @widget = Widget.new(params[:widget]) } does not exist in the Person.widgets collection before saving that new widget to the database but using Person.widgets.include?(@widget) doesn't give me the results that want if field_a and field_b have the same values as a widget in the collection.

I am guessing that this is because the new widget (@widget) technically doesn't exist in that collection because it is a new record even though it's important attributes (field_a and field_b) might match one already in the DB associated with the instance of Person.

Any thoughts on how I might go about checking this so I don't create functionally duplicate widgets in the db associated to the same Person instance? I tried to override the hash, eql? and == methods on the Widget model but that broke some other stuff...thank goodness for TDD! :-)

Thanks, Mike

A: 

Is there a reason you can't just use ActiveRecord::Validations#validates_uniqueness_of?

validates_uniqueness_of :field_a, :scope => [:person_id, :field_b]
validates_uniqueness_of :field_b, :scope => [:person_id, :field_a]

Should do the trick, even if the validation messages may be a little confusing at times. But that's what the :message option for validations is for.

cwninja
Should be able to get by with just `validates_uniqueness_of :person_id, :scope [:field_a, :field_b]` in the Widgets model.
EmFi
That should work too, although default error messages may make your mind melt (as they will all be backwards).
cwninja
A: 
class Widget
  before_save :validate_unique_for_person
  def matches?(w)
    field_a == w.field_a && field_b == w.field_b
  end
  def validate_unique_for_person
    errors.add("base","widget already exists for person") if person.widgets.any? { |w| matches?(w) && self != w }
  end
end
Mike H
Thanks for the help...I was trying to get a little fancy but this did the trick!