From 2e7b191f383acbf148b2b5cf82ea19bb67f4a6ec Mon Sep 17 00:00:00 2001 From: Jason Frey Date: Fri, 6 Apr 2018 14:59:10 -0400 Subject: [PATCH] Merge pull request #17246 from kbrock/vm_template_name convert Vm#miq_provision_template to has_one (cherry picked from commit eef19e08d460594cad629a022169c2ee1a3a9331) --- app/models/vm_or_template.rb | 6 +---- lib/miq_expression.rb | 6 ++--- lib/miq_expression/field.rb | 23 +++++++++++++++++ spec/lib/miq_expression/field_spec.rb | 37 +++++++++++++++++++++++++++ spec/models/miq_report/search_spec.rb | 2 +- spec/models/vm_or_template_spec.rb | 26 +++++++++++++++++++ 6 files changed, 91 insertions(+), 9 deletions(-) diff --git a/app/models/vm_or_template.rb b/app/models/vm_or_template.rb index bf4775c16edf..1ba36e554d9f 100644 --- a/app/models/vm_or_template.rb +++ b/app/models/vm_or_template.rb @@ -166,7 +166,7 @@ class VmOrTemplate < ApplicationRecord virtual_has_many :processes, :class_name => "OsProcess", :uses => {:operating_system => :processes} virtual_has_many :event_logs, :uses => {:operating_system => :event_logs} virtual_has_many :lans, :uses => {:hardware => {:nics => :lan}} - virtual_belongs_to :miq_provision_template, :class_name => "Vm", :uses => {:miq_provision => :vm_template} + has_one :miq_provision_template, :through => "miq_provision", :source => "source", :source_type => "VmOrTemplate" virtual_belongs_to :parent_resource_pool, :class_name => "ResourcePool", :uses => :all_relationships virtual_has_many :base_storage_extents, :class_name => "CimStorageExtent" @@ -1457,10 +1457,6 @@ def v_datastore_path datastorepath end - def miq_provision_template - miq_provision.try(:vm_template) - end - def event_threshold?(options = {:time_threshold => 30.minutes, :event_types => ["MigrateVM_Task_Complete"], :freq_threshold => 2}) raise _("option :event_types is required") unless options[:event_types] raise _("option :time_threshold is required") unless options[:time_threshold] diff --git a/lib/miq_expression.rb b/lib/miq_expression.rb index 8941e3764e0c..ebc3c19d5778 100644 --- a/lib/miq_expression.rb +++ b/lib/miq_expression.rb @@ -1664,10 +1664,10 @@ def self.ruby_for_date_compare(col_ruby, col_type, tz, op1, val1, op2 = nil, val def to_arel(exp, tz) operator = exp.keys.first field = Field.parse(exp[operator]["field"]) if exp[operator].kind_of?(Hash) && exp[operator]["field"] - arel_attribute = field && field.target.arel_attribute(field.column) + arel_attribute = field&.arel_attribute if exp[operator].kind_of?(Hash) && exp[operator]["value"] && Field.is_field?(exp[operator]["value"]) field_value = Field.parse(exp[operator]["value"]) - parsed_value = field_value.target.arel_attribute(field_value.column) + parsed_value = field_value.arel_attribute elsif exp[operator].kind_of?(Hash) parsed_value = exp[operator]["value"] end @@ -1749,7 +1749,7 @@ def to_arel(exp, tz) arel = arel_attribute.eq(parsed_value) arel = arel.and(Arel::Nodes::SqlLiteral.new(extract_where_values(reflection.klass, reflection.scope))) if reflection.scope field.model.arel_attribute(:id).in( - field.target.arel_table.where(arel).project(field.target.arel_table[reflection.foreign_key]).distinct + field.arel_table.where(arel).project(field.arel_table[reflection.foreign_key]).distinct ) end when "is" diff --git a/lib/miq_expression/field.rb b/lib/miq_expression/field.rb index 33b38f085b11..bb965f1c6e74 100644 --- a/lib/miq_expression/field.rb +++ b/lib/miq_expression/field.rb @@ -57,6 +57,29 @@ def report_column (associations + [column]).join('.') end + # this should only be accessed in MiqExpression + # please avoid using it + def arel_table + if associations.none? + model.arel_table + else + # if we are pointing to a table that already in the query, need to alias it + # seems we should be able to ask AR to do this for us... + ref = reflections.last + if ref.klass.table_name == model.table_name + ref.klass.arel_table.alias(ref.alias_candidate(model.table_name)) + else + ref.klass.arel_table + end + end + end + + # this should only be accessed in MiqExpression + # please avoid using it + def arel_attribute + target.arel_attribute(column, arel_table) if target + end + private def custom_attribute_column_name diff --git a/spec/lib/miq_expression/field_spec.rb b/spec/lib/miq_expression/field_spec.rb index 4fd09eebdd0e..e1025971cc3d 100644 --- a/spec/lib/miq_expression/field_spec.rb +++ b/spec/lib/miq_expression/field_spec.rb @@ -191,6 +191,43 @@ end end + describe "#arel_table" do + it "returns the main table when there are no associations" do + field = described_class.new(Vm, [], "name") + expect(field.arel_table).to eq(Vm.arel_table) + end + + it "returns the table of the target association without an alias" do + field = described_class.new(Vm, ["guest_applications"], "name") + expect(field.arel_table).to eq(GuestApplication.arel_table) + expect(field.arel_table.name).to eq(GuestApplication.arel_table.name) + end + + it "returns the table of the target association with an alias if needed" do + field = described_class.new(Vm, ["miq_provision_template"], "name") + expect(field.arel_table.table_name).to eq(Vm.arel_table.table_name) + expect(field.arel_table.name).not_to eq(Vm.arel_table.name) + end + end + + describe "#arel_attribute" do + it "returns the main table when there are no associations" do + field = described_class.new(Vm, [], "name") + expect(field.arel_attribute).to eq(Vm.arel_attribute("name")) + end + + it "returns the table of the target association without an alias" do + field = described_class.new(Vm, ["guest_applications"], "name") + expect(field.arel_attribute).to eq(GuestApplication.arel_attribute("name")) + end + + it "returns the table of the target association with an alias if needed" do + field = described_class.new(Vm, ["miq_provision_template"], "name") + expect(field.arel_attribute.name).to eq("name") + expect(field.arel_attribute.relation.name).to include("miq_provision_template") + end + end + describe "#plural?" do it "returns false if the column is on a 'belongs_to' association" do field = described_class.new(Vm, ["storage"], "region_description") diff --git a/spec/models/miq_report/search_spec.rb b/spec/models/miq_report/search_spec.rb index 8742232c4116..6b5778daf931 100644 --- a/spec/models/miq_report/search_spec.rb +++ b/spec/models/miq_report/search_spec.rb @@ -28,7 +28,7 @@ end it "detects a virtual association (and that it can't be sorted)" do - @miq_report.sortby = ["miq_provision_template.name"] + @miq_report.sortby = ["parent_resource_pool.name"] order = @miq_report.get_order_info expect(order).to be_falsy end diff --git a/spec/models/vm_or_template_spec.rb b/spec/models/vm_or_template_spec.rb index c0311c81c460..ce8ec5aafeac 100644 --- a/spec/models/vm_or_template_spec.rb +++ b/spec/models/vm_or_template_spec.rb @@ -565,6 +565,32 @@ expect(template.miq_provision_vms.collect(&:id)).to eq([vm.id]) end + describe "#miq_provision_template" do + it "links vm to template" do + ems = FactoryGirl.create(:ems_vmware_with_authentication) + template = FactoryGirl.create(:template_vmware, :ext_management_system => ems) + vm = FactoryGirl.create(:vm_vmware, :ext_management_system => ems) + + options = { + :vm_name => vm.name, + :vm_target_name => vm.name, + :src_vm_id => [template.id, template.name] + } + + FactoryGirl.create( + :miq_provision_vmware, + :destination => vm, + :source => template, + :request_type => 'clone_to_vm', + :state => 'finished', + :status => 'Ok', + :options => options + ) + + expect(vm.miq_provision_template).to eq(template) + end + end + describe ".v_pct_free_disk_space (delegated to hardware)" do let(:vm) { FactoryGirl.create(:vm_vmware, :hardware => hardware) } let(:hardware) { FactoryGirl.create(:hardware, :disk_free_space => 20, :disk_capacity => 100) }