Tìm hiểu thêm về gem Paranoia

Trong công việc, đôi khi bạn phải sử dụng gem Paranoia việc hiểu thêm về gem này gíup bạn chủ động hơn trong công việc.

Link: https://github.com/rubysherpas/paranoia

Gem Paranoia đơn gỉan là thêm cột deleted_at vào bảng mà chúng ta muốn đánh dấu đã bị xóa đi.

Đầu tiên, paranoia thêm một class method cho class ActiveRecord::Baseself.acts_as_paranoid (https://github.com/rubysherpas/paranoia/blob/core/lib/paranoia.rb#L209):

class ActiveRecord::Base
  def self.acts_as_paranoid(options={})
    ...
    def self.paranoia_scope
      where(paranoia_column => paranoia_sentinel_value)
    end
    ...

    unless options[:without_default_scope]
      default_scope { paranoia_scope }
    end
  ...
  end
end

Do vậy trong model mỗi khi ta khai báo acts_as_paranoid thì class method này sẽ chạy. Ta cũng có thể gọi ngoài console như một method bình thường vì các model của ta viết đều kế thừa ActiveRecord::Base.

Việc thêm default_scope để loại bỏ những record theo setting của Paranoia. Giả sử đã add acts_as_paranoid vào model Order, khi gọi 1 câu scope bất kỳ từ bảng Order ta đều thấy:

2.3.1 :001 > Order.all
  Order Load (1.9ms)  SELECT `t_order`.* FROM `t_order` WHERE `t_order`.`deleted_at` IS NULL

Muốn bỏ paranoia scope này đơn gỉan ta chỉ cần gọi unscoped.

2.3.1 :002 > Order.all.unscoped
  Order Load (7.3ms)  SELECT `t_order`.* FROM `t_order`

Đối với những model chưa add acts_as_paranoid ta chỉ việc gọi method này, thử đối với model Okan, trước khi goi method này:

2.3.1 :001 > Okan.first
  Okan Load (0.2ms)  SELECT  `t_okan`.* FROM `t_okan`  ORDER BY `t_okan`.`okan_id` ASC LIMIT 1

Sau đó gọi method acts_as_paranoid ta thấy câu query đã thay đổi:

2.3.1 :002 > Okan.acts_as_paranoid
 => [Okan(okan_id: string, member_id: string, ...
2.3.1 :003 > Okan.first
  Okan Load (1.1ms)  SELECT  `t_okan`.* FROM `t_okan` WHERE `t_okan`.`deleted_at` IS NULL  ORDER BY `t_okan`.`okan_id` ASC LIMIT 1

Ta chú ý thấy trong câu query trên có đoạn WHERE t_okan.deleted_at IS NULL, đây là default_scopeparanoia thêm vào, tên column để gem này check được set tại (https://github.com/rubysherpas/paranoia/blob/core/lib/paranoia.rb#L217) self.paranoia_column = (options[:column] || :deleted_at).to_s, muốn thay đổi ta chỉ cần thêm vào khi gọi method acts_as_paranoid

2.3.1 :001 > Okan.acts_as_paranoid column: :my_column
2.3.1 :002 > Okan.first
  Okan Load (7.2ms)  SELECT  `t_okan`.* FROM `t_okan` WHERE `t_okan`.`my_column` IS NULL  ORDER BY `t_okan`.`okan_id` ASC LIMIT 1

Muốn xem gía trị của column ta chỉ cần gọi Okan.paranoia_column

2.3.1 :003 > Okan.paranoia_column
 => "my_column"

Giá trị để paranoia check xem record đã bị xóa hay chưa được set tại: (https://github.com/rubysherpas/paranoia/blob/core/lib/paranoia.rb#L218) self.paranoia_sentinel_value = options.fetch(:sentinel_value) { Paranoia.default_sentinel_value }, muốn thay đổi ta cũng làm như trên.

2.3.1 :006 > Okan.acts_as_paranoid sentinel_value: 'my_value'
 => [Okan(okan_id: string, member_id: string, ...
2.3.1 :007 > Okan.first
  Okan Load (1.9ms)  SELECT  `t_okan`.* FROM `t_okan` WHERE `t_okan`.`deleted_at` = 'my_value'  ORDER BY `t_okan`.`okan_id` ASC LIMIT 1

Muốn xem gía trị của sentinel_value ta chỉ cần gọi Okan.paranoia_sentinel_value

2.3.1 :006 > Okan.paranoia_sentinel_value
 => 'my_value'

Khi destroy record, paranoia overide lại hàm destroy (https://github.com/rubysherpas/paranoia/blob/core/lib/paranoia.rb#L104):

def restore!(opts = {})
  self.class.transaction do
    ...
        write_attribute paranoia_column, paranoia_sentinel_value
    ...
  end
end

Đoạn code write_attribute paranoia_column, paranoia_sentinel_value chính là update cột được định nghĩa tại paranoia_column gía trị được định nghĩa tại paranoia_sentinel_value.

Cảm ơn và hi vọng bài viết có ích cho công việc của bạn.


All Rights Reserved