Rails : Displaying associated model validations - ruby-on-rails

I have got three models
class RateCard < ActiveRecord::Base
validate :name, :presence => true, :uniqueness => true
has_many :rate_card_countries, :dependent => :destroy
has_many :rate_card_details, :dependent => :destroy
has_many :countries, :through => :rate_card_countries
end
class RateCardCountry < ActiveRecord::Base
validates :country_id, :presence => true, :uniqueness => true
validates :rate_card_id, :presence => true
belongs_to :rate_card
belongs_to :country
end
class Country < Geography
has_one :rate_card
has_one :rate_card_country
end
In rate_cards_controller i want to create/update rate_cards such that one country should have one rate_card..
For that i have added uniqueness validation in RateCardCountry Model.
And NOw i want to display the error in rate_card_controller while creating/updating rate_cards..
Needed help?

If I understand your intention correctly, you are trying to build a one-to-many relationship between RateCard and Country. In other words- a country will have only one RateCard, and a RateCard can belong to many countries.
Assuming that's the case, you really don't need the RateCardCountry model (which will be useful if you wanted it to be a many-to-many relationship).
You will need to have:
class RateCard < ActiveRecord::Base
validate :name, :presence => true, :uniqueness => true
belongs_to :rate_card
end
And make sure you have county_id foreign key in the RateCard table.
and then:
class Country < ActiveRecord::Base
has_one :rate_card
end
Also, it seems that right now you have:
class Country < Geography
I am not sure if you are subclassing from a Geography class, as you have not provided the rest of the code.
Hope that helps.

Related

How to validate person's address only if person doesn't belong to company?

In my Rails 5 app I have the following setup:
class Client < ApplicationRecord
has_one :address, :as => :addressable, :dependent => :destroy
accepts_nested_attributes_for :address, :allow_destroy => true
end
class Company < Client
has_many :people
end
class Person < Client
belongs_to :company
end
class Address < ApplicationRecord
belongs_to :addressable, :polymorphic => true
validates :city, :presence => true
validates :postal_code, :presence => true
end
A person can belong to a company but doesn't necessarily have to.
Now I want to validate a person's address only if that person doesn't belong to a company. How can this be done?
There might be other approaches as well, but based on my experience, something like this should work.
validates :address, :presence => true, if: -> {!company}
Hope this helps.
Validations can take either an if or unless argument, which accept a method, proc or string to determine whether or not to run the validation.
In your case:
validates :address, presence: true, unless: :company
Update according to comments
The above only takes care of skipping the validation itself, but due to accepts_nested_attributes_for OP still saw errors when trying to persist a missing address. This solved it:
accepts_nested_attributes_for :address, reject_if: :company_id
Nabin's answer is good but wanted to show another way.
validate :address_is_present_if_no_company
def address_is_present_if_no_company
return if !company_id || address
errors.add(:address, "is blank")
end

validate uniqueness of field in scope

I have a user model which has a polymorphic relationship to teachers, students, and admin. These three types of users each belong to a school. I would like to have it so the username of the user is unique within a school. How would I write the validations to accomplish this?
Here is what my models look like:
class User < ActiveRecord::Base
belongs_to :profileable, :polymorphic => true
delegate :school, :to => :profileable
end
class Student < ActiveRecord::Base
belongs_to :school
has_one :user, :as => :profileable
delegate :name, :username, :to => :user
end
class Teacher < ActiveRecord::Base
belongs_to :school
has_one :user, :as => :profileable
delegate :name, :username, :to => :user
end
class Admin < ActiveRecord::Base
belongs_to :school
has_one :user, :as => :profileable
delegate :name, :username, :to => :user
end
I'm quite sure you will need to use a custom validator for this. The delegated attribute will not be usable in the User model. What you could do is also include the school_id in the User method and set it using before_validate every time. Then you'd be able to use the "simple" uniqueness validator:
validates :username, :uniqueness => {:scope => :school_id}
However, a custom validator joining the school_id of the profileable parent would probably be a cleaner way to go.

how to set unique attribute in a model row

I have a model Competitor like this
class Competitor < ActiveRecord::Base
belongs_to :admin_user
has_many :companies
attr_accessible :admin_user_id, :c1, :c2, :c3, :c4, :c5
validates :admin_user_id, :presence => true
validates_uniqueness_of :admin_user_id, :message => "This user has yet a competitors list"
end
C1, c2,.. are the id of companies. Selected from a drop down list. How can I validate the uniqueness of a row?
(i.e. is not possible to have two or more equals companies for an admin user BUT they can be empties).
You could write your own validation method that would enforce this.
class Competitor < ActiveRecord::Base
belongs_to :admin_user
has_many :companies
attr_accessible :admin_user_id, :c1, :c2, :c3, :c4, :c5
validates :admin_user_id, :presence => true
validates_uniqueness_of :admin_user_id, :message => "This user has yet a competitors list"
validate :check_companies
def check_companies
#[do your checks]
end
end

Last with a custom column name

I have my model defined like this:
class Animal < ActiveRecord::Base
mount_uploader :picture, PictureUploader
attr_accessible :picture, :born_date, :father_id, :mother_id, :name, :obs, :earring, :animal_type, :animal_type_id, :inseminations
validates :name, :born_date, :presence => true
validates :earring, :presence => true, :if => :should_have_earring?
belongs_to :father, :class_name => "Animal"
belongs_to :mother, :class_name => "Animal"
belongs_to :animal_type
has_one :birth
has_one :sell
has_one :death
has_many :inseminations
end
and
class Insemination < ActiveRecord::Base
attr_accessible :bull_id, :cow_id, :done, :expected_birth_date, :expected_dry_date, :insemination_date, :obs, :rut
validates :bull_id, :presence => true
validates :cow_id, :presence => true
validates :insemination_date, :presence => true
belongs_to :bull, :class_name => "Animal"
belongs_to :cow, :class_name => "Animal"
has_one :birth
has_one :abortion
has_one :dry
end
Good, somewhere, I want to get the last insemination from some animal... so, I do #animal.inseminations.last, it should work, but, it does the select using a animal_id property, that does not exist in insemination model. So I get an error like this:
Mysql2::Error: Unknown column 'inseminations.animal_id' in 'where
clause': SELECT inseminations.* FROM inseminations WHERE
inseminations.animal_id = 1 ORDER BY inseminations.id DESC
LIMIT 1
How can I specify it to searh in cow_id and/or bull_id columns? Is that possible?
Thanks in advance.
I think you have a few different options:
1) Instead of using has_many :inseminations, create two separate has many relationships:
has_many :cow_inseminations, :class_name => 'Insemination', :foreign_key => 'cow_id'
has_many :bull_inseminations, :class_name => 'Insemination', :foreign_key => 'bull_id'
2) Use STI and create subclasses of Animal. You will need to add a type field to Animal for this to work:
class Cow < Animal
has_many :inseminations, :foreign_key => 'cow_id'
end
class Bull < Animal
has_many :inseminations, :foreign_key => 'bull_id'
end
Then you can do Bull.first.inseminations or Cow.first.inseminations
You can specify a foreign key:
has_many :inseminations, :foreign_key => :bull_id
However you can only have one foreign_key, so it doesn't work for the cows.
You can do something like Rails Model has_many with multiple foreign_keys to get it to work. But then in this case, you need:
has_many :bull_inseminations, :foreign_key => :bull_id
has_many :cow_inseminations, :foreign_key => :cow_id
def inseminations
# not sure how you store animal type, but something like
return bull_inseminations if animal_type == "bull"
return cow_inseminations if animal_type == "cow"
end
For other attribute methods, you will need to do something similar if you want to use them, eg:
def inseminations_changed?
bull_inseminations_changed? or cow_inseminations_changed?
end
and similarly with inseminations<<, inseminations=, etc.

Join model not getting created properly using accepts_nested_attributes_for

I have a User model and a Project model joined with the Ownership model using has_many :through. I am trying to set an Ownership attribute's value as I create an association between a User and a Project by using accepts_nested_attributes_for.
Here is my User model:
class User < ActiveRecord::Base
attr_accessible :name, :email, :admin, :projects
has_many :ownerships
has_many :projects, :through => :ownerships
accepts_nested_attributes_for :projects
Here is my ownership model:
class Ownership < ActiveRecord::Base
attr_accessible :owner_type
belongs_to :project
belongs_to :user
validates :user_id, :presence => true
validates :project_id, :presence => true
validates :owner_type, :presence => true
end
and my project model:
class Project < ActiveRecord::Base
attr_accessible :name, :description
has_many :ownerships
has_many :users, :through => :ownerships
and this is how I'm trying to set the owner_type value of the ownership model as its being created:
current_user.ownerships.create(:owner_type => 'designer', :project => #project)
for some reason this isn't creating the ownership join model or (obviously) setting the owner_type value of the ownership model. What can I do to fix this?

Resources