guides.rubyonrails.org 读书笔记(五)

来源:互联网 发布:涨乐理财软件下载 编辑:程序博客网 时间:2024/05/29 16:05

Active Record Validations and Callbacks

 

1 The Object Life Cycle

Active Record provides hooks into this object life cycle so that you can control your application and its data. 保证Rails object在创建、更新、销毁过程都是可控的。

(1)Validations allow you to ensure that only valid data is stored in your database.

(2)Callbacks and observers allow you to trigger logic before or after an alteration of an object’s state.

 

2 Validations Overview

2.1 Why Use Validations?

Validations are used to ensure that only valid data is saved into your database. For example, it may be important to your application to ensure that every user provides a valid email address and mailing address.

 

There are several ways to validate data before it is saved into your database, including

(1)native database constraints,

不利于测试和维护,但是在有另外的程序,比如来自移动API,同时使用这个数据库时,数据库层面的校验就非常重要了。

(2)client-side validations,

快速反应,但客户端不易于控制,比如客户可能关闭来javascript

(3)controller-level validations, 

这个层面的控制其实也是可以的,并不会如guide所说的那样不利于测试和维护。但是为了

(1)控制器本身的逻辑代码就不少,把校验移动出去,可以减少控制器的逻辑代码,防止fat

(2)遵从习惯,易于代码的传承管理,交接维护。

(4) model-level validations.

 

2.2 When Does Validation Happen?

There are two kinds of Active Record objects: those that correspond to a row inside your database and those that do not.

Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the INSERT or UPDATE operation.

 

Creating and saving a new record will send an SQL INSERT operation to the database. Updating an existing record will send an SQL UPDATE operation instead. Validations are typically run before these commands are sent to the database.

(1) 部分方法会触发校验;

 

(2)部分方法不会;


(3)save(:validate => false)

Note that save also has the ability to skip validations if passed :validate => false as argument. This technique should be used with caution.

 

2.4 valid? and invalid?

You can also use this method on your own. valid? triggers your validations and returns true if no errors were added to the object, and false otherwise.这里的原理其实很简单,校验失败后,对应的错误信息会被收集起来。而Active:Record也就是通过最终的错误信息来判断一个对象是否有效。也就是下面这句话的含义。

When Active Record is performing validations, any errors found can be accessed through the errors instance method. By definition an object is valid if this collection is empty after running validations.

而此校验有两种方式:

(1)直接运行valid?

>> p.valid?
=> false
>> p.errors
=> {:name=>["can't be blank"]}

(2)会触发校验的方法:

>> p = Person.create
=> #<Person id: nil, name: nil>
>> p.errors
=> {:name=>["can't be blank"]}

Note that an object instantiated with new will not report errors even if it’s technically invalid, because validations are not run when using new.下面的程序就反映了这个问题,

 

class Person < ActiveRecord::Base
  validates_presence_of :name
end
>> Person.new.errors[:name].any? # => false
>> Person.create.errors[:name].any? # => true

 

2.5 errors[]

上面这段程序还值得关注的是errors。To verify whether or not a particular attribute of an object is valid, you can use errors[:attribute]. It returns an array of all the errors for :attribute. If there are no errors on the specified attribute, an empty array is returned.

 

ruby-1.9.2-p180 :013 > ps = Post.create(:name=>"", :title=>"jess")
 => #<Post id: nil, name: "", title: "jess", content: nil, created_at: nil, updated_at: nil>
ruby-1.9.2-p180 :014 > ps.valid?
 => false

ruby-1.9.2-p180 :015 > ps.errors
 => {:name=>["can't be blank"], :title=>["is too short (minimum is 5 characters)"]}

 

 

3 Validation Helpers

Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object’s errors collection, and this message is associated with the field being validated.

Each helper accepts an arbitrary(任意的) number of attribute names, so with a single line of code you can add the same kind of validation to several attributes.

 

All of them accept the :on and :message options, which define when the validation should be run and what message should be added to the errors collection if it fails, respectively. The :on option takes one of the values :save (the default), :create or :update. There is a default error message for each one of the validation helpers. These messages are used when the :message option isn’t specified. Let’s take a look at each one of the available helpers.

(1)validates_format_of,regular expression

(3)validates_length_of

The default error messages depend on the type of length validation being performed. You can personalize these messages using the :wrong_length, :too_long, and :too_short options and %{count} as a placeholder for the number corresponding to the length constraint being used. You can still use the :message option to specify an error message.

This helper counts characters by default, but you can split the value in a different way using the :tokenizer option.

(4) validates_presence_of

 

If you want to be sure that an association is present, you’ll need to test whether the foreign key used to map the association is present, and not the associated object itself.

class LineItem < ActiveRecord::Base
  belongs_to :order
  validates_presence_of :order_id
end

(5) validates_uniqueness_of

his helper validates that the attribute’s value is unique right before the object gets saved. It does not create a uniqueness constraint in the database, so it may happen that two different database connections create two records with the same value for a column that you intend to be unique. To avoid that, you must create a unique index in your database.

There is a :scope option that you can use to specify other attributes that are used to limit the uniqueness check:
There is also a :case_sensitive option that you can use to define whether the uniqueness constraint will be case sensitive or not. This option defaults to true.

(6)  validates_with

这个辅助方法将数据记录传送给一个单独的类以进行校验。

4 Common Validation Options

4.4 :on

The :on option lets you specify when the validation should happen. The default behavior for all the built-in validation helpers is to be run on save (both when you’re creating a new record and when you’re updating it).

5 Conditional Validation

Sometimes it will make sense to validate an object just when a given predicate is satisfied. You can do that by using the :if and :unless options, which can take a symbol, a string or a Proc.

 

 

6 Creating Custom Validation Methods

You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered.


需要用时,可以进一步研究。

7 Working with Validation Errors

7.1 errors
Returns an OrderedHash with all errors. Each key is the attribute name and the value is an array of strings with all errors.
person.errors
# => {:name => ["can't be blank", "is too short (minimum is 3 characters)"]}
7.2 errors[]errors[] is used when you want to check the error messages for a specific attribute.
7.3 errors.add
The add method lets you manually add messages that are related to particular attributes. You can use the errors.full_messages or errors.to_a methods to view the messages in the form they might be displayed to a user.

Another way to do this is using []= setter

8 Displaying Validation Errors in the View

8.1 error_messages and error_messages_for

You can also use the error_messages_for helper to display the error messages of a model assigned to a view template. It’s very similar to the previous example and will achieve exactly the same result.

在模板中使用:

<%= error_messages_for :product %>

 

 

9 Callbacks Overview

Callbacks are methods that get called at certain moments of an object’s life cycle. With callbacks it’s possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.

 

 

9.1 Callback Registration

In order to use the available callbacks, you need to register them. You can do that by implementing them as ordinary methods, and then using a macro-style class method to register them as callbacks.

 

It’s considered good practice to declare callback methods as being protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation.

 

 

10 Available Callbacks

after_save runs both on create and update, but always after the more specific callbacks after_create and after_update, no matter the order in which the macro calls were executed.

 

 

The after_initialize callback will be called whenever an Active Record object is instantiated, either by directly using new or when a record is loaded from the database. It can be useful to avoid the need to directly override your Active Record initialize method.

The after_find callback will be called whenever Active Record loads a record from the database. after_find is called before after_initialize if both are defined.

The after_initialize and after_find callbacks are a bit different from the others. They have no before_* counterparts, and the only way to register them is by defining them as regular methods.



11 Running Callbacks

 

The after_initialize callback is triggered every time a new object of the class is initialized.

 

12 Skipping Callbacks

 

13 Halting Execution

As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model’s validations, the registered callbacks, and the database operation to be executed.

The whole callback chain is wrapped in a transaction. If any before callback method returns exactly false or raises an exception, the execution chain gets halted and a ROLLBACK is issued; after callbacks can only accomplish that by raising an exception.

 

这个带来的影响还需要进一步估计,比如操作或者交易的中途中断。

 

14 Relational Callbacks

建立两个model直接的callback关系,但就以下的例子而言,说明不了什么问题。 User.destroy后,因为:dependent => :destroy,所以对应的Post也会被删除,间而  after_destroy :log_destroy_action被触发。由此可见,after_destroy本质上还是由post自身的destroy引起的。

 

 

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 Conditional Callbacks

You can do that by using the :if and :unless options, which can take a symbol, a string or a Proc.

 

16 Callback Classes

Sometimes the callback methods that you’ll write will be useful enough to be reused by other models. Active Record makes it possible to create classes that encapsulate the callback methods, so it becomes very easy to reuse them.

两种方法:

(1)定义为一个实例方法

Note that we needed to instantiate a new PictureFileCallbacks object, since we declared our callback as an instance method.

(2)定义为一个类方法

You can declare as many callbacks as you want inside your callback classes.

 

这一部分,guide也是没有说详细,定义的回调类中的方法和回调声明之间肯定有着紧密联系,才能实现一一对应的。以下这句,其实也从侧面说明,类中回调方法必须是与回调声明一致。

When declared inside a class, the callback method will receive the model object as a parameter.

17 Observers

 

Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn’t directly related to its purpose, observers allow you to add the same functionality outside of a model. For example, it could be argued that a User model should not include code to send registration confirmation emails.

适用场合:

Whenever you use callbacks with code that isn’t directly related to your model, you may want to consider creating an observer instead.

17.1 Creating Observers

As with callback classes, the observer’s methods receive the observed model as a parameter. 

 

Observers are conventionally placed inside of your app/models directory and registered in your application’s config/application.rb file.

As usual, settings in config/environments take precedence over those in config/application.rb. So, if you prefer that an observer doesn’t run in all environments, you can simply register it in a specific environment instead.

 

By default, Rails will simply strip “Observer” from an observer’s name to find the model it should observe. However, observers can also be used to add behaviour to more than one model, and so it’s possible to manually specify the models that our observer should observe.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 












 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 








 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 








原创粉丝点击