how to validate a polymorphic field association in rails? - ruby-on-rails

Here is the question, I have a customer and address model as follows:
class Customer < ActiveRecord::Base
has_one :address, as: :addressable
end
class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
end
I have a customer form with the render address information, for example:
# customers/form
= f.input :name
...
# render form/address
= f.input :apto
= f.input :city
= f.input :references
What I am looking for is to validate the address fields in the customer form, in such a way that if the user does not enter any value then it prevents its creation or update
pdd: The address entity is polymorphic and I can use it in any relationship. But I don't know how to validate its fields when I use it in the form of other relations
If you could help me I would be grateful and thank you very much for taking the time to read me.
UPDATE 22/12/2022
I would like to specifically validate the address fields (apto, city, reference) that are in customers only and not in others entities
Since any other entity can use address and in those entities the fields must be without validation
many thanks to #max who recommended validates_associates, however it validates all addresses

Maybe you are looking for:
validate :validate_fields, if: -> { addressable_type == 'Customer' }

Related

Saving data to first model and using the generated key to save data to other model in Rails

I have a model named Product that belongs to two model namely User and Address.
class Product < ActiveRecord::Base
belongs_to :user
belongs_to :address
validates :title, :description, :user_id, :address_id, presence: true
validates :product_type, numericality:{:greater_than => 0, :less_than_or_equal_to => 2}, presence: true
accepts_nested_attributes_for :address
end
Now the problem is that a user will enter the address at the time of filling up the product information so I do not have an address_id to feed to the Product model. How can I do this? One option is to first save the data in Address model and then use the generated id to feed in to the Product model. Is there any better way to do it?
Lets say I'm first saving the Address model and then the Product model, suppose if the Address model gets saved and User model somehow triggered some exception. How do I rollback the saved address?
Here's my Controller Code :
class Api::V1::ProductsController < ApplicationController
respond_to :json
def create
product = Product.new(params[:product])
if product.save
render json: {success: "success"}, status: 200
end
end
end
You are facing a common issue mate. It is called nested models. You can address this issue with nested forms. There is a really nice video in the RailsCasts talking about that. take a look here. Try that out and let us know.

rails model class with multiple roles

I'm looking a way to implement a multiple role for a class Address (BillingAddress, ShippingAddress e.t.c) by avoiding using a second table address_roles to my project. Is there any possible way?
My Address model below :
class Address < ActiveRecord::Base
self.inheritance_column = nil
serialize :roles
attr_accessible :street, :number, :postal, :city, :country
end
class InstallationAddress < Address
end
class BillingAddress < Address
end
class ShippingAddress < Address
end
I would like to be able to save roles as an Array such as ["BillingAddress", "InstallationAddress"]
Edit 1: How should I describe it in my model in order to work? For example how InstallationAddress.all is going to return me only the addresses that have role InstallationAddress or if I have a belong_to :user , how user.installation_address will be retrieved.
What you have tried is almost correct. is'nt it..?
1) Add a new column "roles" in the Address model.
2) Make roles as serializable in address model (what you have already written).
3) Include a multiple select dropdown in your view page, where you want to place a dropdown.
<%= form.select :roles,
[["BillingAddress","BillingAddress"], ["InstallationAddress","InstallationAddress"]],
:prompt => "Select Roles",
:multiple => true
%>
You need not to have any new model for address_roles. And, I am sorry if you are not expecting the way like this.
Thanks!!

Rails form structure for accepting Primary and Secondary email

I want to have a 'contact person' form that allows a user to enter their Personal and Work email at the same time.
I can imagine two ways of doing this but am not sure they're optimal and may be missing a Rails way of doing so:
Have the nested form create the email model twice, but add a flag for :position to identify them. (Hidden field to do so?)
Set up a delegate that maps :personal_email and :work_email to the Email model such that the model handles them separately.
Something else?
Currently I have emails set up like this:
class Individual < ActiveRecord::Base
attr_accessible :first_name, ...
has_many :emails
#delegate :personal_email, :to => :email, :allow_nil => true
end
class Email < ActiveRecord::Base
attr_accessible :email_address, :owner_id, :owner_klass, :position, :verified, :email_type
belongs_to :individual
# WIP Returns 'primary' email for a user
def personal_email
end
end

How to design model with two, independent and optional relations to the same model?

I've got a problem with designing my User model and making a decent form for it. I just want to ensure myself that I'm doing it wrong :)
So it goes like this:
User has got two Addresses:
a mandatory Address for identification and billing,
an optional shipping Address that he could fill in or leave blank
I tried like this:
class User < ActiveRecord::Base
has_one :address
has_one :shipping_address, :class_name => 'Address', :foreign_key => 'shipping_address_id'
accepts_nested_attributes_for :address
accepts_nested_attributes_for :shipping_address
#validations for user
end
and:
class Address < ActiveRecord::Base
#validations for address
end
And then I make a form for User using form_for and nested fields_for. Like this:
= form_for #user, :url => '...' do |a|
= f.error_messages
...
= fields_for :address, #user.build_address do |a|
...
But then, despite that f.error_messages generates errors for all models, fields for Addresses don't highlight when wrong.
Also I have problems with disabling validation of the second address when the user chose not to fill it in.
And I have doubts that my approach is correct. I mean the has_one relation and overall design of this contraption.
So the question:
Am I doing it wrong? How would You do that in my place?
What is wrong in your form is that it will build a new address every time the view is rendered, thus losing all validation errors.
In your controller, in the new action you should do something like
#user.build_address
and in your view write:
= fields_for :address, #user.address do |a|
Hope this helps.

rails validate a belongs_to relation

Given a simple relationship where Person has_many Telephones. And a telephone only contains a telephonenumber which must be unique!
class Telephone < ActiveRecord::Base
validates_presence_of :contact_id
belongs_to :contact
validates :telephone, {:presence => true, :uniqueness => true}
end
class Contact < ActiveRecord::Base
has_many :telephones
validates_associated :telephones
has_many :emails
has_many :addresses
validates_presence_of :firstname
accepts_nested_attributes_for :telephones, :allow_destroy=>true
validates_presence_of :lastname
end
test "telephone number must be unique" do
john = contacts :johndoe #johndoe is a person with 1 existing number
2.times do
john.telephones.build :telephone=> "123" # 123 doesnt exist yet
end
puts Telephone.count # this gives 1
john.save
puts Telephone.count # this gives 3 !!!! ???
assert not(john.valid?) # This validates unless I remove the save above
end
Can someone explain the outcome of this test.
just calling valid? fails, but that is mentioned in the rdoc (must save first)
saving first does make valid? pass
BUT now I actually have 3 records in the database which breaks my unique requirement.
Is there a better way to do this? I don't understand the outcome of this test, it really goes against my expectations.
Ok if you read the ruby documentation you will notice that they mention that validating a model is not sufficient for uniqueness. YOU MUST use database unique constraints whenever possible. Otherwise it is possible when using two processes/threads/whatever that both will do a validation check, pass as unique, and then insert same values.
tl;dr: Add a unique constraint to the db column.

Resources