ActiveRecord验证和回调4

9 回调概述
回调是在对象生命周期中某一时刻调用的方法。在Active Record对象从数据库中创建、保存、更新、删除、验证和装载的时候就可以编写回调代码。

9.1 注册回调
使用回调有个规则就是要注册它们。就像平常使用方法一样,使用一个macro-style类方法来注册。
class User < ActiveRecord::Base
validates_presence_of :login, :email
before_validation :ensure_login_has_a_value

protected
def ensure_login_has_a_value
    if login.nil?
      self.login = email unless email.black?
    end
end
end
macro-style类方法也接受一个block,如果代码很短就可以考虑把它写在block中。
class User < ActiveRecord::Base
validates_presence_of :login, :email
before_create { |user| user.name = user.login.capitalize if user. name.blank ?}
end

声明回调方法是保护和私有,这是很有用的做法。如果是公共的,就能从外部其他模型中调用该方法。

10 验证回调

10.1 创建对象
* before_validation
* before_validation_on_create
* after_validation
* after_validation_on_create
* before_save
* before_create
* INSERT OPERATION
* after_create
* after_save

10.2 更新对象
* before_validation
* before_validation_on_update
* after_validation
* after_validation_on_update
* before_save
* before_update
* UPDATE OPERATION
* after_update
* after_save

10.3 删除对象
* before_destroy
* DELETE OPERATION
* after_destroy

10.4 after_initialize和after_find
使用new方法或者从数据库中载入记录就可以使用after_initialize。

当从数据库中载入记录时就可以使用after_find,如果两种方法都定义了,after_find是在after_initialize之前调用。
这两个回调方法和其它的有一点点不同,它们没有before_*的版本。而且注册他们唯一的方法就是定义方法。如果使用macro-style来注册的话,会被忽略掉。
class User < ActiveRecord::Base
def after_initialize
    puts "You have initialized an object!"
end
def after_find
    puts "You have found an object!"
end
end

>> User.new
You have initialize an object!
=> #<User id: nil>

>>User.first
You have found an object!
You have initialized an object!
=>#<User id: 1>

12 跳过回调
在验证时有些方法可以跳过回调,请小心使用这些方法。
* decrement
* decrement_counter
* delete
* delete_all
* find_by_sql
* increment
* increment_counter
* toggle
* update_all
* update_counters

13 终止执行
在模型中注册回调,它们按队列执行。这些队列将包含在模型的验证中,注册回调,数据库执行操作。
整个回调被封装起来,如果有回调方法执行并返回false或者抛出一个异常,回调就终止。

14 关系回调
回调可以通过模型关系工作,并且能够被它们定义。

class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
end

class Post < ActiveRecord::Base
after_destroy :log_destroy_action
def log_destroy_action
    puts 'Post destroyed'
end
end

>> user = User.first
=> #<User id:1>
>> user.posts.create!
=> #<Post id: 1, user_id: 1>
>> user.destroy
Post destroyed
=> #<User id: 1>

15 有条件的回调
和验证类似,回调也可以附加条件。使用:if和:unless选项,该选项可以使用符号、字符串和Proc对象作为参数。

15.1 使用符号的:if和:unless
使用的符号参数一般是指向一个方法,如果这个方法返回false,那么回调就不执行。
class Order < ActiveRecord::Base
before_save :normalize_card_number, :if => :paid_with_card?
end

15.2 使用字符串的:if和:unless
字符串参数是可能通过eval执行的Ruby代码。当描述一个很短的条件时可以用它。
class Order < ActiveRecord::Base
before_save :normalize_card_number, :if => "paid_with_card?"
end

15.3 使用Proc对象的:if和:unless
通过条件在一行时,使用这个参数是再好不过的了。
class Order < ActiveRecord::Base
before_save :normalize_card_number,
    :if => Prod.new{|order| order.paid_with_card?}
end

15.4 多条件的回调
当用条件来限制回调时,可以把:if和:unless同时写上。
class Comment < ActiveRecord::Base
after_create :send_email_to_author, :if => :author_wants_emails?,
    :unless => Proc.new{ |comment| comment.post.ingnore_comment?}
end

16 回调类
虽然多数情况下,使用内建的回调方就足够了。ActiveRecord也让你可以自己定义类来创建回调方法,而且这个过程很容易。
class PictureFileCallbacks
def after_destroy(picture_file)
    File.delete(picture_file.filepath) if File.exists?(picture_file.filepath)
end
end

当在类中声明一个回调方法,会用模型对象作为参数。可以这样来使用:
class PictureFile < ActiveRecord::Base
after_destroy PictureFileCallbacks.new
end
我们声了一个回调的实例方法,这样就要实例化一个PictureFileCallbacks对象。很多时候会用类方法:
class PictureFileCallbacks
def self.after_destroy(picture_file)
    File.delete(picture_file.filepath) if File.exists?(picture_file.filepath)
end
end

如果回调方法是这样定义的,就不用实例化了。
class PictureFile < ActiveRecord::Base
after_destroy PictureFileCallbacks
end

17 观察者
观察者和回调类似,但又有很大的不同。回调会意图污染没有直接关系的模型,而观察者允许你在模型的外部添加同样的功能。例如:有一个User模型,没有包含发送验证邮件的代码,应当考虑使用观察者。

17.1 创建观察者
例如,User模型要为每个新创建的用户发送email。因为发送email和我们的模型没有直接的联系,所以就创建观察者来包含这些功能。
class UserObserver < ActiveRecord::Observer
def after_create(model)
    # code to send confirmation email...
end
end

和回调类一样,观察者方法接受观察者模型作为参数。

17.2 注册观察者
观察者一惯是放在app/models目录和在config/enviroment.rb中注册。上面例子UserObserver应保存在app/models/user_observer.rb文件中和在config/environment.rb中加上:
config.active_record.observers = :user_observer

17.3 共享观察者
观察者可以添加到更多的模型中:
class MailerObserver < ActiveRecord::Observer
observe :registration, :user
def after_create(model)
    # code to send cofirmation email...
end
end

这个例子中,每当一个Registration或者User创建的时候,就会调用after_create方法。要注意的就是新的MailerObserver观察者要注册到config/environment.rb中。
config.active_record.observers = :mailer_observer

 

form:http://hi.baidu.com/haifreeidea/blog/item/6b6bfdef6f96aef3b0fb9566.html

你可能感兴趣的:(ActiveRecord,after_save)