Add Model Validation {Rails} - ruby-on-rails

I have two model association as follows:
Survey_question and survey_answer.
Survey_question Model
class SurveyAnswer < ApplicationRecord
belongs_to :survey_question
validates_presence_of :answer_content, if: "answer_type!=Radio Button"
end
Survey_question Model
class SurveyQuestion < ApplicationRecord
belongs_to :user
belongs_to :survey
has_many :survey_answers
accepts_nested_attributes_for :survey_answers, allow_destroy: true
has_many :survey_responses
accepts_nested_attributes_for :survey_responses
validates :question_content, presence: true
validates :answer_type, presence: true
end
I just to validate presence of survey_answer's answer_content when survey_question's answer_type is "Radio Button" ? how can I achieve this ??
thanks in advance.

I'm not sure if you are looking for an if or unless based on using != in your example, but try the following:
validates_presence_of :answer_content, if: ->(answer) { answer.survey_question.answer_type == 'Radio Button' }

Related

Rails 4 - Validates uniqueness with has_many through

I have these three models:
User:
class User < ActiveRecord::Base
validates :name, presence: true
validates :surname, presence: true
validates :email, presence: true, format: { with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }
has_many :permissions, dependent: :destroy
has_many :stores, through: :permissions
end
Store:
class Store < ActiveRecord::Base
validates :name, presence: true
validates :description, presence: true
has_many :permissions
has_many :users, through: :permissions
end
Permission:
class Permission < ActiveRecord::Base
belongs_to :user
belongs_to :store
end
How can i validate the uniqueness of the user.email based on the store.id?
You don't.
You should validate the uniqueness of the users email in User. And validate the uniqueness of the user_id and store_id in Permission.
class User < ApplicationRecord
# ...
validates_uniqueness_of :email
end
class Permission < ApplicationRecord
validates_uniqueness_of :user_id, scope: 'store_id'
end
This allows a user to have permissions for multiple stores - but does not allow duplicates. In general when linking records together use id's - not something like emails.

Rails 4 - Create record with has_many through

In my project i have something like this:
class User < ActiveRecord::Base
has_many :roles
has_many :websites, through: :roles
end
class Website < ActiveRecord::Base
validates :name, presence: true
has_many :roles
has_many :users, through: :roles
end
class Role < ActiveRecord::Base
validates :name, presence: true
belongs_to :user
belongs_to :website
end
So when I try to do:
User.first.websites.create(name: "First")
I have this error
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
How can i create a new User Website in one line?
The validation error is actually coming from the Role model, which also has validation for the name attribute.
You can do it in one line by creating the website through the role, using accepts_nested_attributes_for:
class Role < ActiveRecord::Base
validates :name, presence: true
belongs_to :user
belongs_to :website
accepts_nested_attributes_for :website
end
User.first.roles.create(name: "Role name", website_attributes: { name: "Website name" })
I think if you remove validates :name, presence: true from role model then it will work.

How to scope validation to specific model in polymorphic association.?

I have two model User and Investment and one polymorhic model Address
class User < ActiveRecord::Base
has_one :address, as: :addressable, dependent: :destroy
accepts_nested_attributes_for :address
end
class Investment < ActiveRecord::Base
has_many :addresses, as: :addressable, dependent: :destroy
accepts_nested_attributes_for :addresses, reject_if: lambda { |v| v['address'].blank? } && :address_blank, :allow_destroy => true
end
class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
validates :address, presence: true
end
now validates :address, presence: true will applicable to both Investment as well as User
but i want it to applicable to only Investment not to User. so how do i do that.
Thanks.
in class Investment add
validates :address_id, presence: true
and remove bellow from class Address
validates :address, presence: true
class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
validates :address, presence: true, if: :investment?
protected
def investment?
addressable_type == 'Investment'
end
end

Rails4: Save object with has_many fails on the has_many model validator

I'm trying to save two models (one to many) in one time. My code looks like this:
#submission = Submission.new(submission_params)
#submission_asset = #submission.attachments.new(submission_asset_params)
#submission_asset.attachment_type = 'submission_asset'
if #submission.save
# render or redirect here
else
#submission.errors
end
But when I run this I get this error #messages={:attachments=>["is invalid"]}. I think it's because my attachment model has this:
# Attachment model snippet
validates :attachable_id, :attachable_type, presence: true
But it's to ensure it is attached to a Submission. But when I remove or comment out the validation it works and saves the two models and the association.
How do I make this save?
EDIT
class Submission < ActiveRecord::Base
has_many :attachments, as: :attachable, dependent: :destroy
end
class Attachment < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
validates :attachable_id, :attachable_type, presence: true
end
#submission_asset = #submission.attachments.build(submission_asset_params)
UPDATE:
class Submission < ActiveRecord::Base
has_many :attachments, as: :attachable, inverse_of: :attachable, dependent: :destroy
end
class Attachment < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
validates :attachable, presence: true
end

Failing validations in join model when using has_many :through

My full code can be seen at https://github.com/andyw8/simpleform_examples
I have a join model ProductCategory with the following validations:
validates :product, presence: true
validates :category, presence: true
My Product model has the following associations:
has_many :product_categories
has_many :categories, through: :product_categories
When I try to create a new product with a category, the call to #product.save! in the controller fails with:
Validation failed: Product categories is invalid
When I remove the validations, everything works and the join models are saved correctly.
I'm using strong_parameters but I don't think that should be related to this issue.
This is a "racing condition" in the callback chain.
When you create a product it doesn't have any id before it is saved, therefore there is no product in the scope of ProductCategory.
Product.new(name: "modern times", category_ids:[1, 2]) #=> #<Product id: nil >
At that stage of validation (before saving), ProductCatgory cannot assign any id to it's foreign key product_id.
That's the reason you have association validations : so that the validation happens in the scope of the whole transaction
UPDATE: As said in the comment you still can't ensure presence of a product/category. There's many ways around depending on why you want do this (e.g direct access to ProductCategory through some form)
You can create a flag to have validates :product, presence: true, if: :direct_access?
or if you can only update them: validates :product, presence: true, on: "update"
create your product first (in the products_controller) and add the categories after
... But indeed these are all compromises or workarounds from the simple #product.create(params)
Specifying inverse_of on your joining models has been documented to fix this issue:
https://github.com/rails/rails/issues/6161#issuecomment-6330795
https://github.com/rails/rails/pull/7661#issuecomment-8614206
Simplified Example:
class Product < ActiveRecord::Base
has_many :product_categories, :inverse_of => :product
has_many :categories, through: :product_categories
end
class Category < ActiveRecord::Base
has_many :product_categories, inverse_of: :category
has_many :products, through: :product_categories
end
class ProductCategory < ActiveRecord::Base
belongs_to :product
belongs_to :category
validates :product, presence: true
validates :category, presence: true
end
Product.new(:categories => [Category.new]).valid? # complains that the ProductCategory is invalid without inverse_of specified
Adapted from: https://github.com/rails/rails/issues/8269#issuecomment-12032536
Pretty sure you just need to define your relationships better. I still might have missed some, but hopefully you get the idea.
class Product < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
validates :name, presence: true
validates :description, presence: true
validates :color_scheme, presence: true
belongs_to :color_scheme
has_many :product_categories, inverse_of: :product
has_many :categories, through: :product_categories
end
class ProductCategory < ActiveRecord::Base
belongs_to :product
belongs_to :category
validates_associated :product
validates_associated :category
# TODO work out why this causes ProductsController#create to fail
# validates :product, presence: true
# validates :category, presence: true
end
class Category < ActiveRecord::Base
has_many :product_categories, inverse_of: :category
has_many :products, through: :product_categories
end

Resources