Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #17918 - Smart class parameters should appear in audits #4165

Merged
merged 1 commit into from
Jul 12, 2017

Conversation

orrabin
Copy link
Member

@orrabin orrabin commented Jan 9, 2017

No description provided.

@mention-bot
Copy link

@orrabin, thanks for your PR! By analyzing the history of the files in this pull request, we identified @domcleal, @isratrade and @dLobatog to be potential reviewers.

Copy link
Member

@tbrisker tbrisker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good in general, just a couple of comments inline

@@ -0,0 +1,12 @@
class FixLookupKeyAuditableType < ActiveRecord::Migration
def up
Audit.where(:auditable_type => 'LookupKey').each do |audit|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would potentially load a very large amount of audits from the DB to check their types. would it be possible to perform this in the database without loading all of the audits and going over them one by one? (maybe change all the puppetLKs in one query and all the variableLKs in a second?) If it isn't possible, please use find_each instead of each so at least this is done in batches.

@@ -67,6 +67,8 @@ def fix_auditable_type
self.associated_type = "Host" if associated_type =~ /Host::/
self.auditable_type = auditable.type if auditable_type == "Taxonomy" && auditable
self.associated_type = auditable.type if auditable_type == "Taxonomy" && auditable
self.auditable_type = auditable.type if auditable_type == "LookupKey" && auditable
self.associated_type = auditable.type if auditable_type == "LookupKey" && auditable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps refactor these 4 lines to something like this?

self.auditable_type = self.associated_type = auditable.type if auditable && ['LookupKey', 'Taxonomy'].includes? auditable_type

@orrabin
Copy link
Member Author

orrabin commented Jan 16, 2017

@tbrisker thanks, I fixed you comments.

Copy link
Member

@tbrisker tbrisker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more sql optimization :)

lookup_key_ids = Audit.where(:auditable_type => 'LookupKey').pluck(:auditable_id).uniq

puppetclass_lookup_key_ids = PuppetclassLookupKey.where(:id => lookup_key_ids).pluck(:id)
Audit.where(:auditable_type => 'LookupKey', :auditable_id => puppetclass_lookup_key_ids).update_all(:auditable_type => 'PuppetclassLookupKey')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about something like:

Audit.joins('JOIN lookup_keys ON lookup_keys.id = audits.auditable_id').where(:auditable_type => 'LookupKey', :lookup_keys => {:type => 'VariableLookupKey'}).reorder(nil)

Also, make sure to reorder(nil) on all the queries to remove the default order scope.


Audit.reorder(nil).joins('JOIN lookup_keys ON lookup_keys.id = audits.auditable_id')
.where(:auditable_type => 'LookupKey', :lookup_keys => {:type => 'PuppetclassLookupKey'})
.update_all(:auditable_type => 'PuppetclassLookupKey')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Place the . on the previous line, together with the method call receiver.

.update_all(:auditable_type => 'VariableLookupKey')

Audit.reorder(nil).joins('JOIN lookup_keys ON lookup_keys.id = audits.auditable_id')
.where(:auditable_type => 'LookupKey', :lookup_keys => {:type => 'PuppetclassLookupKey'})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Place the . on the previous line, together with the method call receiver.

def up
Audit.reorder(nil).joins('JOIN lookup_keys ON lookup_keys.id = audits.auditable_id')
.where(:auditable_type => 'LookupKey', :lookup_keys => {:type => 'VariableLookupKey'})
.update_all(:auditable_type => 'VariableLookupKey')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Place the . on the previous line, together with the method call receiver.

class FixLookupKeyAuditableType < ActiveRecord::Migration
def up
Audit.reorder(nil).joins('JOIN lookup_keys ON lookup_keys.id = audits.auditable_id')
.where(:auditable_type => 'LookupKey', :lookup_keys => {:type => 'VariableLookupKey'})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Place the . on the previous line, together with the method call receiver.


Audit.reorder(nil).joins('JOIN lookup_keys ON lookup_keys.id = audits.auditable_id')
.where(:auditable_type => 'LookupKey', :lookup_keys => {:type => 'PuppetclassLookupKey'})
.update_all(:auditable_type => 'PuppetclassLookupKey')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried to get the two queries into one with update_all('auditable_type = lookup_keys.type') but: rails/rails#13496

@@ -136,6 +136,10 @@ def audited_type(audit)
"#{audit.associated_type || 'Global'}-#{type_name}"
when 'LookupKey'
'Smart Variable'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping this because of old audits that don't have a connected lookup key and therefore I can't determine their type.

self.auditable_type = auditable.type if auditable_type == "Taxonomy" && auditable
self.associated_type = auditable.type if auditable_type == "Taxonomy" && auditable
self.auditable_type = auditable.type if auditable && ["Taxonomy", "LookupKey"].include?(auditable_type)
self.associated_type = auditable.type if auditable && ["Taxonomy", "LookupKey"].include?(auditable_type)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after some debugging, looks like while this condition is always false, actually a side effect of the auditable call is what caused this to work correctly, possibly because it led to a reload of the auditable object. Otherwise the save fails. Some preliminary testing indicated that moving this callback from after_validation to before_save allows removing the second auditable call and saving the object correctly, but this needs to be checked to make sure this doesn't cause other things to break.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be changed anyway for: http://projects.theforeman.org/issues/19354

One thing I could think of that could break is the callbacks we have today on before_save that might have counted on auditable being accessed in this callback.
I moved the callback and did a few create/update/delete that showed up correctly in the audits and didn't see anything break right away.

Copy link
Member

@ShimShtein ShimShtein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, a few suggestions though.

@@ -95,8 +95,8 @@ def fix_auditable_type
# STI Host class should use the stub module instead of Host::Base
self.auditable_type = "Host" if auditable_type =~ /Host::/
self.associated_type = "Host" if associated_type =~ /Host::/
self.auditable_type = auditable.type if auditable_type == "Taxonomy" && auditable
self.associated_type = auditable.type if auditable_type == "Taxonomy" && auditable
self.auditable_type = auditable.type if auditable && ["Taxonomy", "LookupKey"].include?(auditable_type)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can drop auditable &&, if you fix two issues:

  1. Remove duplicate deletion from puppetclass_importer, as you have already fixed this in b5f207d
  2. Add default value to :type column in :lookup_key factory

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&& auditable was already in the code, it's a good suggestion to refactor it but could lead to a lot of changes in unrelated tests and might affect taxonomy as well so I'd rather have it in a separate pr.

I'll move it to the end to avoid calling auditable again for anything but taxonomy and lookup keys.

self.auditable_type = auditable.type if auditable_type == "Taxonomy" && auditable
self.associated_type = auditable.type if auditable_type == "Taxonomy" && auditable
self.auditable_type = auditable.type if auditable && ["Taxonomy", "LookupKey"].include?(auditable_type)
self.associated_type = auditable.type if auditable && ["Taxonomy", "LookupKey"].include?(auditable_type)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line looks a bit odd - you are setting :associated field to the type of :audited object.
It's unrelated to this PR, let's track it as a separate bug here.

@ShimShtein
Copy link
Member

👍 ACK. Works as expected, no more comments.

@orrabin
Copy link
Member Author

orrabin commented Jul 12, 2017

@tbrisker all your comments are now addressed.

@tbrisker tbrisker merged commit 364c520 into theforeman:develop Jul 12, 2017
@tbrisker
Copy link
Member

Thanks @orrabin !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants