Rails每周闲碎(二): Model

1. model validates

 

    Rails的model提供了多种validate方法。 比如:

 

    validates_acceptance_of :terms_of_service    # 对于checkbox的印证,再合适不过了。

 

    validate_confirmation_of  #password confirmation

 

    validates_associated  #对assocation的validates。

 

    在save过程中,model的validates先于before_save, before_create这些callback被调用。

 

    我们还可以定置自己的validate方法:

 

    validates_positive_or_zero :number  #在lib/validations.rb里面加上这个方法即可。

 

    或者 validates :your_method  #在这个methods里面加上印证,如果失败,往erros里面添加错误信息。

 

 

2. ActiveRecord的callbacks

 

       要注意各个callback的正确使用,比如:  不要指望after_create保存在对象上所做的改变,除非你显式调用save。因为after_create的调用是在base.save之后。

 

 

      after_initialize, after_find

 

      http://guides.rubyonrails.org/activerecord_validations_callbacks.html#after-initialize-and-after-find

 

      This behaviour is due to performance reasons, since after_initialize and after_find will both be called for each record found in the database, significantly slowing down the queries.

 

      save & validation

 

      Rails ActiveRecord callback sequence  validation callback is before save callback

 

3. Association

 

    has_many和has_one的validate默认值不同。

 

    比如有两个对象之间的关联是这样的:

 

 

class Company

    has_many :people
    has_one :address

end

 

    当我们在controller里面这样创建它们时:

 

def create

   @person = Person.new(params[:person])
   @company = Company.new(params[:person][:company])
   @address = Address.new(params[:person][:company][:address])

   @company.people << @person
   @company.address = @address
   
   @company.save!
   
end

 

    不要以为address会被验证,其实对于has_one关联,默认的validate为false。

 

    所以,我们要显示得指定:

 

has_one :address, :validate => true

 

 

    注意has_one 和 belongs_to的外键所在:

 

    has_one关联,对应的外键在对方表中; belongs_to关联,外键在自身表中。

 

4. Attributes

 

 

   attributes_protected  attributes_accessible

 

    如果你想让某些值可以被mass assign,比如这样person = Person.new(params[:person]),那么你得把它们声明在attributes_accessible里。当然,你也可以不声明任 何的attributes,不过这样会给你带来可能的安全问题。

 

    显而易见,如果只有少部分attributes不允许被mass assign,那么把这些放在attributes_protected里更加方便。

 

 

 

    ActiveRecord::Base中的inspect方法

 

   看源码

 

 

# File vendor/rails/activerecord/lib/active_record/base.rb, line 2850
def inspect
       attributes_as_nice_string = self.class.column_names.collect { |name|
        if has_attribute?(name) || new_record?
             "#{name}: #{attribute_for_inspect(name)}"
          end
         }.compact.join(", ")
        "#<#{self.class} #{attributes_as_nice_string}>"
en
 

 

    明白了么,如果是不在数据库中的attribute,它是不会打出来给你看的~~~

 

 

    Boolean column:

 

    Rails does a nifty thing with boolean columns: it supports the Ruby question mark convention for object attributes that return a boolean Ruby value.

 

    Type attribute:

 

    为什么不能用self.type?因为type是ruby的保留方法,它会返回类型信息。所以,要取得对象内的type attribute,就得用self[:type]。可以看出,所有的attributes,都可以用hash的方式取出。

 

 

 

5. Find方法中的select option

 

    有时候为了执行效率,我们会指定select的字段。对于纯粹的数据读取,这没问题。但如果还会对读取之后的数据进行更新,则需要注意,不要在select中落下id字段。

 

    比如:

 

person = Person.find(:first, :select => "first_name, last_name")
person.update_attribute :first_name, person.first_name.downcase

 

    你会发现第二个语句的执行sql是:

 

update people set first_name = 'bo' where id = nil

 

    这会导致对person的更新不能成功。

 

    正确的操作是:

 

person = Person.find(:first, :select => "id, first_name, last_name")
person.update_attribute :first_name, person.first_name.downcase

 

 

 

    则更新操作就会成功:

 

update people set first_name = 'bo' where id = 12

 

 

6. save(false), save and save!

 

    save(false): skip model validation

    save: donot skip model validation

    save!: raise exception if not valid, create! called it

 

7. new_record?

 

 

      # Returns true if this object hasn't been saved yet -- that is, a record for the object doesn't exist yet.
      def new_record?
        defined?(@new_record) && @new_record
      end

 

 

8. destory, delete

 

    destory: Deletes the record in the database and freezes this instance to reflect that no changes should be made. And particularly, it can set callbacks through before_destroy and after_destroy.

    delete: it simply delete the row in database and freeze the instance. But it does not have any callbacks unless you make it by observers. If you do want callbacks, use destroy.

 

    对于依赖删除的model,如果只是想让关联失效,而不是删除记录,可以使用:nilfy指定。

 

9.  乐观锁,悲观锁机制

 

   http://guides.rubyonrails.org/active_record_querying.html#locking-records-for-update

 

10. Eager loading and N +1

 

 

clients = Client.all(:limit => 10) 
clients.each do |client| 
  puts client.address.postcode 
end 
 

    11 queries

 

     VS

 

 

clients = Client.all(:include => :address, :limit => 10) 
clients.each do |client| 
  puts client.address.postcode 
end 

 

    2 queries:

 

 

SELECT * FROM clients 
SELECT addresses.* FROM addresses WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10)) 

 

    http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

 

11. named_scope

 

    定制一个具名的find方法:http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html#M002177


12. accepts_nested_attributes_for

 

    Make complex form easier.   http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#M002132

 

 

 

你可能感兴趣的:(html,Ruby,Rails,ActiveRecord,performance)