public
Created

How can I validate a parent model, which uses accepts_nested_attributes_for

  • Download Gist
company.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
class Company < ActiveRecord::Base
include CompanyRepository
 
PHONES_NUMBER_MIN = 1
EMAILS_NUMBER_MIN = 1
 
attr_accessible :name, :state_event, :payment_method_id, :tariff_id, :status_id, :assigned_id,
:category_id, :referer, :rental_fee,
:contact_details_attributes, :counteragents_attributes, :gis_objects_code_list
 
acts_as_taggable_on :gis_objects_codes
 
composed_of :rental_fee, ComposeOfParams.money(:rental_fee_in_kop)
 
belongs_to :payment_method
belongs_to :tariff
belongs_to :category
belongs_to :status
belongs_to :creator, :class_name => ::Employee, :foreign_key => 'employee_id'
belongs_to :assigned, :class_name => ::Employee, :foreign_key => 'assigned_id'
 
has_many :contact_details, :as => :contactable, :dependent => :destroy
has_many :people, :dependent => :destroy
has_many :invoices, :dependent => :destroy
has_many :deals, :dependent => :destroy
has_many :accounts, :dependent => :destroy
has_many :crm_accounts, :dependent => :destroy
has_many :gis_accounts, :dependent => :destroy
has_many :notes, :dependent => :destroy, :order => 'created_at DESC'
has_many :events, :dependent => :destroy, :class_name => ::Employee::Event
has_many :counteragents, :dependent => :destroy
has_many :counteragent_kinds, :through => :counteragents,
:class_name => 'Counteragent::Kind', :source => :kind, :uniq => true
 
validates :name, :presence => true, :uniqueness => {:case_sensitive => false}, :length => {:maximum => 255}
validates :creator, :presence => true
validates :assigned, :presence => true
validates :rental_fee, :numericality => { :greater_than_or_equal_to => 0 }, :allow_nil => true
validates_each :rental_fee do |record, attr, value|
record.errors.add(attr, :not_a_number) if value.is_a?(NilMoney)
end
 
validate do |company|
check_emails_number if our_client?
check_phones_number
end
 
after_initialize :init
 
accepts_nested_attributes_for :contact_details, :allow_destroy => true, :reject_if => :contact_details_invalid
accepts_nested_attributes_for :counteragents, :allow_destroy => true
 
state_machine :state, :initial => :active do
state :active
state :deleted
 
before_transition :on => :del do |company|
company.people.active.map &:del
company.deals.active.map &:del
company.accounts.active.map &:del
company.unassigned_events.active.map &:del
end
 
event :del do
transition :active => :deleted
end
end
 
def to_s
name
end
 
def our_client?
status.our_client? if status.present?
end
 
def cars_count
counteragents.collect{ |c| c.cars_count || 0 }.sum
end
 
# Public: Sets nil if value is blank, calls super otherwise
#
# value - The String value
def rental_fee_with_empty_string_processing=(value)
value = nil if value.is_a?(String) && value.empty?
self.send('rental_fee_without_empty_string_processing=', value)
end
 
alias_method_chain :rental_fee=, :empty_string_processing
 
# FIXME [Anton Kalyaev 09/07/2012] we cannot guarantee that it is true main email
def main_email
contact_details.emails.try :first
end
 
def main_phone
contact_details.phones.try :first
end
 
private
 
def init
if new_record?
self.rental_fee ||= 0.0
end
end
 
def phones_number_valid?
kind = ContactDetail::Kind.phone
phones = contact_details.select { |cd| cd.kind_id == kind.id }
phones.size >= PHONES_NUMBER_MIN
end
 
def check_phones_number
unless phones_number_valid?
errors.add(:base, :phones_too_short, :count => PHONES_NUMBER_MIN)
end
end
 
def email_number_valid?
kind = ContactDetail::Kind.email
emails = contact_details.select { |cd| cd.kind_id == kind.id }
emails.size >= EMAILS_NUMBER_MIN
end
 
def check_emails_number
unless email_number_valid?
errors.add(:base, :email_too_short, :count => EMAILS_NUMBER_MIN, :our_client_name => Status.our_client.name)
end
end
 
def contact_details_invalid(attributes)
# validate emails
unless our_client?
email_kind_id = ContactDetail::Kind.email.id
if attributes['kind_id'] == email_kind_id.to_s && attributes['kind_value_source'].blank?
return true
end
end
 
false
end
end
contact_detail.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
class ContactDetail < ActiveRecord::Base
include ContactDetailRepository
 
attr_accessible :kind_id, :kind_value_source
 
belongs_to :contactable, :polymorphic => true
belongs_to :kind
 
validates :kind_value_source, :presence => true, :length => {:maximum => 255}
 
# custom validation
validates :kind_value, :contact_detail_uniqueness => {:case_sensitive => false}, :phone => true, :if => :phone?
validates :kind_value, :contact_detail_uniqueness => {:case_sensitive => false}, :email => true, :if => :email?
validates :kind_value, :contact_detail_uniqueness => {:case_sensitive => false}, :url => true, :if => :site?
 
def to_s
kind_value_source || kind_value
end
 
def phone?
kind == ContactDetail::Kind.phone
end
 
def email?
kind == ContactDetail::Kind.email
end
 
def site?
kind == ContactDetail::Kind.site
end
 
def kind_value_source=(v)
value = v
write_attribute(:kind_value_source, value) # save original value
if phone?
value = Filters.phone(v)
end
if site?
value = Filters.site(v)
end
self.kind_value = value
end
end
contact_detail_kind.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
class ContactDetail::Kind < ActiveRecord::Base
include UsefullScopes
 
attr_accessible :name, :slug
 
validates :name, :presence => true, :length => {:maximum => 255}
validates :slug, :slug => true, :uniqueness => true
 
def to_s
name
end
 
class << self
 
def phone
find_by_slug(:phone)
end
 
def email
find_by_slug(:email)
end
 
def site
find_by_slug(:site)
end
end
end
contact_detail_repository.rb
Ruby
1 2 3 4 5 6 7 8 9
module ContactDetailRepository
extend ActiveSupport::Concern
include UsefullScopes
 
included do
scope :phones, where(:kind_id => ContactDetail::Kind.phone)
scope :emails, where(:kind_id => ContactDetail::Kind.email)
end
end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.