From e02cf6615aaeb02f4e254dfaca0ca1d4e94539f0 Mon Sep 17 00:00:00 2001 From: Nick LaMuro Date: Tue, 13 Nov 2018 23:26:14 -0600 Subject: [PATCH] [AuthenticationMixin] authentication_status to virtual_delegate Creates a virtual_delegate for AuthenticationMixin#authentication_status which allows it to be included in reports and put in as part of the main query. The biggest thing of note in this change is how the status_severity_arel is being used to handle the sorting properly in the SQL query. It makes use of a SQL's case statement to handle what would normally be a `sort_by` on the hash lookup of Authentication::STATUS_SEVERITY. Instead, we match each key to the status column and use that as the value for the `ORDER BY exp DESC` in the `has_one`, which allows for the same affect. This also means that it can inject itself in the `SELECT` of a `MiqReport`, and avoid N+1's on things like quadicons and such for pages that use `MiqReport#paged_view_search`. --- app/models/authentication.rb | 20 ++++++++++++++++++++ app/models/mixins/authentication_mixin.rb | 16 ++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/app/models/authentication.rb b/app/models/authentication.rb index 52dd992eed0b..cf8ae1b9b2f3 100644 --- a/app/models/authentication.rb +++ b/app/models/authentication.rb @@ -68,6 +68,26 @@ def self.db_name "auth_key_pair_cloud" end + # Builds a case statement that case be used in a sql ORDER BY. + # + # Generated SQL looks like: + # + # CASE + # WHEN LOWER(status) = '' THEN -1 + # WHEN LOWER(status) = 'valid' THEN 0 + # ... + # ELSE -1 + # + def self.status_severity_arel + arel_case = Arel::Nodes::Case.new + + STATUS_SEVERITY.each do |value, sort_weight| + arel_case.when(arel_table[:status].lower.eq(value)).then(sort_weight) + end + + arel_case.else(-1) + end + def status_severity STATUS_SEVERITY[status.to_s.downcase] end diff --git a/app/models/mixins/authentication_mixin.rb b/app/models/mixins/authentication_mixin.rb index a92b849211cb..b1a21a7b43a2 100644 --- a/app/models/mixins/authentication_mixin.rb +++ b/app/models/mixins/authentication_mixin.rb @@ -4,7 +4,16 @@ module AuthenticationMixin included do has_many :authentications, :as => :resource, :dependent => :destroy, :autosave => true - virtual_column :authentication_status, :type => :string + has_one :authentication_status_severity_level, + -> { order(Authentication.status_severity_arel.desc) }, + :as => :resource, + :inverse_of => :resource, + :class_name => "Authentication" + + virtual_delegate :authentication_status, + :to => "authentication_status_severity_level.status", + :default => "None", + :allow_nil => true def self.authentication_check_schedule zone = MiqServer.my_server.zone @@ -117,11 +126,6 @@ def missing_credentials?(type = nil) !has_credentials?(type) end - def authentication_status - ordered_auths = authentication_for_providers.sort_by(&:status_severity) - ordered_auths.last.try(:status) || "None" - end - def authentication_status_ok?(type = nil) authentication_best_fit(type).try(:status) == "Valid" end