Validates uniqueness in a one-to-many association - ruby-on-rails

I have an Album model and Track model. I want to make sure that the name of each track on the album they belong to are unique. I tried using this validation in my Track model
validates :name, presence: true, uniqueness: true, scope: :album_id
but get the error: Unknown validator: 'ScopeValidator'
What am I doing wrong?
class Album < ActiveRecord::Base
has_many :tracks
accepts_nested_attributes_for :tracks, :reject_if => :all_blank, :allow_destroy => true
validates :name, presence: true, uniqueness: true
end
class Track < ActiveRecord::Base
belongs_to :album
validates :name, presence: true, uniqueness: true, scope: :album_id
end

You need to scope the uniqueness, not put it as a separate argument.
class Track < ActiveRecord::Base
belongs_to :album
validates :name, presence: true, uniqueness: { scope: :album_id }
end

Related

How to exclude the validation in case of the specific nested attributes?

I'm using one address model with polymorphic.
Class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true, touch: true
...
validates :street_address_1, presence: {with true, message:'cannot be blank'}
validates :street_address_2, presence: {with true, message:'cannot be blank'}
validates :city, presence: {with true, message:'cannot be blank'}
validates :locale, presence: {with true, message:'cannot be blank'}
validates :postal_code, presence: {with true, message:'cannot be blank'}
validates :country, presence: {with true, message:'cannot be blank'}
...
end
Company model
class Company < ApplicationRecord
...
has_many :physical_addresses, :as=> addressable, dependent: :destroy
accepts_nested_attributes_for :physical_addresses, allow_destroy: true
...
end
User model
class User < ApplicationRecord
...
has_many :physical_addresses, :as=> addressable, dependent: :destroy
accepts_nested_attributes_for :physical_addresses, allow_destroy: true
...
end
I'm using the nested attribute for creating or updating the User and Company controller.
I'd like to apply the address validation only for User creating and updating. But the companies don't have to be applied the address validation.
Is there any best way to solve this issue?
Write a validator class.
Skip the validations if addressable refers to a Company.
def validate(address)
return unless address.addressable.kind_of?(User)
...
end

Rails use model in the same namespace for belongs_to reference, how to reference model from outside

I working on a Rails application, currently we structure the app by modules. Right now we have 2 separate model for users: User and Freight::Customer::User.
I have a new model Freight::Customer::MembershipStatus looks like this:
class Freight::Customer::MembershipStatus < ActiveRecord::Base
belongs_to :customer, class_name: 'Freight::Customer'
belongs_to :created_by, class_name: 'User'
validates :from, presence: true
validates :to, presence: true
validates :customer, presence: true
validates :status, presence: true
end
In this case, the created_by is reference to User. But when the code run membership_status.created_by, rails try to look for the Freight::Customer::User, I think it because Rails try to look for model within the same module first.
Is there a way to config this model to use the outer User model class?
You can get user class using this type, try this.
class Freight::Customer::MembershipStatus < ActiveRecord::Base
belongs_to :customer, class_name: 'Freight::Customer'
belongs_to :created_by, class_name: '::User'
validates :from, presence: true
validates :to, presence: true
validates :customer, presence: true
validates :status, presence: true
end

Skip children validations with condition

I have two ActiveRecords Author and Book.
class Author < ActiveRecord::Base
has_many :books
enum author_type: {
musician: 0,
scientist: 1
}
accepts_nested_attributes_for :books
end
class Book < ActiveRecord::Base
belongs_to :author
validates :name, presence: true
validates :score_url, presence: true
end
Now Book validates presence for both name and score_url,
but I want skip validation for score_url when author.author_type is scientist.
I tried this way, but author can not be found during creation.
class Book < ActiveRecord::Base
belongs_to :author
validates :name, presence: true
validates :score_url, presence: true, if: "author.scientist?"
end
What is the best solution here?
You need to provide a Proc to the conditional validation
validates :score_url, presence: true, if: Proc.new { |book| book.author.scientist? }
if your validation gets any more complex, you should extract the logic to a new method.
validates :score_url, presence: true, if: :author_scientist?
private
def author_scientist?
author.present? && author.scientist?
end

How to created new record on has_one for two model on the same time on Rails?

I need to create new record for two models that belong to the same model on one method.
This is my Model
class Promotion < ApplicationRecord
has_one :promotion_thai ,dependent: :destroy
has_one :promotion_eng ,dependent: :destroy
end
class PromotionThai < ApplicationRecord
belongs_to :promotion
mount_uploader :long_banner, PromotionImageUploader
mount_uploader :square_banner, PromotionImageUploader
mount_uploader :details_image, PromotionImageUploader
validates :promotion_id, presence: true
validates :title, presence: true
validates :description, presence: true
#validates :long_banner, presence: true
#validates :square_banner, presence: true
end
class PromotionEng < ApplicationRecord
belongs_to :promotion
mount_uploader :long_banner, PromotionImageUploader
mount_uploader :square_banner, PromotionImageUploader
mount_uploader :details_image, PromotionImageUploader
validates :promotion_id, presence: true
validates :title, presence: true
validates :description, presence: true
validates :long_banner, presence: true
validates :square_banner, presence: true
end
This is my controller method
def create
promotion = Promotion.new
promotion.build_promotion_eng(promotion_eng_params).build_promotion_thai(promotion_thai_params)
if promotion.save
flash[:success] = 'Success Created Promotion'
redirect_to admins_promotions_path
else
errors_message = promotion.errors.full_messages.join(', ')
redirect_to admins_promotion_new_path, :flash => { :error => errors_message }
end
end
Then when i submit the form i always got this error
undefined method `build_promotion_thai' for #<PromotionEng:0x007f9fdbcb0250> Did you mean? build_promotion
On this line
promotion.build_promotion_eng(promotion_eng_params).build_promotion_thai(promotion_thai_params)
How can i fix this kind of problem?
Thanks!
That's because build_promotion_eng(promotion_eng_params) returns an PromotionEng instance.
This should work fine.
promotion.build_promotion_eng(promotion_eng_params)
promotion.build_promotion_thai(promotion_thai_params)

Second Level Model

I have Locations, Order and Event Models.
class Order < ActiveRecord::Base
belongs_to :event
validates :first_name, presence: true
validates :last_name, presence: true
validates :amount, presence: true, :numericality => {:only_integer=>true, :greater_than =>0}
end
class Event < ActiveRecord::Base
belongs_to :location
validates :title, presence: true
validates :price, presence: true, :numericality => {:greater_than =>0}
end
class Location < ActiveRecord::Base
has_many :events, dependent: :destroy
has_many :orders, through: :events
validates :title, presence: true
validates :size, presence: true, :numericality => {:only_integer=>true,:greater_than =>0}
end
I want to check, in the orders create controller, how many seats the location has.
#orders.events returns me the right event.
if I ask for #order.event.location the return is always "#".
Is this a security issue? I also added in the Location model:
has_many: orders, through: events

Resources