Rails 审核批量创建
Rails audited create in batch
我使用 rails 5 / 审核 4.6.5
我一次对 2000 多个项目进行了批量操作。
为了使其可用,我需要使用 updatre_all 函数。
那么,我想一次性创建需要的audited
我想做的是这样的事情:
Followup.where(id: ids).in_batches(of: 500) do |group|
#quick update for user responsiveness
group.update_all(step_id: 1)
group.delay.newAudits(step_id: 1)
end
但经过审核的 gem 看起来很基础。
我敢肯定很多人以前都遇到过这样的问题
在 group.update_all
中,您的回调将被跳过,并且不会最终记录新审计中的更改。
您不能为这些记录手动创建审核,即使您可以手动创建审核更改,您也需要 "what changed?" 的参考(进入 audited_changes
)。但是当您之前在 group
上执行 update_all
时,这些更改已经丢失。
(`action`, `audited_changes`, `auditable_id`, `auditable_type`, `created_at`, `version`, `request_uuid`)
在这个audited issue - https://github.com/collectiveidea/audited/issues/352
中也有记载
paper_trail, another such gem which retains change_logs, also has this issue: https://github.com/airblade/paper_trail/issues/337
经过多次迭代,我设法创建了一个优化查询。
我把它放在 AditBatch class 中,还添加了延迟
class AuditBatch
############################################
## Init a batch update from a list of ids
## the aim is to avoid instantiations in controllers
## @param string class name (eq: 'Followup')
## @param int[] ids of object to update
## @param changet hash of changes {key1: newval, key2: newval}
############################################
def self.init_batch_creation(auditable_type, auditable_ids, changes)
obj = Object.const_get(auditable_type)
group = obj.where(id: auditable_ids)
AuditBatch.delay.batch_creation(group, changes, false)
end
############################################
## insert a long list of audits in one time
## @param group array array of auditable objects
## @param changet hash of changes {key1: newval, key2: newval}
############################################
def self.batch_creation(group, changes, delayed = true)
sql = 'INSERT INTO audits ("action", "audited_changes", "auditable_id", "auditable_type", "created_at", "version", "request_uuid")
VALUES '
total = group.size
group.each_with_index do |g, index|
parameters = 'json_build_object('
length = changes.size
i=1
changes.each do |key, val|
parameters += "'#{key}',"
parameters += "json_build_array("
parameters += "(SELECT ((audited_changes -> '#{key}')::json->>1) FROM audits WHERE auditable_id = #{g.id} order by id desc limit 1),"
parameters += val.is_a?(String) ? "'#{val.to_s}'" : val.to_s
parameters += ')'
parameters += ',' if i < length
i +=1
end
parameters += ')'
sql += "('update', #{parameters}, #{g.id}, '#{g.class.name}', '#{Time.now}', (SELECT max(version) FROM audits where auditable_id= #{g.id})+1, '#{SecureRandom.uuid}')"
sql += ", " if (index+1) < total
end
if delayed==true
AuditBatch.delay.execute_delayed_sql(sql)
else
ActiveRecord::Base.connection.execute(sql)
end
end
def self.execute_delayed_sql(sql)
ActiveRecord::Base.connection.execute(sql)
end
end
我使用 rails 5 / 审核 4.6.5 我一次对 2000 多个项目进行了批量操作。 为了使其可用,我需要使用 updatre_all 函数。
那么,我想一次性创建需要的audited
我想做的是这样的事情:
Followup.where(id: ids).in_batches(of: 500) do |group|
#quick update for user responsiveness
group.update_all(step_id: 1)
group.delay.newAudits(step_id: 1)
end
但经过审核的 gem 看起来很基础。 我敢肯定很多人以前都遇到过这样的问题
在 group.update_all
中,您的回调将被跳过,并且不会最终记录新审计中的更改。
您不能为这些记录手动创建审核,即使您可以手动创建审核更改,您也需要 "what changed?" 的参考(进入 audited_changes
)。但是当您之前在 group
上执行 update_all
时,这些更改已经丢失。
(`action`, `audited_changes`, `auditable_id`, `auditable_type`, `created_at`, `version`, `request_uuid`)
在这个audited issue - https://github.com/collectiveidea/audited/issues/352
中也有记载paper_trail, another such gem which retains change_logs, also has this issue: https://github.com/airblade/paper_trail/issues/337
经过多次迭代,我设法创建了一个优化查询。 我把它放在 AditBatch class 中,还添加了延迟
class AuditBatch
############################################
## Init a batch update from a list of ids
## the aim is to avoid instantiations in controllers
## @param string class name (eq: 'Followup')
## @param int[] ids of object to update
## @param changet hash of changes {key1: newval, key2: newval}
############################################
def self.init_batch_creation(auditable_type, auditable_ids, changes)
obj = Object.const_get(auditable_type)
group = obj.where(id: auditable_ids)
AuditBatch.delay.batch_creation(group, changes, false)
end
############################################
## insert a long list of audits in one time
## @param group array array of auditable objects
## @param changet hash of changes {key1: newval, key2: newval}
############################################
def self.batch_creation(group, changes, delayed = true)
sql = 'INSERT INTO audits ("action", "audited_changes", "auditable_id", "auditable_type", "created_at", "version", "request_uuid")
VALUES '
total = group.size
group.each_with_index do |g, index|
parameters = 'json_build_object('
length = changes.size
i=1
changes.each do |key, val|
parameters += "'#{key}',"
parameters += "json_build_array("
parameters += "(SELECT ((audited_changes -> '#{key}')::json->>1) FROM audits WHERE auditable_id = #{g.id} order by id desc limit 1),"
parameters += val.is_a?(String) ? "'#{val.to_s}'" : val.to_s
parameters += ')'
parameters += ',' if i < length
i +=1
end
parameters += ')'
sql += "('update', #{parameters}, #{g.id}, '#{g.class.name}', '#{Time.now}', (SELECT max(version) FROM audits where auditable_id= #{g.id})+1, '#{SecureRandom.uuid}')"
sql += ", " if (index+1) < total
end
if delayed==true
AuditBatch.delay.execute_delayed_sql(sql)
else
ActiveRecord::Base.connection.execute(sql)
end
end
def self.execute_delayed_sql(sql)
ActiveRecord::Base.connection.execute(sql)
end
end