summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Provaznik <jprovaznik@gitlab.com>2018-05-31 20:32:36 +0200
committerJan Provaznik <jprovaznik@gitlab.com>2018-05-31 20:32:36 +0200
commitcf87c3be18a8dfb6c31d549d35d6d2c07517df1d (patch)
tree2dbd29a579b202fba4c00cb0dc4da709a4a14baa
parente57ad62d488b15b9e65ea63f4ab78e51336318a5 (diff)
downloadgitlab-ce-rails5-enum-nil.tar.gz
Enable mapping to nil in enumsrails5-enum-nil
Enum in Rails 5 does not map nil values - IOW nil value remains nil, even if there is a key with nil value in the enum definition. This commit overrides the underlying Enum methods so nil value is still mapped. This solution is far from being ideal: it uses dynamic definition of methods which introduces more magic/confusion into the codebase. It would be better to get rid of the nil value in enums.
-rw-r--r--app/models/ci/pipeline.rb16
-rw-r--r--app/models/commit_status.rb10
-rw-r--r--app/models/concerns/enum_with_nil.rb31
3 files changed, 36 insertions, 21 deletions
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 53af87a271a..bf6fe113cb0 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -7,6 +7,7 @@ module Ci
include Presentable
include Gitlab::OptimisticLocking
include Gitlab::Utils::StrongMemoize
+ include EnumWithNil
belongs_to :project, inverse_of: :pipelines
belongs_to :user
@@ -49,7 +50,7 @@ module Ci
after_create :keep_around_commits, unless: :importing?
- enum source: {
+ enum_with_nil source: {
unknown: nil,
push: 1,
web: 2,
@@ -59,7 +60,7 @@ module Ci
external: 6
}
- enum config_source: {
+ enum_with_nil config_source: {
unknown_source: nil,
repository_source: 1,
auto_devops_source: 2
@@ -575,17 +576,6 @@ module Ci
@latest_builds_with_artifacts ||= builds.latest.with_artifacts_archive.to_a
end
- # Rails 5.0 autogenerated question mark enum methods return wrong result if enum value is nil.
- # They always return `false`.
- # These methods overwrite autogenerated ones to return correct results.
- def unknown?
- Gitlab.rails5? ? source.nil? : super
- end
-
- def unknown_source?
- Gitlab.rails5? ? config_source.nil? : super
- end
-
private
def ci_yaml_from_repo
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index a7d05722287..97516079b66 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -3,6 +3,7 @@ class CommitStatus < ActiveRecord::Base
include Importable
include AfterCommitQueue
include Presentable
+ include EnumWithNil
self.table_name = 'ci_builds'
@@ -39,7 +40,7 @@ class CommitStatus < ActiveRecord::Base
scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) }
scope :after_stage, -> (index) { where('stage_idx > ?', index) }
- enum failure_reason: {
+ enum_with_nil failure_reason: {
unknown_failure: nil,
script_failure: 1,
api_failure: 2,
@@ -190,11 +191,4 @@ class CommitStatus < ActiveRecord::Base
v =~ /\d+/ ? v.to_i : v
end
end
-
- # Rails 5.0 autogenerated question mark enum methods return wrong result if enum value is nil.
- # They always return `false`.
- # This method overwrites the autogenerated one to return correct result.
- def unknown_failure?
- Gitlab.rails5? ? failure_reason.nil? : super
- end
end
diff --git a/app/models/concerns/enum_with_nil.rb b/app/models/concerns/enum_with_nil.rb
new file mode 100644
index 00000000000..17915716ec1
--- /dev/null
+++ b/app/models/concerns/enum_with_nil.rb
@@ -0,0 +1,31 @@
+module EnumWithNil
+ extend ActiveSupport::Concern
+
+ included do
+ def self.enum_with_nil(definitions)
+ # use original `enum` to auto-define all methods
+ enum(definitions)
+
+ # override auto-defined methods only for the
+ # key which uses nil value
+ definitions.each do |name, values|
+ next unless key_with_nil = values.key(nil)
+
+ # E.g. for enum_with_nil failure_reason: { unknown_failure: nil }
+ # this overrides auto-generated method `unknown_failure?`
+ define_method("#{key_with_nil}?") do
+ Gitlab.rails5? ? self[name].nil? : super()
+ end
+
+ # E.g. for enum_with_nil failure_reason: { unknown_failure: nil }
+ # this overrides auto-generated method `failure_reason`
+ define_method(name) do
+ orig = super()
+
+ return orig unless orig.nil?
+ self.class.public_send(name.to_s.pluralize).key(nil)
+ end
+ end
+ end
+ end
+end