Skip to content

Instantly share code, notes, and snippets.

@kbrock
Last active January 14, 2016 17:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kbrock/b764ff3fc1cb63c18d0d to your computer and use it in GitHub Desktop.
Save kbrock/b764ff3fc1cb63c18d0d to your computer and use it in GitHub Desktop.
Active Record allows you to define relationships in 2 directions. But unfortunately, it is not always smart enough to detect when a relationship on one side is the same as the opposite direction. This aims to help you discover where and why rails is not helping you out.
class Reason
def reason_inverse_name(src, ref)
# def inverse_name; delegate_reflection.send(:inverse_name); end
ref = ref.respond_to?(:delegate_reflection) ? ref.delegate_reflection : ref
if ref.options[:inverse_of]
# will this false positive a :through?
if ref.options[:inverse_of] == ref.send(:automatic_inverse_of)
"UNNEEDED: `options[:inverse_of]`"
else
"`options[:inverse_of]`"
end
else
reason_automatic_inverse_of(src, ref)
end
end
def reason_automatic_inverse_of(src, ref)
reason = reason_can_find_inverse_of_automatically?(src, ref, ref)
return reason if reason
inverse_name = ActiveSupport::Inflector.underscore(ref.options[:as] || ref.active_record.name.demodulize).to_sym
begin
reflection = ref.klass._reflect_on_association(inverse_name)
rescue NameError
# Give up: we couldn't compute the klass type so we won't be able
# to find any associations either.
return "cant compute #{ref.klass}.#{inverse_name}.klass"
end
reason_valid_inverse_reflection?(src, ref, reflection, "#{reflection.try(:active_record).try(:name) || ref.klass}.#{inverse_name}")
end
# return reason it is BAD
def reason_can_find_inverse_of_automatically?(src, ref, reflection) # inverse ( return value if failing)
case
when reflection.options[:inverse_of] == false
"detection disabled with `:inverse_of => false`"
when !ref.class::VALID_AUTOMATIC_INVERSE_MACROS.include?(reflection.macro)
"`#{ref.macro}` not supported"
when !(opts=ref.class::INVALID_AUTOMATIC_INVERSE_OPTIONS.select { |opt| reflection.options[opt] }).empty?
"option `:#{opts.join("`, `:")}` not supported"
when reflection.scope
# do default scopes even come into play?
"`scope` not supported (#{reflection.klass})#{" (there is a `default_scope`)" if reflection.klass.default_scopes.size > 0}"
end
end
def reason_valid_inverse_reflection?(src, ref, reflection, name) # inverse (return value if valid or not)
case
when !reflection
# would be nice to get all the STI ancestors
options = [ref.klass, ref.klass.base_class].uniq.flat_map do |k|
k.reflections.values.select { |r|
(r.klass.base_class rescue nil) == src.base_class
}.map(&:name)
end
possible = options.empty? ? "" : " (suggested values: `#{options.join("`, `")})`"
"no reverse association `#{name}`#{possible}"
when ref.klass.name != reflection.active_record.name
"`#{name}` exists, but wrong parent class (want `#{ref.klass.name}`)"
else
reason_can_find_inverse_of_automatically?(src, ref, reflection) # return value if valid or not
end
end
def reasons(*srcs)
srcs = [Tenant, Vm, VmOrTemplate, Host, EmsCluster] if srcs.empty?
puts "|reference|reverse|reason"
puts "|---------|-----|------"
srcs.each do |src|
src.reflections.values.each_with_index do |ref, i|
value = ref.send(:inverse_name)
why = reason_inverse_name(src, ref)
puts "|`#{src.name}.#{ref.name}`|#{value ? "`#{ref.klass.name}.#{value}`" : "**NO**"}|#{why || "automatic"}|"
end
end
nil
end
end
Reason.new.reasons(Tenant, Vm, VmOrTemplate, Host, EmsCluster)
reference reverse reason
Tenant.taggings NO option :polymorphic not supported
Tenant.tags NO option :through not supported
Tenant.providers Provider.tenant automatic
Tenant.ext_management_systems ExtManagementSystem.tenant automatic
Tenant.vm_or_templates VmOrTemplate.tenant automatic
Tenant.vms NO VmOrTemplate.tenant exists, but wrong parent class (want Vm)
Tenant.miq_templates NO VmOrTemplate.tenant exists, but wrong parent class (want MiqTemplate)
Tenant.service_template_catalogs ServiceTemplateCatalog.tenant automatic
Tenant.service_templates ServiceTemplate.tenant automatic
Tenant.tenant_quotas TenantQuota.tenant automatic
Tenant.miq_groups MiqGroup.tenant automatic
Tenant.users NO option :through not supported
Tenant.ae_domains MiqAeDomain.tenant automatic
Tenant.miq_requests MiqRequest.tenant automatic
Tenant.miq_request_tasks MiqRequestTask.tenant automatic
Tenant.services Service.tenant automatic
Tenant.default_miq_group MiqGroup.tenant UNNEEDED: options[:inverse_of]
Vm.snapshots Snapshot.vm_or_template automatic
Vm.compliances NO option :polymorphic not supported
Vm.evm_owner NO no reverse association User.vm_or_template (suggested values: vms, miq_templates)
Vm.miq_group NO no reverse association MiqGroup.vm_or_template (suggested values: vms, miq_templates)
Vm.custom_attributes NO option :polymorphic not supported
Vm.miq_custom_attributes NO scope not supported (CustomAttribute)
Vm.ems_custom_attributes NO scope not supported (CustomAttribute)
Vm.miq_server NO option :foreign_key not supported
Vm.operating_system OperatingSystem.vm_or_template automatic
Vm.hardware Hardware.vm_or_template automatic
Vm.host NO no reverse association Host.vm_or_template (suggested values: vms_and_templates, vms, miq_templates)
Vm.ems_cluster NO no reverse association EmsCluster.vm_or_template (suggested values: vms_and_templates, miq_templates, vms)
Vm.storage NO no reverse association Storage.vm_or_template (suggested values: vms_and_templates, miq_templates, vms, all_vms_and_templates, all_miq_templates, all_vms)
Vm.repositories NO option :through not supported
Vm.storages NO has_and_belongs_to_many not supported
Vm.ext_management_system NO option :foreign_key not supported
Vm.miq_provision NO MiqRequestTask.destination exists, but wrong parent class (want MiqProvision)
Vm.miq_provisions_from_template NO MiqRequestTask.source exists, but wrong parent class (want MiqProvision)
Vm.miq_provision_vms NO option :through not supported
Vm.miq_provision_requests NO MiqRequest.source exists, but wrong parent class (want MiqProvisionRequest)
Vm.guest_applications GuestApplication.vm_or_template automatic
Vm.patches Patch.vm_or_template automatic
Vm.accounts Account.vm_or_template automatic
Vm.users NO scope not supported (Account)
Vm.groups NO scope not supported (Account)
Vm.system_services SystemService.vm_or_template automatic
Vm.win32_services NO scope not supported (SystemService)
Vm.kernel_drivers NO scope not supported (SystemService)
Vm.filesystem_drivers NO scope not supported (SystemService)
Vm.linux_initprocesses NO scope not supported (SystemService)
Vm.filesystems NO option :polymorphic not supported
Vm.directories NO scope not supported (Filesystem)
Vm.files NO scope not supported (Filesystem)
Vm.scan_histories ScanHistory.vm_or_template automatic
Vm.lifecycle_events LifecycleEvent.vm_or_template automatic
Vm.advanced_settings NO option :polymorphic not supported
Vm.registry_items RegistryItem.vm_or_template automatic
Vm.metrics NO option :polymorphic not supported
Vm.metric_rollups NO option :polymorphic not supported
Vm.vim_performance_states NO option :polymorphic not supported
Vm.storage_files StorageFile.vm_or_template automatic
Vm.storage_files_files NO scope not supported (StorageFile)
Vm.ems_events NO scope not supported (EmsEvent)
Vm.ems_events_src NO EventStream.vm_or_template exists, but wrong parent class (want EmsEvent)
Vm.ems_events_dest NO option :foreign_key not supported
Vm.policy_events NO scope not supported (PolicyEvent)
Vm.miq_events NO EventStream.target exists, but wrong parent class (want MiqEvent)
Vm.miq_alert_statuses NO option :polymorphic not supported
Vm.miq_cim_instance NO option :polymorphic not supported
Vm.service_resources NO option :polymorphic not supported
Vm.direct_services NO option :through not supported
Vm.tenant NO no reverse association Tenant.vm_or_template (suggested values: vm_or_templates, vms, miq_templates)
Vm.taggings NO option :polymorphic not supported
Vm.tags NO option :through not supported
Vm.all_relationships NO option :polymorphic not supported
Vm.drift_states NO option :polymorphic not supported
Vm.first_drift_state NO scope not supported (DriftState)
Vm.last_drift_state NO scope not supported (DriftState)
Vm.first_drift_state_timestamp_rec NO scope not supported (DriftState)
Vm.last_drift_state_timestamp_rec NO scope not supported (DriftState)
Vm.vim_performance_operating_ranges NO option :polymorphic not supported
VmOrTemplate.snapshots Snapshot.vm_or_template automatic
VmOrTemplate.compliances NO option :polymorphic not supported
VmOrTemplate.evm_owner NO no reverse association User.vm_or_template (suggested values: vms, miq_templates)
VmOrTemplate.miq_group NO no reverse association MiqGroup.vm_or_template (suggested values: vms, miq_templates)
VmOrTemplate.custom_attributes NO option :polymorphic not supported
VmOrTemplate.miq_custom_attributes NO scope not supported (CustomAttribute)
VmOrTemplate.ems_custom_attributes NO scope not supported (CustomAttribute)
VmOrTemplate.miq_server NO option :foreign_key not supported
VmOrTemplate.operating_system OperatingSystem.vm_or_template automatic
VmOrTemplate.hardware Hardware.vm_or_template automatic
VmOrTemplate.host NO no reverse association Host.vm_or_template (suggested values: vms_and_templates, vms, miq_templates)
VmOrTemplate.ems_cluster NO no reverse association EmsCluster.vm_or_template (suggested values: vms_and_templates, miq_templates, vms)
VmOrTemplate.storage NO no reverse association Storage.vm_or_template (suggested values: vms_and_templates, miq_templates, vms, all_vms_and_templates, all_miq_templates, all_vms)
VmOrTemplate.repositories NO option :through not supported
VmOrTemplate.storages NO has_and_belongs_to_many not supported
VmOrTemplate.ext_management_system NO option :foreign_key not supported
VmOrTemplate.miq_provision NO MiqRequestTask.destination exists, but wrong parent class (want MiqProvision)
VmOrTemplate.miq_provisions_from_template NO MiqRequestTask.source exists, but wrong parent class (want MiqProvision)
VmOrTemplate.miq_provision_vms NO option :through not supported
VmOrTemplate.miq_provision_requests NO MiqRequest.source exists, but wrong parent class (want MiqProvisionRequest)
VmOrTemplate.guest_applications GuestApplication.vm_or_template automatic
VmOrTemplate.patches Patch.vm_or_template automatic
VmOrTemplate.accounts Account.vm_or_template automatic
VmOrTemplate.users NO scope not supported (Account)
VmOrTemplate.groups NO scope not supported (Account)
VmOrTemplate.system_services SystemService.vm_or_template automatic
VmOrTemplate.win32_services NO scope not supported (SystemService)
VmOrTemplate.kernel_drivers NO scope not supported (SystemService)
VmOrTemplate.filesystem_drivers NO scope not supported (SystemService)
VmOrTemplate.linux_initprocesses NO scope not supported (SystemService)
VmOrTemplate.filesystems NO option :polymorphic not supported
VmOrTemplate.directories NO scope not supported (Filesystem)
VmOrTemplate.files NO scope not supported (Filesystem)
VmOrTemplate.scan_histories ScanHistory.vm_or_template automatic
VmOrTemplate.lifecycle_events LifecycleEvent.vm_or_template automatic
VmOrTemplate.advanced_settings NO option :polymorphic not supported
VmOrTemplate.registry_items RegistryItem.vm_or_template automatic
VmOrTemplate.metrics NO option :polymorphic not supported
VmOrTemplate.metric_rollups NO option :polymorphic not supported
VmOrTemplate.vim_performance_states NO option :polymorphic not supported
VmOrTemplate.storage_files StorageFile.vm_or_template automatic
VmOrTemplate.storage_files_files NO scope not supported (StorageFile)
VmOrTemplate.ems_events NO scope not supported (EmsEvent)
VmOrTemplate.ems_events_src NO EventStream.vm_or_template exists, but wrong parent class (want EmsEvent)
VmOrTemplate.ems_events_dest NO option :foreign_key not supported
VmOrTemplate.policy_events NO scope not supported (PolicyEvent)
VmOrTemplate.miq_events NO EventStream.target exists, but wrong parent class (want MiqEvent)
VmOrTemplate.miq_alert_statuses NO option :polymorphic not supported
VmOrTemplate.miq_cim_instance NO option :polymorphic not supported
VmOrTemplate.service_resources NO option :polymorphic not supported
VmOrTemplate.direct_services NO option :through not supported
VmOrTemplate.tenant NO no reverse association Tenant.vm_or_template (suggested values: vm_or_templates, vms, miq_templates)
VmOrTemplate.taggings NO option :polymorphic not supported
VmOrTemplate.tags NO option :through not supported
VmOrTemplate.all_relationships NO option :polymorphic not supported
VmOrTemplate.drift_states NO option :polymorphic not supported
VmOrTemplate.first_drift_state NO scope not supported (DriftState)
VmOrTemplate.last_drift_state NO scope not supported (DriftState)
VmOrTemplate.first_drift_state_timestamp_rec NO scope not supported (DriftState)
VmOrTemplate.last_drift_state_timestamp_rec NO scope not supported (DriftState)
VmOrTemplate.vim_performance_operating_ranges NO option :polymorphic not supported
Host.ext_management_system NO option :foreign_key not supported
Host.ems_cluster NO no reverse association EmsCluster.host (suggested values: hosts)
Host.operating_system NO no reverse association OperatingSystem.host
Host.hardware Hardware.host automatic
Host.vms_and_templates VmOrTemplate.host automatic
Host.vms NO VmOrTemplate.host exists, but wrong parent class (want Vm)
Host.miq_templates NO VmOrTemplate.host exists, but wrong parent class (want MiqTemplate)
Host.storages NO has_and_belongs_to_many not supported
Host.switches Switch.host automatic
Host.patches Patch.host automatic
Host.system_services SystemService.host automatic
Host.host_services NO option :foreign_key not supported
Host.metrics NO option :polymorphic not supported
Host.metric_rollups NO option :polymorphic not supported
Host.vim_performance_states NO option :polymorphic not supported
Host.ems_events NO scope not supported (EmsEvent)
Host.ems_events_src NO EventStream.host exists, but wrong parent class (want EmsEvent)
Host.ems_events_dest NO option :foreign_key not supported
Host.policy_events NO scope not supported (PolicyEvent)
Host.guest_applications GuestApplication.host automatic
Host.miq_events NO EventStream.target exists, but wrong parent class (want MiqEvent)
Host.filesystems NO option :polymorphic not supported
Host.directories NO scope not supported (Filesystem)
Host.files NO scope not supported (Filesystem)
Host.accounts Account.host automatic
Host.users NO option :foreign_key not supported
Host.groups NO option :foreign_key not supported
Host.advanced_settings NO option :polymorphic not supported
Host.miq_alert_statuses NO option :polymorphic not supported
Host.miq_cim_instance NO option :polymorphic not supported
Host.host_service_groups HostServiceGroup.host automatic
Host.custom_attributes NO option :polymorphic not supported
Host.miq_custom_attributes NO scope not supported (CustomAttribute)
Host.ems_custom_attributes NO scope not supported (CustomAttribute)
Host.filesystems_custom_attributes NO option :through not supported
Host.taggings NO option :polymorphic not supported
Host.tags NO option :through not supported
Host.all_relationships NO option :polymorphic not supported
Host.drift_states NO option :polymorphic not supported
Host.first_drift_state NO scope not supported (DriftState)
Host.last_drift_state NO scope not supported (DriftState)
Host.first_drift_state_timestamp_rec NO scope not supported (DriftState)
Host.last_drift_state_timestamp_rec NO scope not supported (DriftState)
Host.vim_performance_operating_ranges NO option :polymorphic not supported
Host.authentications NO option :polymorphic not supported
Host.compliances NO option :polymorphic not supported
EmsCluster.taggings NO option :polymorphic not supported
EmsCluster.tags NO option :through not supported
EmsCluster.ext_management_system NO option :foreign_key not supported
EmsCluster.hosts Host.ems_cluster automatic
EmsCluster.vms_and_templates VmOrTemplate.ems_cluster automatic
EmsCluster.miq_templates NO VmOrTemplate.ems_cluster exists, but wrong parent class (want MiqTemplate)
EmsCluster.vms NO VmOrTemplate.ems_cluster exists, but wrong parent class (want Vm)
EmsCluster.metrics NO option :polymorphic not supported
EmsCluster.metric_rollups NO option :polymorphic not supported
EmsCluster.vim_performance_states NO option :polymorphic not supported
EmsCluster.policy_events NO scope not supported (PolicyEvent)
EmsCluster.miq_events NO EventStream.target exists, but wrong parent class (want MiqEvent)
EmsCluster.drift_states NO option :polymorphic not supported
EmsCluster.first_drift_state NO scope not supported (DriftState)
EmsCluster.last_drift_state NO scope not supported (DriftState)
EmsCluster.first_drift_state_timestamp_rec NO scope not supported (DriftState)
EmsCluster.last_drift_state_timestamp_rec NO scope not supported (DriftState)
EmsCluster.all_relationships NO option :polymorphic not supported
EmsCluster.vim_performance_operating_ranges NO option :polymorphic not supported
=> true
irb(main):002:0>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment