When using the globalize gem with Active Record enums, I get an error, as if globalize doesn't know that the enum exists.
class Stuff < ActiveRecord::Base
enum stuff_type: { one: 1, two: 2 }
translates :name
validates :name, presence: true, uniqueness { case_sensitive: false, scope: :stuff_type }
default_scope do
includes(:translations)
end
end
If I do:
s = Stuff.new(name: 'stuff')
s.one!
I get an error as the following:
ActiveRecord::StatementInvalid: PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: "one"
This happens because of the validation, cause it seems like globalize doesn't understand the enum.
Am I doing something wrong? How should I accomplish this?
The solution was to create my own validation method!
Something like:
validate :name_by_type
def name_by_type
max_occurrences = persisted? ? 1 : 0
occurrences = Stuff.where(stuff_type: stuff_type, name: name).count
errors['name'] << 'Name already in use' if occurrences > max_occurrences
end
Related
In a Rails 6 app, I have the Course model with 3 attributes: instructor_id, year, and tag.
If there a way to make a course with a tag invalid if there isn't an already defined course having the same value as year for the same instructor_id?
For instance, with the following courses table.
|instructor_id|year|tag|
|1 |2019| |
The following statements are all correct
Course.new(instructor_id: 1, tag: 2019).valid? #=> true
Course.new(instructor_id: 1, tag: 2020).valid? #=> false
Or should I write a custom validator for that?
To clarify, here my custom validator
class Course < ApplicationRecord
validates :tag, referential_integrity: { reference: :year, scope: :instructor },
allow_nil: true
end
class ReferentialIntegrityValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors.add(attribute, :required) unless record.class.find_by(options[:scope] => record.send(options[:scope]),
options[:reference] => value)
end
end
Can I achieve the same suing built-in validation?
Maybe you are looking for a validation like this or similar with year instead of tag
validates :instructor_id, uniqueness: { scope: [:tag] }
I'm having problems with the validate_inclusion_of matcher when writing a spec.
My current specs are to do with users and user groups. A user has a user group id.
I want to check that the user group id of a user is actually in the list of current user group ids.
At the moment my spec is basically:
describe 'company_user_group list of valid IDs' do
let!(:company_user_group_everything) { FactoryGirl.create(:company_user_group_everything) }
let!(:company_user_group_nothing) { FactoryGirl.create(:company_user_group_nothing) }
it '' do
#company_user = FactoryGirl.create(:company_user, id: 1)
CompanyUser.current_id = #company_user.id
is_expected.to validate_inclusion_of(:company_user_group_id).in_array(CompanyUserGroup.full_list_of_ids)
end
end
but the error I get is:
1) CompanyUser validations company_user_group list of valid IDs should validate that :company_user_group_id is either ‹2› or ‹3›
Failure/Error: is_expected.to validate_inclusion_of(:company_user_group_id).in_array(CompanyUserGroup.full_list_of_ids)
NoMethodError:
undefined method `attribute_setter' for nil:NilClass
I have tried various different things and debugged using byebug etc. but nothing is working for me.
e.g.
Adding in
#company_user_group_id = #company_user.company_user_group_id
and changing the is_expected.to line to
is_expected.to validate_inclusion_of(#company_user_group_id).in_array(CompanyUserGroup.full_list_of_ids)
I get the following error
1) CompanyUser validations company_user_group list of valid IDs should validate that :8 is either ‹8› or ‹9›
Failure/Error: is_expected.to validate_inclusion_of(#company_user_group_id).in_array(CompanyUserGroup.full_list_of_ids)
Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeDoesNotExistError:
The matcher attempted to set :8 on the CompanyUser to 8, but that
attribute does not exist
So it seems that the group id to check is valid (e.g. 8) and the array is valid (e.g. 8 and 9) but the matching isn't working.
Any help much appreciated!
Some of the company user model
# This model holds User identities for internal staff. This model is
# primarily intended for use in the xxxx application.
class CompanyUser LT ActiveRecord::Base
acts_as_authentic do |c|
c.merge_validates_uniqueness_of_email_field_options case_sensitive: false
c.merge_validates_length_of_password_field_options minimum: 8
if Rails.env.production?
c.logged_in_timeout = 30.minutes
else
c.logged_in_timeout = 90.minutes
end
end
# Constants
# relationships
belongs_to :company_user_group
# validations
validates :first_name, presence: true, length: { maximum: 20 }
validates :last_name, presence: true, length: { maximum: 20 }
validates :company_user_group_id, presence: true, numericality: { only_integer: true, greater_than: 0 }
validates :company_user_group_id, inclusion: { in: CompanyUserGroup.full_list_of_ids }, unless: 'Rails.env.test?'
validate :check_sys_admin_permission
If the "unless: 'Rails.env.test?'" bit is removed, most of the specs fail for some unknown reason. Just mentioned in case it is relevant.
and the following method from the Company Group model
# class methods
def self.full_list_of_ids
CompanyUserGroup.all.pluck(:id)
end
I think you want something like this:
it '' do
#company_user = FactoryGirl.create(:company_user, id: 1)
#company_user.company_user_group = company_user_group_everything
expect(#company_user).to validate_inclusion_of(:company_user_group_id).in_array(CompanyUserGroup.full_list_of_ids)
end
You might not even need to set the company user gropu of the company user.
But you've got
validates :company_user_group_id, inclusion: { in: CompanyUserGroup.full_list_of_ids }, unless: 'Rails.env.test?'
Which surely means it would fail because you don't do that in the test environment
I have figured it out. For some reason the validate_inclusion_of works when it is within a let! block.
It doesn't matter what argument is sent to the let helper method, just that one is.
Still don't know WHY this fixes it though, if anybody can enlighten me!?
So, the following spec now passes
describe 'company_user_group list of valid IDs' do
let!(:company_user_group_everything) { FactoryGirl.create(:company_user_group_everything) }
let!(:company_user_group_nothing) { FactoryGirl.create(:company_user_group_nothing) }
let!(:temp) do
it {is_expected.to validate_inclusion_of(:company_user_group_id).in_array(CompanyUserGroup.full_list_of_ids)}
end
end
Hi I have an array column in my model:
t.text :sphare, array: true, default: []
And I want to validate that it includes only the elements from the list ("Good", "Bad", "Neutral")
My first try was:
validates_inclusion_of :sphare, in: [ ["Good"], ["Bad"], ["Neutral"] ]
But when I wanted to create objects with more then one value in sphare ex(["Good", "Bad"] the validator cut it to just ["Good"].
My question is:
How to write a validation that will check only the values of the passed array, without comparing it to fix examples?
Edit added part of my FactoryGirl and test that failds:
Part of my FactoryGirl:
sphare ["Good", "Bad"]
and my rspec test:
it "is not valid with wrong sphare" do
expect(build(:skill, sphare: ["Alibaba"])).to_not be_valid
end
it "is valid with proper sphare" do
proper_sphare = ["Good", "Bad", "Neutral"]
expect(build(:skill, sphare: [proper_sphare.sample])).to be_valid
end
Do it this way:
validates :sphare, inclusion: { in: ["Good", "Bad", "Neutral"] }
or, you can be fancy by using the short form of creating the array of strings: %w(Good Bad Neutral):
validates :sphare, inclusion: { in: %w(Good Bad Neutral) }
See the Rails Documentation for more usage and example of inclusion.
Update
As the Rails built-in validator does not fit your requirement, you can add a custom validator in your model like following:
validate :correct_sphare_types
private
def correct_sphare_types
if self.sphare.blank?
errors.add(:sphare, "sphare is blank/invalid")
elsif self.sphare.detect { |s| !(%w(Good Bad Neutral).include? s) }
errors.add(:sphare, "sphare is invalid")
end
end
You can implement your own ArrayInclusionValidator:
# app/validators/array_inclusion_validator.rb
class ArrayInclusionValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
# your code here
record.errors.add(attribute, "#{attribute_name} is not included in the list")
end
end
In the model it looks like this:
# app/models/model.rb
class YourModel < ApplicationRecord
ALLOWED_TYPES = %w[one two three]
validates :type_of_anything, array_inclusion: { in: ALLOWED_TYPES }
end
Examples can be found here:
https://github.com/sciencehistory/kithe/blob/master/app/validators/array_inclusion_validator.rb
https://gist.github.com/bbugh/fadf8c65b7f4d3eaa55e64acfc563ab2
I'm new to RoR. I'm facing a problem when using validates_uniqueness_of. I've a table with 3 columns:
name || father_name || dob
Vimal Raj || Selvam || 1985-08-30
I've a code in my model like this:
class Candidate < ActiveRecord::Base
attr_accessible :dob, :father_name, :name
validates_uniqueness_of :name, scope: [:father_name, :dob], case_sensitive: false,
message: ": %{value} already present in the database!!!"
before_save :capitalize_name, :capitalize_father_name
private
def capitalize_name
self.name.capitalize!
end
def capitalize_father_name
self.father_name.capitalize!
end
end
It throws error as expected when I insert => "vimal raj, Selvam, 1985-08-30"
But it is accepting the following data => "Vimal Raj, selvam, 1985-08-30" . I was expecting it will throw an error, but unexpectedly it accepts the record and inserts into the db as a new record.
Please help me on how to solve this.
If you want a one-liner solution, please try this :
before_validation lambda {self.name.capitalize!; self.father_name.capitalize!}
Hope, it will help.
I think the case_sensitivity is only matching on name, not on father_name. I would try changing before_save to before_validation so that both name and father_name are consistently the same capitalization when your validation is evaluated.
I just updated from rails 2.3 to 3, i'm trying to replace this old method with something cleaner, because it's outputting the model and field name, wtf!
However I get the above error when calling validates_uniqueness_of (the presence works fine). I passed in the primary id scope, and still get it. Any help is welcome.
def validate
if org_name.blank?
errors.add(:org_name, :blank, :default => nil)
else
if (org = Organization.find_by_org_name(org_name)) && org != self
errors.add(:org_name, :taken, :default => nil, :value => org_name)
end
end
end
to
validates :org_name, :presence => true
validates_uniqueness_of :org_name, :scope => :org_id
Ths is the Rails 3 syntax for uniqueness validtion:
validates :org_name, uniqueness: {scope: :org_id}
This is easy to fix.
Firstly, analyse the error message:
Org name translation missing:
en.activerecord.errors.models.user.attributes.org_name.blank
This is caused by the following line of code:
errors.add(:org_name, :blank, :default => nil)
When you call the above, you are telling rails to look for a translation whose key is :blank. You probably didn't set that up yet, so to do that, just go into your locales file (config/locales/en.yml), and add the following:
en:
hello: "Hello world"
activerecord:
errors:
models:
organization:
attributes:
org_name:
blank: "can't be blank."
Hopefully that will fix it for you.