The Design of ActiveRecord
Giới thiệu về ActiveRecord ActiveRecord là một phần của Rails mà sẽ làm nhiệm vụ trừu tượng hóa trong việc thao tác với các bảng cơ sở dữ liệu. Chức năng này được gọi là lập quan hệ với đối tượng, và nó cho phép bạn có thể sử dụng được cả 2 cách liên kết là object-data và object-oriented ...
Giới thiệu về ActiveRecord
ActiveRecord là một phần của Rails mà sẽ làm nhiệm vụ trừu tượng hóa trong việc thao tác với các bảng cơ sở dữ liệu. Chức năng này được gọi là lập quan hệ với đối tượng, và nó cho phép bạn có thể sử dụng được cả 2 cách liên kết là object-data và object-oriented programming.
Chúng ta có thể sử dụng ActiveRecord trong một ứng dụng Rails hay một phần của ứng dụng định kỳ. Trong một ứng dụng Rails, chúng ta có thể sử dụng ActiveRecord trong phần model của mô hình thiết kế MVC(Model - View - Controller). Ý tưởng ở đây là chúng ta sử dụng các đối tượng ruby để quản lý logic và sử dụng ActiveRecord đảm bảo để các đối tượng được luu vào trong database.
Giả sử chúng ta có một database SQLite với một bảng dữ liệu là ducks và trong bảng có một trường tên là name, Chúng ta có thể sử dụng ActiveRecord và mở kết nối với database.
require 'activerecord' ActiveRecord::Base.establish_connection :adapter => "sqlite3" , :database => "dbfile"
ActiveRecord::Base là một lớp quan trong nhất trong ActiveRecord. Nó không chỉ chứa các methods quan trọng để mở kết nối với database , nó cũng có các phương thức được dùng ở nhiều class khác nhau, như Duck
class Duck < ActiveRecord::Base validates_length_of :name, :maximum => 6 end
phương thức validates_length_of() là một Class Macro, trong trương hợp này trường name trong bảng Duck có độ dài không vượt quá 6 kí tự.
Theo quy ước, ActiveRecord sẽ tự động ánh xạ các đối tượng Duck tới bảng dữ liệu Ducks. Bằng cách nhìn vào lược đồ dữ liệu, và nó cũng tìm thấy thuộc tính name trong class Duck, và nó sẽ định nghĩa một phương thức Ghost để truy cập thuộc tính này. Và nhờ đó chúng ta có thể sử dụng lớp Duck để lưu thông tin.
my_duck = Duck.new my_duck.name = "Test" my_duck.valid? # => true my_duck.save!
ActiveRecord::Base
Đầu tiền, các classes và methods trong ActiveRecord có thế làm chúng ta mất phương hướng,nếu như nhìn vào ví dụ trước chúng ta không tìm thấy phương thức validates_length_of() trong ActiveRecord::Base. Tìm vòng quanh ta có thể thấy method này nằm trong ActiveRecord::Validations. Khi gọi require 'active_record' thì tất cả các module được khai báo trong namespace ActiveRecord sẽ được tự tải.
module ActiveRecord autoload :Base, 'active_record/base' autoload :Batches, 'active_record/batches' autoload :Calculations, 'active_record/calculations' autoload :Callbacks, 'active_record/callbacks' # ... autoload :Timestamp, 'active_record/timestamp' autoload :Transactions, 'active_record/transactions' autoload :Validations, 'active_record/validations' # ... end
ActiveRecord sẽ tải từng module thông qua phương thức autoload(), phương thức này giúp chúng ta loại bỏ nhiều file mà chúng ta thật sự không cần thết khi load nhiều file cùng một lúc. Nó đảm bảo các module và các file sẽ được load khi chúng ta dùng tới.
module ActiveRecord class Base class << self # Class methods def find(*args) # ... def first(*args) # ... # ... end public def id # ...
ActiveRecord::Base định nghĩa một danh sách dài các phương thức class như là find(), first()... nó cũng khai báo một loạt các instance methods như save(), delete(). Tuy nhiên, chúng cũng chỉ là một phần nhỏ trong ActiveRecord::Base.
ActiveRecord::Validations
Trong phần trên, chúng ta đã sử dụng 2 phương thức valid?() và validates_length_of(), đây là 2 phương thức được khai báo trong module ActiveRecord::Validations
module ActiveRecord module Validations def self.included(base) base.extend ClassMethods base.class_eval do alias_method_chain :save, :validation alias_method_chain :save!, :validation end base.send :include, ActiveSupport::Callbacks # ... end end end
Vậy chúng ta xem cơ chế làm viêc của ActiveRecord sẽ như thế nào. Đầu tiên, ActiveRecord::Validations sẽ định nghĩa các instance method giống như valid?(), sau đó khi 'ActiveRecord::Validations' được include vào trong ActiveRecord::Base thì mặc đinh ActiveRecord::Base sẽ có các instance method và class method của ActiveRecord::Validations.
alias_method_chain()
Để hiểu rõ hơn về alias_method_chain(), chúng ta xét ví dụ sau
class MyClass def greet puts "Hello!" end end MyClass.new.greet => Hello!
Mục đích bây giờ của chúng ta là thao tác với hàm MyClass#greet(), với Alias chúng ta có thể làm
module Module def alias_method_chain(target, feature) aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ' ), $1 yield(aliased_target, punctuation) if block_given? with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}" , "#{aliased_target}_without_#{feature}#{punctuation}" alias_method without_method, target alias_method target, with_method end end
Chúng ta hãy xem cách mà alias_method_chain() làm việc. Đầu tiên, chúng sẽ loại bỏ các ký tự đặc biệt ở cuối tên name của phương thức để đẩy nó vào cuối của alias mới. sau đó nó sẽ tính toán tên cho tất cả các aliases, rồi tiếp tục là các phương thức. cuối cùng là việc là việc thiết lập khả năng hoạt động của phương thức.