问题
Given the following classes:
class Candidate
has_many :applications
has_many :companies, :through => :job_offers
end
class JobOffer
belongs_to :company
end
class Application
belongs_to :candidate
belongs_to :job_offer
end
How can I validate the previous statement (in the image) on Rails?
Adding the following validation on Application won't work when updating:
def validate_uniqueness_of_candidate_within_company
errors.add(:job_offer_id, "...") if candidate.companies.include?(company)
end
Cause when trying to change the application to a different JobOffer of the same company candidate.companies will return that company.
I also tried doing something like this on Application:
validates_uniqueness_of :user_id, :scope => {:job_offer => :company_id}
But it didn't work either. Any ideas to solve this without having to use 10 lines of crappy code?
回答1:
There are likely many acceptable approaches to solve your issue but I think the bottom line is that you're trying to enforce a uniqueness constraint on the table that doesn't (directly) have all the attributes (both company
AND user
). I'd de-normalize the company
info into the application table (user_id
, job_offer_id
, company_id
) and always set it in a before_save
callback to match the job_offer
's company
. Then you should be able to use the scoped uniqueness validation:
class JobApplication < ActiveRecord::Base
belongs_to :user
belongs_to :job_offer
belongs_to :hiring_company, :class_name=>"Company", :foreign_key=>"company_id"
before_save :set_hiring_company
def set_hiring_company
self.hiring_company = job_offer.hiring_company
end
validates_uniqueness_of :user_id, :scope => :company_id
end
回答2:
this is how I will structure the models:
class Candidate
has_many :applicatons
has_many :job_offers
has_many :offering_companies, :through => :job_offers
end
class Application
belongs_to :candidate
end
class JobOffer
belongs_to :candidate
belongs_to :company
validates_uniqueness_of :candidate_id, :scope => :company_id
end
class Company
end
This should work! Btw. I will call the application something else to avoid the naming confusion( rails already has application.rb
回答3:
As the image points out, a candidate and a job offer will have many applications & a candidate can only apply to one job offer per company. So, validating uniqueness of candidate scoped to a job offer in application might do.
class Candidate
has_many :applications
has_many :job_offers, :through => :applications
end
class JobOffer
belongs_to :company
has_many :applications
has_many :candidates, :through => :applications
end
class Application
belongs_to :candidate
belongs_to :job_offer
validates_uniqueness_of :candidate_id, :scope => :job_offer_id
end
This will prevent an application to be associated to the same candidate for the same job offer. The candidate can apply to other job offers, right?
And as pointed out by @ez., renaming application to something appropriate is better.
Hope this helps.
回答4:
For anyone finding this today. The answer is to check when there are pre-existing (prevents multiple) & skip when the application itself is switching.
def validate_uniqueness_of_candidate_within_company
pre_existing = Application.includes(:candidate).includes(job_offer: :company).
where(companies: { id: self.company.id }).
where(candidates: { id: self.candidate.id })
if pre_existing.present? && (!pre_existing.map(&:id).include? self.id)
errors.add(:job_offer_id, "...")
end
end
来源:https://stackoverflow.com/questions/8965089/validate-uniqueness-of-in-association