+2

Thêm thuộc tính động vào Model ActiveRecord Rails

Trong quá trình làm việc thì chắc hẳn ai trong chúng ta cũng đã gặp trường hợp không thể nắm bắt hết tất cả các thuộc tính của 1 model hoặc thuộc tính sẽ phát sinh trong quá trình xây dựng ứng dụng. Một ví dụ điển hình là hệ thống theo dõi các địa chỉ liên lạc có một model Contact bao gồm name, email, phone... Đặt trường hợp là ở đây chúng ta không thể biết trước được các thuộc tính mà model Contact chúng ta cần phải có.

Configuring model

Đầu tiên chúng ta cần cài đặt active_dymamic game

gem 'active_dynamic'
$ bundle

Sau đó chạy lệnh

rails generate active_dynamic rake db:migrate

Nó sẽ copy migration và configuration files vào dự án sau đó chạy migration Tiếp theo chúng ta tạo model Contact và thêm has_dynamic_attributes vào

class Contact < ActiveRecord::Base  
  has_dynamic_attributes
end

Bây giờ chúng ta cần phải cho active_dynamic biết nơi để tìm thông tin về các thuộc tính mà nó cần thêm vào model Contact. Để làm điều đó, chúng ta tạo ra một lớp cung cấp dịch vụ mà phải tuân thủ hai quy tắc:

  • Nó cần phải chấp nhận một model class như là đối số khởi tạo duy nhất
  • Nó cần phải có phương thức call trả về một mảng các định nghĩa thuộc tính

Định nghĩa thuộc tính chỉ là một lớp helper cho phép chỉ định tên hiển thị của một thuộc tính sẽ được tự động thêm vào model của chúng ta, và tùy chọn kiểu dữ liệu của nó, tên hệ thống, xác nhận sự hiện diện và giá trị mặc định. Dưới đây là provider class đơn giản xác định thuộc tính age và description:

class ContactAttributeProvider

  def initialize(model)
    @model = model    
  end

  def call
    [
      ActiveDynamic::AttributeDefinition.new('age', datatype: ActiveDynamic::DataType::Integer, default_value: 18),
      ActiveDynamic::AttributeDefinition.new('description')
    ]
  end

end

Để làm cho chúng trở nên thực sự năng động, chúng ta có thể tải các định nghĩa thuộc tính từ bộ nhớ ngoài - cơ sở dữ liệu, tệp YAML, cấu hình XML hoặc cái gì đó khác. Trong ứng dụng demo, chúng ta sử dụng một bảng contact_attributes để lưu và thao tác danh sách các định nghĩa thuộc tính, do đó, ContactAttributeProvider sẽ như sau:

class ContactAttributeProvider
  
  def initialize(model)    
    @model = model  
  end   
  def call    
    ContactAttribute.all.map do |attr|
      ActiveDynamic::AttributeDefinition.new(
        attr.name, datatype: attr.datatype, 
        required: attr.required?)
    end 
  end
end

Cuối cùng, chúng ta cần phải cho active_dynamic sử dụng lớp provider này. Trong tập tin cấu hình config / initializers / active_dynamic.rb thêm dòng:

config.provider_class = ContactAttributeProvider

Bây giờ mỗi khi một thể hiện của Liên hệ được tạo ra, nó sẽ có bất cứ thuộc tính nào bạn liệt kê trong lớp cung cấp thuộc tính của bạn. Vì vậy, bây giờ chúng ta có thể sử dụng nó như thế này:

contact = Contact.new
# first_name is a regular attribute mapped to 
# a column in contacts table
contact.first_name = 'John'
# age attribute was added dynamically
contact.age = 27
contact.save
# we can also do this
second_contact = Contact.new(first_name: 'Jane', age: 25)

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí