1

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.

Patrick
  • 7,903
  • 11
  • 52
  • 87

3 Answers3

3
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.

Voldy
  • 12,829
  • 8
  • 51
  • 67
1

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. :)

maddening
  • 11
  • 1
  • the answer by Voldy showed a correct approach in 2010. using `validates_uniqueness_of :field, scope: :field2` will validate that a pair of values is unique in the database, additional source [here](http://stackoverflow.com/questions/4870961/rails-validate-uniqueness-of-multiple-columns) and [API docs](http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of) – Mike H-R Feb 11 '14 at 09:45
0

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.

krunal shah
  • 16,089
  • 25
  • 97
  • 143