Ruby on Rails: Getting validates_uniqueness_of to work - ruby-on-rails

I have two params :work and :grade. In the model, before saving I want to use validates_uniqueness_of to check given a unique work, there is only one grade. Grade can be the same for other work. How would I write this?
Edit:
validates_uniqueness_of :work, :scope => :grade

If you have a deprecated syntax warning, you can write it so:
validates :work, uniqueness: {scope: :grade}, presence: true
Edit:
It seems you need a two way checking, so perhaps adding this will work:
validates :grade, uniqueness: {scope: :work}, presence: true
Although under high load I've seen this fail, so best is to create a database constraint.

Related

validate vs validate_uniquess_of?

Is there a difference between using
validates :foo, uniqueness: true
or
validates_uniqueness_of :foo?
I know this is a simple questions, but Google didn't help
When and why should one be used over the other?
The validates method is a shortcut to all the default validators that Rails provides. So, validates :foo, uniqueness: true would trigger UniquenessValidator under the hood. The source code for validates can be found in the API doc here. As shown there, it basically triggers the validators of the options passed and raises an error in case an invalid option is passed.
validates_uniqueness_of also triggers the UniquenessValidator, the same as validates. Its source code is
# File activerecord/lib/active_record/validations/uniqueness.rb, line 233
def validates_uniqueness_of(*attr_names)
validates_with UniquenessValidator, _merge_attributes(attr_names)
end
The only difference is that with validates_uniqueness_of, we can ONLY validate the uniqueness and not pass additional options, whereas validates accepts multiple options. So we could have the following validations with validates:
validates :name, presence: true, uniqueness: true, <some other options>
But the same would not be possible with validates_uniqueness_of.

Pass validation context to associated model

I'm using contexts to invoke specific validations at different points in the model lifecycle:
model Address
validates :city, presence: true
validates :street, presence: true, on: :send_letter
end
incomplete_address = Address.new(city: 'Berlin')
incomplete_address.valid? # => true
incomplete_address.valid?(:send_letter) # => false
This works fine for the simple case above. But, as far as I can tell, the context is ignored for any associated objects:
model Address
belongs_to :country
validates :street, presence: true, on: :send_letter
validates_associated :country
end
model Country
has_many :addresses
validates :iso_alpha_3, presence: true, size: 3, on: :send_letter
end
incomplete_address = Address.new(street: 'Oranienstr', country: Country.new(name: 'Germany', iso_alpha_3: 'Invalid iso code')
incomplete_address.valid? # => true
incomplete_address.valid?(:send_letter) # => true
incomplete_address.country.valid?(:send_letter) => false
Question: Is this expected behaviour, or is it a bug I'm hitting? Or am I making a conceptual mistake? What's the most elegant way to validate associated models under such circumstances?
I know this question is 3 years old but there is a slightly easier path now and an an even easier option on the horizon.
There is currently an outstanding PR that adds this functionality via a configuration option on the validates_associated call. In the meantime, you can add that version of AssociatedValidator as a separate validator (e.g. AssociatedPreservingContextValidator) and call validate_with AssociatedPreservingContextValidator, :country in `Address.
Is the expected behaviour, validators are executed only in the current model.
You can achieve the desired result using a custom method validator.
You can find more informations here

Rails 4 validate uniqueness with hash scope deprecated

In Rails 3.2 I have this syntax:
validates_uniqueness_of :sport_name, :scope => :sports_org_id
This is now deprecated in rails 4 but i can't figure out the new syntax. I want to validate both presence and uniqueness for a data field.
how about this ?
validates :sport_name, uniqueness: {scope: :sports_org_id}, presence: true
See The Rails Guides for more info. Your syntax dates from rails 2 !
EDIT
You can now also use the allow_blank option instead of a presence validation, which makes for nicer error messages :
validates :sport_name, uniqueness: {scope: :sports_org_id, allow_blank: false}

Best way to check if a username exists in a model

I'm quite new to ruby/rails. I was wondering what is the best way to ensure that two people don't choose the same username. Here is my model at the moment:
class User < ActiveRecord::Base
validates :username, :presence => true
validates :password, :presence => true, :length => { :minimum => 7}
end
Note: I'm assuming it is best to place this type of code in the model. Correct me if I'm wrong.
There's a validation to make sure a field is unique. Just change your username validation to:
validates :username, :presence => true, :uniqueness => true
You should also add an index to your usertable, with uniqueness. This way, if people quickly press the username register button twice, you will also be protected at the database level
add_index :users, :username, :unique => true
This question has already been correctly answered but for future reference, APIDock has excellent Rails documentation here: http://apidock.com/rails. The search's autocomplete is fantastic.
The documentation for the validates method is here: http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates where you can find the :uniqueness => true option.

Rails - force field uppercase and validate uniquely

Airports have four-letter ICAO codes. By convention, these are always uppercase. I'm creating a form for receiving user input, but this form needs to be able to accept user input in mixed case, and prevent them from creating dupes.
The default :uniqueness is case-sensitive, of course. I figured out how to transform the user's input to uppercase before it gets saved, but the problem is that this appears to be post-validation, instead of pre-validation.
For example, if there is already an Airport with ICAO of KLAX, a user can enter klax, it will get validated as unique, and then transformed to uppercase and stored, resulting in duplicates.
Here's my model code at present.
class Airport < ActiveRecord::Base
validates :icao, :name, :lat, :lon, :presence => true
validates :icao, :uniqueness => true
before_save :uppercase_icao
def uppercase_icao
icao.upcase!
end
end
Or a slightly different take: Write a setter for icao that converts anything thrown at it to uppercase:
def icao=(val)
self[:icao] = val.upcase
end
And then you can use regular uniqueness validation (back it up with a unique index in your DB). Might even make things a little easier for the DB during finds, 'cause it doesn't have to worry about case-insensitive comparisons any more.
Hope this helps!
try this:
validates :icao, :uniqueness => { :case_sensitive => false }
Updated answer for Rails 4.
class Airport < ActiveRecord::Base
validates :icao, :name, :lat, :lon, :presence => true
validates :icao, :uniqueness => { case_sensitive: false }
def icao=(val)
write_attribute :icao, val.upcase
end
end
Simply fixed (as many problems with Rails are) - as Danny pointed out above, although not in his own answer so I can't accept it :), changing before_save to before_validation fixes it perfectly.

Resources