Validate the quantity of associated objects - ruby-on-rails

Given this:
class User < ActiveRecord::Base
has_many :photos
MAX_PHOTOS = 5
validate :quantity_of_photos
def quantity_of_photos
???
end
end
And this:
#user.photos.size # => 5
I need this to fail:
#user.photos << Photo.create(valid_photo_attributes)
How do I do this validation?

Move the quantity of photos method to the Photo model:
class Photo < ActiveRecord::Base
belongs_to :user
validates :quantity_of_photos
def quantity_of_photos
if new_record? && user.photos.size >= User::MAX_PHOTOS
errors.add_to_base "You cannot have more than #{MAX_PHOTOS} photos."
end
end
end
The validity of a ActiveRecord instance is determined by whether there are errors in it's errors array.

Related

rails validate dependent model

There have 2 tables: Orders and Arrivals. There can be many arrivals on an order. I want to validate the creation of arrivals for a specific order.
Orders has fields book_id and quantity:integer
Arrivals has fields order:belongs_to and quantity:integer
Order.rb:
class Order < ActiveRecord::Base
has_many :arrivals
def total_arrival_quantity
arrivals.map(&:quantity).sum
end
def order_quantity_minus_arrival_quantity
quantity - total_arrival_quantity
end
end
Arrival.rb:
class Arrival < ActiveRecord::Base
belongs_to :order
validates :total_arrival_quantity_less_or_equal_to_order_quantity, on: create
validates :current_arrival_quantity_less_or_equal_to_order_quantity, on: create
def current_arrival_quantity_less_or_equal_to_order_quantity
self.quantity <= order.quantity
end
end
How can I make the two validations work?
Something like this should work,
validate :order_quantity, on: :create
private
def order_quantity
if quantity > order.order_quantity_minus_arrival_quantity
errors.add(:quantity, 'cannot be greater than ordered quantity.')
end
end

Access parent Object in Child model

I am using rails 2.3.17 and have this relationship setup
class Item < ActiveRecord::Base
belongs_to :order
end
class Order < ActiveRecord::Base
has_many :items, :dependent => :delete_all
end
Now i need to do a validation on an item, by accessing order object attributes, how can I do this?
When I write
validate :checkXYZ
def checkXYZ
Rails.logger.debug self.order // I AM GETTING NIL
end
but when I write
before_save :checkXYZ
def checkXYZ
Rails.logger.debug self.order // I AM ORDER OBJECT
end
This is my controller logic
#order = #otherObj.orders.create(params[:order])
item = #order.items.create(params[:item])
I need to get the order object in validate of item class, how can I do that?
In before_validate section, the parent(order) is not yet connected to the item object. Hence it'll definitely show nil.
But after the validation is passed & in before_save stage, the order & item are connected hence you are able to access the parent order of the selected item.
You can have below approach to validate your object.
class Order < ActiveRecord::Base
has_many :items, dependent: :delete_all
end
class Item < ActiveRecord::Base
before_save :something_missing?
belongs_to :order
private
def something_missing?
your_order = self.order
if (add_your_condition_which_is_violated)
errors[:base] << "Your error message"
return false
end
# When you are returning false here, the record won't be saved.
# And the respective error message you can use to show in the view.
end
end
To do this reliably when creating or updating an order you should call the validation on the parent object's (order's) model like this:
class Order < ActiveRecord::Base
has_many :items, :dependent => :delete_all
validate :checkXYZ
private
def checkXYZ
Rails.logger.debug self // Here you will have the Order object
for i in items do
if (vehicle == 7 and i.distance <= 500) then // vehicle is an attribute of order
errors.add(:error, "You're driving by car, distance must be larger than 500")
end
end
end
end

Rails 4 : Access attributes from model

I have a Model Reservation with 2 columns, user_id and teleporter_id.
I want to lock the creation of a Reservation to 3 same teleporter_id but I don't know how to access to the attribute teleporter_id from the Model that I'm creation.
Here my code :
class Reservation < ActiveRecord::Base
# Relations
belongs_to :teleporter
belongs_to :user
# Validations
validate :max_reservation
def max_reservation
if Reservation.where(:teleporter_id => self.teleporter_id).count >= 3
errors.add(:base, t('reservation.model.error.max_reservation'))
end
end
end
I think that the problem is from self.teleporter_id but I don't know how access to the attribut teleporter_id from the current model.
Try this:
def max_reservation
_id = self.teleporter_id
errors.add(:base, t('reservation.model.error.max_reservation')) unless Reservation.where(teleporter_id: _id).count <= 3
end

Ruby Validation When Adding to Database

I am really new in Ruby and I am on the last step to finish my project, when I'm trying to add appointment I have to change if doctor works in that time. I don't know how to do this :(
It is how my db works:
In appointment I have data_wizyty (visit_date), doctor_id and godzina_wizyty(visit_time) - it is in my adding form.
In schedules I have:
dzien_tygodnia(day_of_the_week), poczatek_pracy(start_working), koniec_pracy(end_working) and doctors_workplace_id
In doctors_workplace:
doctor_id, schedule_id, clinic_id
I want to check if doctor is available in any of the clinic in choosen date and time :)
Please help me with this :)
I have already validated if date and time is unique with:
class Appointment < ActiveRecord::Base
validates :doctor_id, uniqueness: { scope: [:data_wizyty, :godzina_wizyty], message: 'Ten termin jest juz zajety!' }
end
I need to check if it is unique and if doctor works.
Appointment:
class Appointment < ActiveRecord::Base
validates :doctor_id, uniqueness: { scope: [:data_wizyty, :godzina_wizyty], message: 'Ten termin jest juz zajety!' }
after_initialize :aInit
after_save :aSave
belongs_to :patient
belongs_to :doctor
belongs_to :schedule
belongs_to :refferal
belongs_to :clinic
has_many :employees
include MultiStepModel
def self.total_steps
3
end
def aInit
#wymaga_Potwierdzenia = true
end
def aSave
if self.refferal_id == nil
#potwierdzona = false
else
#potwierdzona = true
end
if self.wymaga_Potwierdzenia == false
#potwierdzona = true
end
end
end
Schedule:
class Schedule < ActiveRecord::Base
has_many :appointments
belongs_to :clinic
belongs_to :doctors_workplace
def full_schedule
"#{dzien_tygodnia} : #{poczatek_pracy} - #{koniec_pracy}"
end
end
Doctors_workplace:
class DoctorsWorkplace < ActiveRecord::Base
has_many :schedules
belongs_to :doctor
belongs_to :clinic_surgery
end
Now I have something like this :
def check_doctor_available
if Schedule.where(doctor: doctor, dzien_tygodnia: data_wizyty.wday)
.where('poczatek_pracy < ? and koniec_pracy > ?', godzina_wizyty, godzina_wizyty).empty?
self.errors.add(:doctor, message: 'nie pracuje w tym terminie!')
end
It's what I have now:
def check_doctor_available
if DoctorsWorkplace.where(doctor_id: doctor_id) and
Schedule.where(doctors_workplace_id: ????, dzien_tygodnia: data_wizyty.wday)
.where('poczatek_pracy < ? and koniec_pracy > ?', godzina_wizyty, godzina_wizyty).empty?
self.errors.add(:doctor, message: 'nie pracuje w tym terminie!')
end
You can use a custom validation. Create a private method in appointment that checks if the doctor is available at the given date/time.
validate :check_doctor_available
private
def check_doctor_available
#your implementation
end
Take a look at this if you have any doubts what to write in your custom validation method.

Too many chained conditions in if-else

Using Rails. How to best rewrite the country_photo?
# country.rb
class Country < ActiveRecord::Base
has_many :zones
def country_photo
if !zones.blank? && !zones.first.shops.blank? && !zones.first.shops.first.photos.blank?
zones.first.shops.first.photos.first.url(:picture_preview)
end
end
end
# zones.rb
class Zone < ActiveRecord::Base
belongs_to :country
has_many :zone_shops
has_many :shops, :through => :zone_shops
end
# zone_shop.rb
class ZoneShop < ActiveRecord::Base
belongs_to :zone
belongs_to :shop
end
# shop.rb
class Shop < ActiveRecord::Base
end
Note that !x.blank? -> x.present?. Anyway, if you are ok with doing assignations in ifs (they are pretty common in Ruby), you can write:
def country_photo
if (zone = zones.first) &&
(shop = zone.shops.first) &&
(photo = shop.photos.first)
photo.url(:picture_preview)
end
end
If you like fancy abstractions, with Ick you can write:
def country_photo
zones.first.maybe { |zone| zone.shops.first.photos.first.url(:picture_preview) }
end
Assuming you want to show an image in a view, I would do something like this:
# show.html.haml
- if #country.photo
image_tag #country.photo.url(:picture_preview)
# country.rb
class Country < ActiveRecord::Base
def photo
zones.first.photo unless zones.blank?
end
end
# zone.rb
class Zone < ActiveRecord::Base
def photo
shops.first.photo unless shops.blank?
end
end
# shop.rb
class Shop < ActiveRecord::Base
def photo
photos.first unless photos.blank?
end
end

Resources