Patrick
Patrick

Reputation: 8083

Rails3 - Validate a unique pair of indexes

I created an index in my migrations:

add_index "enrollments", ["student_id", "lecture_id"], :name => "index_enrollments_on_student_id_and_lecture_id", :unique => true

How is it possible to validate this pair of keys in Rails? I tried:

validates_uniqueness_of :enrollment_id, :scope => [:student_id, :lecture_id]

But it doesn't work properly.

Also, I need to find out in a view, if this key already exists, or if it is possible to create a new entry.

Upvotes: 1

Views: 1789

Answers (3)

maddening
maddening

Reputation: 11

Sorry for opening an old thread but since it's 2011 and I still couldn't find a proper validator, I created one myself:

class UniqueSetValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    setup record
    record.errors[attribute] << "- collection of fields [" + @fields + "] is not unique" if record.class.count(:conditions => @conditions) > 0
  end

  def check_validity!
    raise ArgumentError, "Must contain an array of field names' symbols" unless options[:in] && options[:in].respond_to?(:each)
  end

  private

  def setup record
    conditions  = []
    fields      = []

    options[:in].each do |field|
      conditions  |= [ field.to_s + " = '" + record[field].to_s + "'" ]
      fields      |= [ field.to_s ]
    end

    @conditions = conditions.join(" AND ")
    @fields     = fields.join(", ")
  end
end

It seems to work to me. To use it paste the code into:

your_rails_app/lib/unique_set_validator.rb

and enable it in:

your_rails_app/config/application.rb

by adding this line:

config.autoload_paths += %W( #{config.root}/lib  )

Then you can simply use it in your model:

validates :field, :unique_set => [ :field, :field2 ]

It will validate the uniqueness of pair [ :field, :field2 ], and any error would be returned to :field. I haven't tried but it should work for more that 2 fields.

I hope that I didn't messed up anything, and that this will help someone. :)

Upvotes: 1

krunal shah
krunal shah

Reputation: 16339

Try this!

validates_uniqueness_of :enrollment_id, student_id, :scope => [:student_id, :lecture_id], :lecture_id], :message => "combination of enrollment, student and lecture should be unique."

If combination of student and lecture is not unique than you will get message in your error messages.

Update:

validates_uniqueness_of :student_id, :scope => [:lecture_id], :message => "combination of student and lecture should be unique."

The way voldy define in answer that's the correct way.

Upvotes: 0

Voldy
Voldy

Reputation: 12868

class Enrollment < ActiveRecord::Base    
  validates_uniqueness_of :student_id, :scope => :lecture_id
end

If you want to determine in the view before submitting new enrollment that this pair exists then you can use ajax request (I prefer RJS with JQuery) and check it with:

class Enrollment < ActiveRecord::Base    
  def self.pair_exists?(student_id, lecture_id)
    Enrollment.find_all_by_student_id_and_lecture_id(student_id, lecture_id).any?
  end
end

Hope this will help you.

Upvotes: 3

Related Questions