Specific validation - validation

I have models User and Product in my project. User have some products. I want user products to have unique title only for this user.
For example user1 has a product titled "product". In this case user2 also can have a product titled "product". First "product" differs from second "product". In table both products have the same name. But the user may not have both of these products at the same time.
That is my Product.rb:
validates :title, :description, presence: true
validate :uniq_of_product_title
def uniq_of_product_title
if Product.where(user_id: user_id).find_by_title(title)
errors.add(:title, "Product already exists")
end
end
So it works. Problem appears then I edit description and try to update product. Validator finds created product in table and gives a error.
The question is how can I make validates best way?

You can probably use regular Rails' validates method for this case, try something like:
validates :title, uniqueness: true

Related

RoR: Validation of field through model-level validation

In Ruby on Rails, I have a table called Person. It has a field name. The table already has many rows. Some of them also have name as nil. I am fine with the records that already have nil in the name field but moving forward I want to mandate filling of name field when someone creates a new Person entry. I am using Active Record Validation to implement this:
in app/models/person.rb
class Person < ActiveRecord::Base
validates :name, :presence => true
end
Will this mess up my Person table, since I already have some entries with nil in the name field.
Validate only while creating new entry
validates :name, :presence => true, on::create

How to validate a mongoid field based on another mongoid field?

I made the switch to nosql and am playing with Mongoid with Sinatra. I'm still new to this, and I"m stumped on this problem.
class Item
field :name, type: String
field :category, type: Moped::BSON::ObjectId # holds _id of the category object
field :cover_type, type: String
validates_presence_of :category
validates_inclusion_of :cover_type, in:["Hardcover", "Softcover"]
end
class Category
field :name
validates_inclusion_of :name, in:["Books", "Movies", "Ebooks"]
end
Imagine a store that sells Books, Movies, and Ebooks and each item sold belongs to one of the three categories. If an Item is listed under the category "Books", then the Item is required to have a field called cover_type. Furthermore, cover_type can only be either "Hardcover" or "Softcover".
When saving an Item, how do I piece together the validate in the Item class for when the Item is in the Book category and therefore requires the presence of the field cover_type, which is also validated as being "Hardcover" or "Softcover"?
If the Item isn't a Book, then cover_type can be null.
Mongoid models inherit ActiveModel validations. You can just write a custom validator method:
class Item
validates :cover_type_must_be_valid, if: :book?
def book?
Category.find(category).name == 'Books'
end
def cover_type_must_be_valid
errors.add(:cover_type, 'must be Hardcover or Softcover') unless %w{Hardcover Softcover}.include? cover_type
end
end
The book? method is unpleasant; why not use belongs_to :category on Item and has_many :items on Category?
EDIT: here’s what book? could look like if you used the has_many and belongs_to:
def book?
category.name == 'Books'
end
Not that different, but you’ll surely be accessing item.category all over your application, I can’t see why you wouldn’t want to make it easier.

Pass Validation on Form Fields Before Friendly ID Creation - Custom

I currently have two models
Location and Product
I have it configured that when a record is created in my production model, it creates a custom url based on the information it has gather from the location selected during the product creation
extend FriendlyId
friendly_id :slug_candidates, use: :slugged
def should_generate_new_friendly_id?
name_changed? or location_id_changed?
end
def slug_candidates
[
[location.media_type, location.state, location.name, :name, :sku]
]
end
What I am currently testing is when a user decides NOT to fill out those very important fields, for it to throw an error message before creating
validates :name, presence: true
validates :sku, presence: true
validates :location_id, presence: true
What is happening in my case, is that it overlooks that validator and first tries to create the slug. If I remove the custom attributes to the url creation and list as
def slug_candidates
[
[:name, :sku]
]
end
it will work fine, running the field validators first. Assuming because those two are attributes on the given model directly.
Does anyone know why this is happening? I need for the validators to be picked up first since it contains all the relevant information for the url.
Solved
def slug_candidates
if self.location_id.nil?
self.errors.add(:location_id)
else
[
[location.media_type, location.state, location.name, :name, :sku]
]
end
end

Rails model validation: two users cannot be the same

I have a model set out like so:
class Rating
# user_id, author_id
end
What I want to do is validate the author_id/user_id so they cannot be the same, essentially, so that a user cannot rate themselves.
Am I right to say this should be done using a validation in the Rating class?
validates :author_id, # custom validation options
You'll need a custom validation:
class Rating
# user_id, author_id
validate :ensure_author_is_not_user
private
def ensure_author_is_not_user
errors[:author_id] << "can not be the same as user" unless user_id != author_id
end
end

How to show model title instead on #<Mymodel:0x000000...> in activeadmin dropdown menus?

I've created an association where Project has_many Tasks and Task belongs_to Project.
I've created the form in admin/tasks.rb
form do |f|
f.inputs "Details" do
f.input :title
f.input :project
end
f.buttons
end
Now in the edit Task page I hahe a dropdown menu where I can choose the project, but the entry are #<Project:0x00000...>.
How can I customize the entries in the dropdown to show the Project title field instead?
I'm a Rails newbie.
Active admin makes use of formtastic, under the hood formtastic loops through your model searching for a method like name, to_s, value, title, that returns a string.
At the moment you see the data entry itself, if you want formtastic to show the name, make sure you put something like
def name
return self.what_key_you_want_to_use
end
in your Project.rb model.
That should let formtastic show the name action instead of the model .to_s!
This solved it for me:-
In project.rb (Model) to make ActiveAdmin display properly in select dropdown use alias_attribute.
alias_attribute :name, :project_name (or whatever you named the field in your database)
tldr: You can define or alias :to_label on your model to customize the label used:
def to_label
"#{name} - (#{id})"
end
alias_attribute :to_label, :name
The library used by Rails: Formtastic, (or an alternative: Simple Form) uses the collection_label_methods to configure which fields are checked for deriving a label for your model.
Formastic defaults are: "to_label", "display_name", "full_name", "name", "title", "username", "login", "value", "to_s"
Simple Form defaults are: :to_label, :name, :title, :to_s
As most of these fields might already be used in your model, to_label or display_name seems to be the good candidates. I prefer to_label.
You can create a proc like such :
f.input :your_field, member_label: Proc.new { |p| "#{p.name}"}

Resources