validating a belongs_to association - ruby-on-rails

I'm trying to validate a model Student like this;
class Student < ActiveRecord::Base
belongs_to :room
end
I want to ensure that Room is a valid model, and with that I can only save a student only if the room is valid.
I tried to change the association to:
belongs_to :room, :validate => true
But it didnt change the behaviour..
API says:
:validate
If false, don’t validate the associated objects when saving the parent object. false by default.
So I changed the validation to room:
class Room < ActiveRecord::Base
has_many :students, :validate => true
end
but neither options solve for me
any ideas???

Give this a try...
class Student < ActiveRecord::Base
belongs_to :room
validates_associated :room
end
I'm looking at this portion of the API docs: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_associated
Also, be careful not to use that validation on both sides of the association!

Related

How do I validate that has_one association exists?

I have two models Person and Address:
class Person < ApplicationRecord
has_one :address
end
class Address < ApplicationRecord
belongs_to :person
end
How do I validate that each points to the other?
I want to do something similar to:
class Person < ApplicationRecord
has_one :address
validates :address, presence: true
end
Of course this doesn't work because address is not an attribute on Person.
What is the correct way in Rails to ensure that a record has a valid association with another record?
class Person < ApplicationRecord
has_one :address, required: true
end
class Address < ApplicationRecord
belongs_to :person
end
See the required option in the options section of https://apidock.com/rails/v5.2.3/ActiveRecord/Associations/ClassMethods/has_one
belongs_to in Rails 5 is now automatically required so you don't need to put anything different inside of Address.
You need to use validates_associated :address to validate associations

An equivalent to first_or_create on a nested attribute in Rails 4

I'm using a has many through pattern with these 3 models
class User < ActiveRecord::Base
has_many :user_topics
has_many :topics, through: :user_topics
end
class Topic < ActiveRecord::Base
validates_presence_of :name
validates :name, :uniqueness => true
end
class UserTopic < ActiveRecord::Base
belongs_to :user
belongs_to :topic
accepts_nested_attributes_for :topic
end
At the moment a new topic model is trying to be created every time a new user_topic is created. I'd like to create a new topic model only if the topic name doesn't already exist, otherwise if it does, use the existing topic_id.
So something like:
class UserTopic < ActiveRecord::Base
belongs_to :user
belongs_to :topic
accepts_nested_attributes_for :topic, :first_or_create(:name)
end
Is it possible to do something similar to this?

Validate presence of foreign key on associated objects and using collection.build

I'm having the following models:
class Price < ActiveRecord::Base
belongs_to :article, inverse_of: :prices
validates :article_id, presence: true
end
class Article < ActiveRecord::Base
has_many :prices, dependent: :destroy, inverse_of: :article
end
The code when creating them raises validation error when saving (Prices is invalid):
article = Article.new
article.prices.build( { amount: 55.0 } )
article.save! #=> Validation failed: Prices is invalid
So Rails isn't smart enough to save the parent object (Article) before the child objects (Prices) so article_id can be assigned to the price before it is saved.
How do you use validations on the foreign key when using the build function?
It seems like a pretty standard scenario that should work?
(I know you can use database level constraints, but I'm asking about application level validations here)
In Rails way you can do like this
class Article < ActiveRecord::Base
has_many :prices, dependent: :destroy, inverse_of: :article
validates_associated :prices
end
but this is not 100% solution to this.
You can try this gem https://github.com/perfectline/validates_existence

activerecord / db theory - where do I put these fields?

I have the models shown below. I need to store some details that are specific a person and a house (first_viewed:date, opening offer:decimal, etc). I feel like these should belong to the PersonHouse model but I'm not certain enough. Any suggestions?
class Person < ActiveRecord::Base
has_many :houses, through: :person_houses
has_one :favorite_house, through: :person_houses
end
class PersonHouse < ActiveRecord::Base
belongs_to :house
belongs_to :person
end
class House < ActiveRecord::Base
has_many :house_people
has_many :people, through: :person_houses
end
I could do something like this to get all the details but perhaps there is a more effient way.
#house = House.find(1)
#house.house_people.each do |hp|
puts hp.person.name
puts hp.first_viewed
puts #house.address
end
I think your assumption is correct. If the data is relevant to the relationship between a person and a house, then yes it belongs on this model. The only recommendation I would make is to rename this model to a name that better describes what the relationship is. It doesn't have to be the concatenation of the two models it joins. I don't know exactly what the model is going to be ultimately used for, but SelectedHouse, HouseProspect or something along those lines might work.
You can also delegate properties to the house or person models:
class PersonHouse < AR::Base
belongs_to :person
belongs_to :house
delegate :address, :to => :house, :prefix => true
delegate :name, :to => :person, :prefix => true
end
person_house.address
person_house.person_name

How to delete nested objects in Rails3?

How can I delete nested objects in a form? I found out that I need to add :allow_destroy in the parent model at the accepts_nested_attributes_for directive.
Further, I want to restrict the deletion. A nested object only should be deleted, if the parent object is the only one that retains the association.
Example:
class Internship < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company, allow_destroy => true
end
class Company < ActiveRecord::Base
has_many :internships
end
Explanation: A company can host many internships. Therefore, I do not want to delete the company record as long as there is at least one other internship associated with it.
You could use dependent => :destroy
class Internship < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company, allow_destroy => true
end
class Company < ActiveRecord::Base
has_many :internships, :dependent => :destroy
end
If you return false in a before_destroy filter, then the destroy action will be blocked. So we can check to see if there are any internships associated to the company, and block it if so. This is done in the company model.
class Company < ActiveRecord::Base
has_many :internships
before_destroy :ensure_no_internships
private
def ensure_no_internships
return false if self.internships.count > 0
end
end

Resources