[rspec-users] Validations based on associations

David Chelimsky dchelimsky at gmail.com
Mon Jan 1 09:07:18 EST 2007

On 1/1/07, Pat Maddox <pergesu at gmail.com> wrote:
> My model is very simple, it's mostly just a join table that represents
> which tournaments a user has registered for.
> class Registration < ActiveRecord::Base
>   belongs_to :user
>   belongs_to :tournament
>   validates_presence_of :user_id, :tournament_id
>   validates_uniqueness_of :user_id, :scope => :tournament_id
> end
> the validates_uniqueness checks to make sure there's no record that
> has the same user_id and tournament_id.
> Is there a relatively easy way to specify this behavior?  The only way
> that I know is to do something like
> context "A Registration with a User and Tournament" do
>   setup do
>     @user = User.new
>     @user.save false
>     @tournament = Tournament.new
>     @tournament.save false
>     @reg = Registration.new(:user => @user, :tournament => @tournament)
>   end
>   specify "should be valid" do
>     @reg.should_be_valid
>   end
>   specify "should not be valid if a registration with the same details
> already exists" do
>     @reg.save
>     Registration.new(:user => @user, :tournament =>
> @tournament).should_not_be_valid
>   end
> end

Geez, ActiveRecord models are SUCH a violation of SRP! I realize that
this is the rails way, and that there are great productivity benefits
we glean from AR, but having a model that validates both at both the
instance level (validates_presence_of) and the class level
(validates_uniqueness_of) is a pain in the ass. It's confusing because
both sorts of validations look the same, but they are really
fundamentally different.

Ranting aside, there are a couple of different ways you can view this.
To be the most clear, I'd probably spec the class level validations
separately from instance level validations. The uniqueness spec might
look like this:

context "The Registration model class" do
  setup do
    @user1 = User.new
    @user2 = User.new
    @tournament = Tournament.new

    [@user1, @user2, @tournament].each {|model| model.save(false)}

  specify "should permit registrations with different users" do
    Registration.create(:user => @user1, :tournament => @tournament)
    Registration.new(:user => @user2, :tournament =>

  specify "should deny multiple registrations with the same user" do
    Registration.create(:user => @user1, :tournament => @tournament)
    Registration.new(:user => @user1, :tournament =>


> Well actually that's obviously pretty easy :)  Is it bad that I'm tied
> to the implementations of User and Tournament at all?  ActiveRecord
> dictates that, so I guess it's not a problem to have that in my spec
> at all.
> Anyway this is just the spec I came up with and I'm wondering if
> anyone else has a better idea.
> Pat
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

More information about the rspec-users mailing list