ActiveRecord Trong Rails
ActiveRecord là một phần của Rails nó sẽ đảm nhiệm việc mapping giữa các đối tượng với các bảng trong cơ sở dữ liệu. Nó còn được gọi là object-relation-mapping. Trong Rails app ta sử dụng ActiveRecord trong model (trong đó có domain object và nghiệp vụ logic), ý tưởng ở đây chính là làm việc trên ...
ActiveRecord là một phần của Rails nó sẽ đảm nhiệm việc mapping giữa các đối tượng với các bảng trong cơ sở dữ liệu. Nó còn được gọi là object-relation-mapping. Trong Rails app ta sử dụng ActiveRecord trong model (trong đó có domain object và nghiệp vụ logic), ý tưởng ở đây chính là làm việc trên các đối tượng để quản lý nghiệp vụ logic, còn sử dụng ActiveRecord để đảm bảo các đối tượng đó được lưu (persisted) xuống database.
I.1 ActiveRecord::Base
ActiveRecord::Base là thành phần quan trọng nhất trong ActiveRecord. Nó không chỉ chưa các class method phục vụ việc kết nối với database mà nó còn là base class của các mapped class (User, Product ..)
class Duck < ActiveRecord::Base validates_length_of :name, maximum: 6 end
Trong ví dụ trên thì validates_length_of( ) là một Class Macro, nó đảm bảo trường name không vượt quá 6 ký tự.
ActiveRecord sẽ tự động map các đối tượng Duck vào trong bảng ducks của database, ActiveRecord cũng định nghĩa các Ghost Method để truy cập vào các trường.
Giờ hãy nhìn vào ví dụ trên bạn sẽ nghĩ rằng validates_length_of là một method của ActiveRecord::Base thế nhưng thực tế thì không phải vậy nó nằm trong module ActiveRecord::Validation, ActivRecor::Validation validate các trường bên trong model không phải trong database, Như ở ví dụ trên thì trong database trường name của bảng ducks vẫn có thể dài hơn 6 ký tự, bạn có thể thêm vào bằng cách thêm thủ công bằng câu lệnh sql.
Giả sử model của bạn kế thừa ActiveRecord::Base class, autoload sẽ load activerecord/base.rb file và sẽ định nghĩa một class Base
module ActiveRecord class Base class << self # Class methods def find(*args) # ... def first(*args) # ... def last(*args) # ... end public def id # ... def save # ... def save! # ... def delete # ... # ... end end end
I.2 ActiveRecord::Validations
duck = Duck.new(name: "Conan") duck.valid?
Như phần trên ta đã đề cập tới method validates_length_of ( ) nó nằm trong ActiveRecord::Validation, điều này là do khi kế thừa từ ActiveRecord::Base, class Base đã include module Validations
module ActiveRecord Base.class_eval do # ... include Validations include Locking::Optimistic, Locking::Pessimistic include AttributeMethods include Dirty include Callbacks, Observing, Timestamp # ... end end
Khi ActiveRecord:Base includes ActiveRecord::Validations nó sẽ thêm các instance methods và class methods vào trong ActiveRecord::Base. Đồng thời thì Active::Validations::Included() cũng include module ActiveSupport::Callbacks, điều này suy ra ActiveRecord::Base cũng includes ActiveRecord::Callbacks
ActiveRecord::Validations module sử dụng các alias method, các phương thức mà bạn hay sử dụng như save(), save()! thực ra là bạn đang gọi alias method.
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 def save_with_validation(perform_validation = true) # ... # ... end
II.1 Dynamic Attributes
Xét ví dụ sau:
class Task < ActiveRecord::Base end
task = Task.new task.description = 'Clean up garage' task.completed = true task.save
Các phương thức description=() hay completed? thực ra là các Ghost Mehthods . Lần đầu nó được gọi thông qua method_missing() của ActiveRecord::Base và sau đó nó sẽ gọi phương thức define_attribute_methods ( )
phương thức này sẽ định nghĩa phương thức read, write cho các trường trong database. Trong các lần gọi tiếp theo khi bạn gọi phương thức description() hay bất kỳ một thức nào khác được map với các cột trong database nó sẽ không gọi thông qua method_missing() nữa mà nó gọi phương thức thực (đã được định nghĩa thông qua define_attribute_methods())
Khi đi vào method_missing thì description method trong ví dụ trên trở thành một Ghost Method, Sau đó method_missing() sẽ gọi Dynamic Dispatch (sử dụng send() method), Việc gọi này chỉ được thực thi một lần cho mỗi class kế thừa từ ActiveRecord::Base.
II.2 Dynamic Finders
ActiveRecord cũng cung cấp cá dynamic finders, bằng cách gọi phương thức find kết hợp với tên của các attriubtes
task = Task.find_by_description("clean") Task.find_by_description_and_completed('Clean' , true) #...
Các phương thức find này được định nghĩa trong mising_method (để biết rõ hơn bạn có thể xem trong lib của Rails), tên của phương thức phải được bắt đầu bằng find theo sau là các attributes Sau đó nó sẽ định các phương thức find thực như find_by_description, find_by_completed ..
References
Metaprograming
Rubydoc
Stackoverflow