Noz
Noz

Reputation: 6346

Rails Pass A Parameter To Conditional Validation

I'm importing heaps of student data from an spreadsheet document. Each row of student data will represent a new user, however, the possibility of importing an already existing student exists and I want to bypass some of my user validations such as username uniqueness accordingly so that I can build associations for both new and existing records, but only if they're being imported to the same school.

Thus far I have the following validation setup in my User model:

user.rb

validates_uniqueness_of :username, :unless => :not_unique_to_school?

def not_unique_to_school?
  user = find_by_username(self.username)
  user.present? && user.school_id == 6
end

Now how would I go about replacing that 6 with a value I have access to in the controller? Instructors will be the ones handling the importing and they'll be importing students to their school so I would typically run current_user.school_id to retrieve the school id that I want them to be imported to, but I don't have access to the current_user helper in my model.

I'm not concerned about duplicating usernames as I'll be handling that on a different step, this is just the preliminary validation.


Edit

Simplified school & user model:

user.rb

class User < ActiveRecord::Base    

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me, :username, 
                  :first_name, :last_name, :school_id, :roles_mask

  belongs_to :school

  validates_presence_of :username, :on => :create, :message => "can't be blank"
  validates_uniqueness_of :username, :unless => :unique_to_school?

  def unique_to_school?
    user = find_by_username(self.username)
    user.present? && user.school_id == 6
  end 

  def find_by_username(username)
    User.where(:username => username).first
  end     

end

school.rb

class School < ActiveRecord::Base
  attr_accessible :country_id, :name, :state_id

  has_many :users    

end

Upvotes: 1

Views: 2974

Answers (2)

Noz
Noz

Reputation: 6346

Here's what ended up working for me:

validate :user_cant_be_duplicate_in_other_schools  

def user_cant_be_duplicate_in_other_schools
    errors.add(:username, :taken) if User.count(:conditions => ["school_id != ? AND username = ?", self.school_id, self.username]) > 0
end  

As opposed to testing if a User belongs to a particular school we're testing for the lack of belonging to a particular school. I didn't come up with this answer, another user posted this as an answer but deleted it shortly after for reasons unknown.

Upvotes: 1

Alex Peattie
Alex Peattie

Reputation: 27657

I'd add a method to your School model:

def student_named?(name)
  self.users.where(:username => name).any?
end

then in your validation:

def not_unique_to_school?
  self.school.student_named?(self.username)
end

Upvotes: 4

Related Questions