诗歌rails之Rails验证的示例

先补充一个部分的代码用来说明这些回调在一些实际中的用法,

Ruby代码
  1. class Profile < ActiveRecord::Base  
  2.   before_validation :archive#在验证之前判断,  
  3.   #为什么验证之前呢,因为如果是新建的话就不要验证了  
  4.   before_destroy :destroy_validate#删除的时候验证  
  5.   def archive  
  6.     return unless self.new_record?  
  7.     profile = Profile.find_by_name(self.name)  
  8.     unless profile.nil?  
  9.       profile.name = sprintf("a-%s", profile.id)  
  10.       profile.status = true  
  11.       unless profile.save   
  12.         return false  
  13.       end  
  14.     end  
  15.   end  
  16.   def validate#修改默认的验证  
  17.     errors.add(:major_offset"must be >= Minor Offset"unless major_offset >= minor_offset  
  18.     errors.add(:minor_offset"must be <= Major Offset"unless minor_offset <= major_offset  
  19.      if Analyzer.count(:conditions => ["profile_id = ? and status= ?"self.id, Analyzer::INGRESS]) > 0  
  20.       errors.add_to_base("One or more Analyzers are in Ingress Monitoring mode and use this profile.  Edits are disabled until you stop Ingress Monitoring.")  
  21.       return false  
  22.     end  
  23.   end  
  24.   def destroy_validate#对应删除验证的描述  
  25.     if Analyzer.count(:conditions => ["profile_id = ? "self.id]) > 0  
  26.       errors.add_to_base("One or more Analyzers use this profile, Delete are disabled.")  
  27.       return false  
  28.     end  
  29.     if SwitchPort.exists?(:profile_id=> self.id)  
  30.       errors.add_to_base("One or more Analyzers use this profile, Delete are disabled.")  
  31.       return false  
  32.     end  
  33.   end  
  34. end  

通常在一个active record对象的生命周期里,有八个过程
引用
(-) save
(-) valid?
(1) before_validation
(2) before_validation_on_create
(-) validate
(-) validate_on_create
(3) after_validation
(4) after_validation_on_create
(5) before_save
(6) before_create
(-) create
(7) after_create
(8) after_save

这些stat是可以用来hook
下面是一个

回调的典型例子

Ruby代码
  1. class CreditCard < ActiveRecord::Base  
  2.   # 这个例子用来说明预先处理信用卡数据,作用是在验证  
  3.   # 以前把输入的数据中不是数字的输入,屏蔽掉。就是把 "555 234 34"或者  
  4.   # "5552-3434" 都转换成 "55523434"  
  5.   def before_validation_on_create  
  6.     self.number = number.gsub(/[^0-9]/, ""if attribute_present?("number")  
  7.   end  
  8. end  
  9.   
  10.   
  11. class Subscription < ActiveRecord::Base  
  12.   #这是另一个回调的例子,是在创建的时候,积累时间。  
  13.   #当然,这里是示例,没有人需要这个功能  
  14.   before_create :record_signup  
  15.   
  16.   private  
  17.     def record_signup  
  18.       self.signed_up_on = Date.today  
  19.     end  
  20. end  
  21.   
  22. class Firm < ActiveRecord::Base  
  23.   # 下面的例子也经常用就是相关删除。很多时候,这件事应该是dependent => :destroy  
  24.   # 来完成,当然,还有些时候比较复杂的回调,就会用到类似的方法  
  25.   # 当firm公司删除时,同时删除对应员工(Person)和客户(Client)  
  26.   before_destroy { |record| Person.destroy_all "firm_id = #{record.id}"   }  
  27.   before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }  
  28. end  


有继承关系的回调

下面的情景是说,当在一个类中定义了回调。但,他有一个子类,又定义了一个回调。
  然后,我们希望,
        有些时候,回调继承执行。就是又要执行父类的回调,又要执行子类的回调。
        有些时候,希望子类的回调,重写覆盖父类的回调。
  那么,看看如何实现 
Ruby代码
  1. #这样的话,将实现回调的继承和队列调用  
  2.   class Topic < ActiveRecord::Base  
  3.     before_destroy :destroy_author  
  4.   end  
  5.   
  6.   class Reply < Topic  
  7.     before_destroy :destroy_readers  
  8.   end  
  9. #也就是说,当Topic#destroy调用的时候 destroy_author将被执行。而,当Topic#destroy被执行的时候destroy_author和 destroy_readers将都被调用  
  10. #-------------------------------------------------------------------------  
  11. #下面的方法,将导致覆盖  
  12. class Topic < ActiveRecord::Base  
  13.     def before_destroy() destroy_author end  
  14.   end  
  15.   
  16.   class Reply < Topic  
  17.     def before_destroy() destroy_readers end  
  18.   end  
  19. #这个时候,当Reply#destroy被调用时候将只调用destroy_readers将不会调用 destroy_author.  
  20. #-------------------------------------------------------------------------  


回调的四种类型

  • Method references (符号),
  • callback objects(最常用吧),
  • inline methods (使用块方法),
  • and inline eval methods (字符串).

在这其中,前两种是推荐的回调表达方式。块方法的回调有些时候,也比较合适。最后的一种,基本废弃。

Ruby代码
  1. class Topic < ActiveRecord::Base  
  2.   #这是标准的使用,把回调的方法本身,限制为private或者protected   
  3.   before_destroy :delete_parents  
  4.   
  5.   private  
  6.     def delete_parents  
  7.       self.class.delete_all "parent_id = #{id}"  
  8.     end  
  9. end  


回调的参数

回调方法的参数,是记录,根据传入的不同,灵活调用。
Ruby代码
  1. class BankAccount < ActiveRecord::Base  
  2.   before_save      EncryptionWrapper.new("credit_card_number")  
  3.   after_save       EncryptionWrapper.new("credit_card_number")  
  4.   after_initialize EncryptionWrapper.new("credit_card_number")  
  5. end  
  6.   
  7. class EncryptionWrapper  
  8.   def initialize(attribute)  
  9.     @attribute = attribute  
  10.   end  
  11.   
  12.   def before_save(record)  
  13.     record.credit_card_number = encrypt(record.credit_card_number)  
  14.   end  
  15.   
  16.   def after_save(record)  
  17.     record.credit_card_number = decrypt(record.credit_card_number)  
  18.   end  
  19.   
  20.   alias_method :after_find:after_save  
  21.   
  22.   private  
  23.     def encrypt(value)  
  24.       # Secrecy is committed  
  25.     end  
  26.   
  27.     def decrypt(value)  
  28.       # Secrecy is unveiled  
  29.     end  
  30. end  

method missing的应用

回调的宏,默认下会等待一个符号,但当我们在符号部分,使用method missing时,就可以在预期估值的时候,执行绑定的回调。

Ruby代码
  1. class Topic < ActiveRecord::Base  
  2.   #实现act as tree的级联删除  
  3.   before_destroy 'self.class.delete_all "parent_id = #{id}"'  
  4. end  
  5. class Topic < ActiveRecord::Base  
  6.   before_destroy 'self.class.delete_all "parent_id = #{id}"',  
  7.                  'puts "Evaluated after parents are destroyed"'  
  8. end  


  •     *  after_create
  •     * after_destroy
  •     * after_save
  •     * after_update
  •     * after_validation
  •     * after_validation_on_create
  •     * after_validation_on_update
  •     * before_create
  •     * before_destroy
  •     * before_save
  •     * before_update
  •     * before_validation
  •     * before_validation_on_create
  •     * before_validation_on_update


http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
posted @ 2009-08-18 15:21  麦飞  阅读(596)  评论(0编辑  收藏  举报