How do I validate that has_one association exists? - ruby-on-rails

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

Related

Rails: Polymorphic Relationship needed multiple times for one model. How to differentiate? Is there a better way?

I have a complicated relationship where I have multiple models require addresses. This usually means using a polymorphic relationship like so:
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
end
class User < ApplicationRecord
# no issue, its "addressable" so just use this line of code
has_one :address, as: :addressable
end
class Account < ApplicationRecord
# Ok the issue here is that I need exactly TWO addresses though
# One is for billing and one if a physical address where an event will
# physically take place.
has_one :billing_address, class_name: "Address", as: :addressable
has_one :site_address, class_name: "Address", as: :addressable
end
The problem with this is ...
a = Account.first
a.billing_address #returns an address
a.site_address #returns the same address
How can I get the account to differentiate between two addresses? I know this isn't really a limitation of polymorphism but rather a software design problem that I need to solve. I'm wondering if maybe I need to treat Address as an abstract model and derive BillingAddress and SiteAddress from it and maybe have something like this:
class Address < ApplicationRecord
# see active_record-acts_as gem for how this mixin works
# https://github.com/hzamani/active_record-acts_as
actable
belongs_to :addressable, polymorphic: true
end
class User < ApplicationRecord
# no issue, its "addressable" so just use this line of code
has_one :address, as: :addressable
end
class BillingAddress < ApplicationRecord
acts_as :address
end
class SiteAddress < ApplicationRecord
acts_as :address
end
class Account < ApplicationRecord
has_one :billing_address
has_one :site_address
end
This might be good to do because I also have an Event model which requires a site address so I could do this as well:
class Event < ApplicationRecord
has_one :site_address
end
Is this over engineering? At the risk of sounding too subjective, what are your thoughts on this? Is there a better way to do this?
What separates the address categories? You mention that you may have a billing address and a site address.
If for example the categories are determined by an attribute called 'category', then all you have to do is set a condition on the association declarations on the addressable:
class Account < ApplicationRecord
has_one :billing_address, -> { where category: 'billing' }, class_name: "Address", as: :addressable
has_one :site_address, -> { where category: 'site' }, class_name: "Address", as: :addressable
end

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?

more than one entry saved on has_one association rails

I am trying to create a has_one association among two model.
class User < ActiveRecord::Base
has_one :emergency_contact
end
class EmergencyContact < ActiveRecord::Base
belongs_to :user
end
when i try to test it through rails console more than one entries are saved for the emergency contact model for a single user. Although when i retrieve it using User.emergency_contact only the first entry is returned. When saving how can i make it to rollback for more than one entry
You can simply validate uniqueness of user_id column in EmergencyContact:
class EmergencyContact < ActiveRecord::Base
belongs_to :user
validates_uniqueness_of :user_id, allow_nil: true
end

creating object with nested attributes

i need to create a form, which will create object which has another two objects as attributes, but those objects should be available from a dropdown list that contains templates of those objects.
class User < ActiveRecord::Base
accepts_nested_attributes_for :adresses, :profiles
end
class Address < ActiveRecord::Base
attr_accessible :city, :country
belongs_to :user
end
class Profile < ActiveRecord::Base
attr_accessible :nickname, :password
belongs_to :user
end
tricky part might be, that User has no column 'address_id' or 'profiles_id', everything should go to the Profile and Address, which are being created in the same moment as the User (they have the same attributes as their templates)
I could really use some help, dont expext full code solution, but some hints would be nice
Try this setup:
class User < ActiveRecord::Base
has_one :address
has_one :profile
accepts_nested_attributes_for :address, :profile
attr_accessible :adress_attributes, :profile_attributes
end
class Address < ActiveRecord::Base
attr_accessible :city, :country
belongs_to :user
end
class Profile < ActiveRecord::Base
attr_accessible :nickname, :password
belongs_to :user
end
See doc

Something seems to be broken in my belongs_to, has_one relationship

I have a data model that looks like this:
A customer has subscription_id and setup_id as parameters. In some cases, customer will only have one of the parameters. In other cases, it will have both.
Currently, if I make a new customer through either the subscriptions flow or the setups flow, either Subscription.last or Setup.last will reflect the most recent customer that was created (with customer_id equalling the last customer created)
However, I am having the problem of Customer.setup_id or Custumer.subscription_id being nil in all cases.
Here's my code from both subscription.rb and setup.rb:
class Subscription < ActiveRecord::Base
attr_accessible :status, :customer_id
belongs_to :customer
end
class Setup < ActiveRecord::Base
attr_accessible :status, :customer_id
belongs_to :customer
end
And in customer.rb:
class Customer < ActiveRecord::Base
attr_accessible :email, :name, :stripe_token, :subscription_id, :setup_id, :phone, :plan
has_one :subscription
has_one :setup
end
I'm not sure what I'm doing incorrectly here but I'd love it if the three data models could talk to each other correctly.
Edit: Is it bad that both setup and subscription belong to :user rather than :customer?
Edit 2: Updated the code of setup.rb and subscriptions.rb to correctly reflect the data model currently. And customer.rb is still not recognizing the correct setup_id or subscription_id
class Subscription < ActiveRecord::Base
attr_accessible :status, :customer_id
belongs_to :customer
end
class Setup < ActiveRecord::Base
attr_accessible :status, :customer_id
belongs_to :customer
end
class Customer < ActiveRecord::Base
attr_accessible :email, :name, :stripe_token, :phone, :plan
has_one :subscription
has_one :setup
end
customer = Customer.first
customer.subscription # Instance of Subscription that belongs to customer
customer.setup # Instance of Setup that belongs to customer

Resources