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

Migrate existing dialog field association data to use new relationship #80

Conversation

d-m-u
Copy link
Contributor

@d-m-u d-m-u commented Sep 27, 2017

The planned targeted auto-refresh enhancement to dialog fields requires the dialog fields to be able to be associated to one another. This migration takes our old system of relating dialog fields by order-dependent auto_refresh and trigger_auto_refresh fields and updates them to use the recently added DialogFieldAssociation table. It's worth noting that this may not upgrade all existing dialog associations correctly and that it may be necessary to manually check and possibly fix some of the associations not caught by this migration.

@d-m-u d-m-u changed the title Migrate existing dialog field association data to use new relationship [WIP] Migrate existing dialog field association data to use new relationship Sep 27, 2017
@miq-bot miq-bot added the wip label Sep 27, 2017
@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch from 9a6e96c to fb00efd Compare September 27, 2017 15:08
@d-m-u d-m-u changed the title [WIP] Migrate existing dialog field association data to use new relationship Migrate existing dialog field association data to use new relationship Sep 27, 2017
@d-m-u d-m-u changed the title Migrate existing dialog field association data to use new relationship [WIP] Migrate existing dialog field association data to use new relationship Sep 27, 2017
@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch from fb00efd to a3040d0 Compare September 27, 2017 17:43
@@ -0,0 +1,31 @@
class MigrateDialogFieldAssociationsToUseNewRelationship < ActiveRecord::Migration[5.0]
Rails.application.eager_load!
Copy link
Member

Choose a reason for hiding this comment

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

nope!

Rails.application.eager_load!

def up
Dialog.all.each do |dialog|
Copy link
Member

Choose a reason for hiding this comment

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

Create a stub model, as is done in other data migrations, for Dialog and DialogFieldAssociation

def up
Dialog.all.each do |dialog|
fields = dialog.dialog_fields
dialog_fields_with_associations = fields.select { |df| !df.auto_refresh.nil? || !df.trigger_auto_refresh.nil? }.sort { |n| n.position * -1 }
Copy link
Member

@Fryguy Fryguy Oct 2, 2017

Choose a reason for hiding this comment

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

!df.auto_refresh.nil? || !df.trigger_auto_refresh.nil?

simplifies to

df.auto_refresh || df.trigger_auto_refresh

... Also, should those be auto_refresh? and trigger_auto_refresh? (with trailing ?)


.sort { |n| n.position * -1 }

simplifies to

.sort { |n| -n.position }


def up
Dialog.all.each do |dialog|
fields = dialog.dialog_fields
Copy link
Member

Choose a reason for hiding this comment

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

you might want an includes in the original query or this is going to be a nasty N+1

Dialog.all.each do |dialog|
fields = dialog.dialog_fields
dialog_fields_with_associations = fields.select { |df| !df.auto_refresh.nil? || !df.trigger_auto_refresh.nil? }.sort { |n| n.position * -1 }
triggers = dialog_fields_with_associations.select { |df| df.trigger_auto_refresh == true }
Copy link
Member

Choose a reason for hiding this comment

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

if trigger_auto_refresh is a boolean column, this simplifies to

.select(&:trigger_auto_refresh)

(same with the next line)

triggers = dialog_fields_with_associations.select { |df| df.trigger_auto_refresh == true }
responders = dialog_fields_with_associations.select { |df| df.auto_refresh == true }
triggers.each_with_index do |t, index|
responder_fields_for_t = if !triggers[index + 1].nil?
Copy link
Member

Choose a reason for hiding this comment

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

Prefer coding in the positive as opposed to ! nil? because double-negative are hard for people to reason about. So,

responder_fields_for_t =
  if triggers[index + 1]
    responders.select { |r| r.position
 ....

@Fryguy
Copy link
Member

Fryguy commented Oct 2, 2017

Don't forget the specs 😄 All data migrations require specs.

@Fryguy Fryguy added the data label Oct 2, 2017
@Fryguy Fryguy self-assigned this Oct 2, 2017
@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch 3 times, most recently from 108a22a to ca220ba Compare October 3, 2017 18:07
@d-m-u
Copy link
Contributor Author

d-m-u commented Oct 5, 2017

@eclarizio just working on the testing for this one now

@d-m-u
Copy link
Contributor Author

d-m-u commented Oct 12, 2017

@miq-bot assign @eclarizio

@miq-bot miq-bot assigned eclarizio and unassigned Fryguy Oct 12, 2017
@eclarizio
Copy link
Member

I'm guessing you meant to add me as a reviewer, since I don't really have any powers as an assignee 😛

@miq-bot assign @Fryguy

@Fryguy Looking at the miq-bot repo though, can we even set a reviewer with miq-bot?

@miq-bot miq-bot assigned Fryguy and unassigned eclarizio Oct 12, 2017
@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch from ca220ba to 33f510e Compare October 13, 2017 16:41
@d-m-u d-m-u changed the title [WIP] Migrate existing dialog field association data to use new relationship Migrate existing dialog field association data to use new relationship Oct 13, 2017
@miq-bot miq-bot removed the wip label Oct 13, 2017
@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch 2 times, most recently from a244cf4 to 406045f Compare October 16, 2017 14:06
@d-m-u d-m-u changed the title [WIP] Migrate existing dialog field association data to use new relationship Migrate existing dialog field association data to use new relationship Oct 25, 2017
@miq-bot miq-bot removed the wip label Oct 25, 2017
before(:each) do
dialog_group_stub.create!(:id => 2, :dialog_tab_id => 8, :position => 7)
dialog_tab_stub.create!(:id => 8, :dialog_id => 10, :position => 4)
dialog_stub.create!(:id => 10)
Copy link
Member

Choose a reason for hiding this comment

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

Do not use manual ids because it bypasses proper region testing.

Copy link
Member

Choose a reason for hiding this comment

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

Instead create the record, let ActiveRecord create a proper id, then use that id after the fact to update the associations.

let(:dialog_field_association_stub) { migration_stub(:DialogFieldAssociation) }

migration_context :up do
before(:each) do
Copy link
Member

Choose a reason for hiding this comment

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

:each is redundant, so you can remove it.

index = field_position + dialog_group_position * 100 + dialog_tab_position * 10_000
positions << {:id => f.id, :position => index}
end
positions
Copy link
Member

Choose a reason for hiding this comment

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

prefer .collect over the

x = []
foo.each { x << y }
x

pattern.

x = foo.collect { y }

field_position = f.position
dialog_group_position = DialogGroup.find(f.dialog_group_id).position
dialog_tab_position = DialogTab.find(DialogGroup.find(f.dialog_group_id).dialog_tab_id).position
index = field_position + dialog_group_position * 100 + dialog_tab_position * 10_000
Copy link
Member

Choose a reason for hiding this comment

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

Why these numbers? Are they just arbitrarily for segmenting? I only ask because I remember a customer with over 100 fields on a form, and so this could cause issues. Even so, since you are updating the position, I still think it's weird to segment and then leave it that way...I would expect something to post-process the "weird" numbers, and put them into "normal" numbers by sorting and mapping the indexes or something.


def responder_range(trigger_min, trigger_max)
min = trigger_min[:position] + 1
max = trigger_max.present? ? trigger_max[:position] - 1 : 10_000_000
Copy link
Member

Choose a reason for hiding this comment

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

Also curious about this 10 million number.

end

def down
DialogFieldAssociation.delete_all
Copy link
Member

Choose a reason for hiding this comment

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

Will the previous migration just drop the table? If so, then there's no need for this at all. (You could just put a comment stating that fact)

end

def dialog_fields_with_associations_by_dialog(dialog_fields_with_associations)
dialog_fields_with_associations.group_by { |df| Dialog.find(DialogTab.find(DialogGroup.find(DialogField.find(df.id).dialog_group_id).dialog_tab_id).dialog_id) }
Copy link
Member

Choose a reason for hiding this comment

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

This looks like an N+1 nightmare. There are much better approaches for querying all the data, then mixing and matching (we do something very similar with the RelationshipMixin for child objects. I can sit with you and show you.

dialog_fields.each do |f|
field_position = f.position
dialog_group_position = DialogGroup.find(f.dialog_group_id).position
dialog_tab_position = DialogTab.find(DialogGroup.find(f.dialog_group_id).dialog_tab_id).position
Copy link
Member

Choose a reason for hiding this comment

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

Also an N+1 issue (on both of these lines)

@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch 6 times, most recently from 78e5e20 to 3687054 Compare October 30, 2017 18:50
@d-m-u
Copy link
Contributor Author

d-m-u commented Oct 30, 2017

@gmcculloug can you take a quick looksee at this, 'specially the specs, again please?

.where(:auto_refresh => true)
.or(DialogField.where(:trigger_auto_refresh => true))
.includes(:dialog_group => {:dialog_tab => :dialog})
.group_by { |f| f.dialog_group.dialog_tab.dialog }
Copy link
Member

Choose a reason for hiding this comment

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

@Fryguy had the suggest to protect against this relationship chain hitting a nil here and I would agree. If we use try and allow the fields to get grouped together until nil we can throw those fields away before processing.

@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch 2 times, most recently from cbe0bd9 to 73f524a Compare October 30, 2017 20:33

migration_context :down do
it "should delete dialog field associations" do
migrate
Copy link
Member

Choose a reason for hiding this comment

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

This should create a dialog_field_association record before the migrate, otherwise you are testing nothing.

@Fryguy
Copy link
Member

Fryguy commented Oct 30, 2017

minor problem with the down migration spec but otherwise looks good to me 👍

@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch 2 times, most recently from e41ebc4 to 035c632 Compare October 30, 2017 21:04
@d-m-u d-m-u force-pushed the migrate_existing_dialog_field_associations_to_new_association_relationship branch from 035c632 to a860e35 Compare October 30, 2017 21:09
@miq-bot
Copy link
Member

miq-bot commented Oct 30, 2017

Checked commit d-m-u@a860e35 with ruby 2.3.3, rubocop 0.47.1, and haml-lint 0.20.0
2 files checked, 0 offenses detected
Everything looks fine. 👍

@chessbyte chessbyte merged commit ee290b8 into ManageIQ:master Oct 30, 2017
@chessbyte chessbyte added this to the Sprint 72 Ending Oct 30, 2017 milestone Oct 30, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants