Adds support for multiselect custom fields (#1189).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@8721 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -38,6 +38,8 @@ class CustomField < ActiveRecord::Base
|
||||
def set_searchable
|
||||
# make sure these fields are not searchable
|
||||
self.searchable = false if %w(int float date bool).include?(field_format)
|
||||
# make sure only these fields can have multiple values
|
||||
self.multiple = false unless %w(list user version).include?(field_format)
|
||||
true
|
||||
end
|
||||
|
||||
@@ -123,6 +125,7 @@ class CustomField < ActiveRecord::Base
|
||||
# objects by their value of the custom field.
|
||||
# Returns false, if the custom field can not be used for sorting.
|
||||
def order_statement
|
||||
return nil if multiple?
|
||||
case field_format
|
||||
when 'string', 'text', 'list', 'date', 'bool'
|
||||
# COALESCE is here to make sure that blank and NULL values are sorted equally
|
||||
@@ -161,14 +164,24 @@ class CustomField < ActiveRecord::Base
|
||||
nil
|
||||
end
|
||||
|
||||
# Returns the error message for the given value
|
||||
# Returns the error messages for the given value
|
||||
# or an empty array if value is a valid value for the custom field
|
||||
def validate_field_value(value)
|
||||
errs = []
|
||||
if is_required? && value.blank?
|
||||
errs << ::I18n.t('activerecord.errors.messages.blank')
|
||||
if value.is_a?(Array)
|
||||
if !multiple?
|
||||
errs << ::I18n.t('activerecord.errors.messages.invalid')
|
||||
end
|
||||
if is_required? && value.detect(&:present?).nil?
|
||||
errs << ::I18n.t('activerecord.errors.messages.blank')
|
||||
end
|
||||
value.each {|v| errs += validate_field_value_format(v)}
|
||||
else
|
||||
if is_required? && value.blank?
|
||||
errs << ::I18n.t('activerecord.errors.messages.blank')
|
||||
end
|
||||
errs += validate_field_value_format(value)
|
||||
end
|
||||
errs += validate_field_value_format(value)
|
||||
errs
|
||||
end
|
||||
|
||||
|
||||
+27
-6
@@ -429,7 +429,7 @@ class Issue < ActiveRecord::Base
|
||||
else
|
||||
@attributes_before_change = attributes.dup
|
||||
@custom_values_before_change = {}
|
||||
self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
|
||||
self.custom_field_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
|
||||
end
|
||||
# Make sure updated_on is updated when adding a note.
|
||||
updated_on_will_change!
|
||||
@@ -1006,14 +1006,35 @@ class Issue < ActiveRecord::Base
|
||||
end
|
||||
if @custom_values_before_change
|
||||
# custom fields changes
|
||||
custom_values.each {|c|
|
||||
custom_field_values.each {|c|
|
||||
before = @custom_values_before_change[c.custom_field_id]
|
||||
after = c.value
|
||||
next if before == after || (before.blank? && after.blank?)
|
||||
@current_journal.details << JournalDetail.new(:property => 'cf',
|
||||
:prop_key => c.custom_field_id,
|
||||
:old_value => before,
|
||||
:value => after)
|
||||
|
||||
if before.is_a?(Array) || after.is_a?(Array)
|
||||
before = [before] unless before.is_a?(Array)
|
||||
after = [after] unless after.is_a?(Array)
|
||||
|
||||
# values removed
|
||||
(before - after).reject(&:blank?).each do |value|
|
||||
@current_journal.details << JournalDetail.new(:property => 'cf',
|
||||
:prop_key => c.custom_field_id,
|
||||
:old_value => value,
|
||||
:value => nil)
|
||||
end
|
||||
# values added
|
||||
(after - before).reject(&:blank?).each do |value|
|
||||
@current_journal.details << JournalDetail.new(:property => 'cf',
|
||||
:prop_key => c.custom_field_id,
|
||||
:old_value => nil,
|
||||
:value => value)
|
||||
end
|
||||
else
|
||||
@current_journal.details << JournalDetail.new(:property => 'cf',
|
||||
:prop_key => c.custom_field_id,
|
||||
:old_value => before,
|
||||
:value => after)
|
||||
end
|
||||
}
|
||||
end
|
||||
@current_journal.save
|
||||
|
||||
+10
-4
@@ -57,7 +57,7 @@ class QueryCustomFieldColumn < QueryColumn
|
||||
def initialize(custom_field)
|
||||
self.name = "cf_#{custom_field.id}".to_sym
|
||||
self.sortable = custom_field.order_statement || false
|
||||
if %w(list date bool int).include?(custom_field.field_format)
|
||||
if %w(list date bool int).include?(custom_field.field_format) && !custom_field.multiple?
|
||||
self.groupable = custom_field.order_statement
|
||||
end
|
||||
self.groupable ||= false
|
||||
@@ -73,8 +73,8 @@ class QueryCustomFieldColumn < QueryColumn
|
||||
end
|
||||
|
||||
def value(issue)
|
||||
cv = issue.custom_values.detect {|v| v.custom_field_id == @cf.id}
|
||||
cv && @cf.cast_value(cv.value)
|
||||
cv = issue.custom_values.select {|v| v.custom_field_id == @cf.id}.collect {|v| @cf.cast_value(v.value)}
|
||||
cv.size > 1 ? cv : cv.first
|
||||
end
|
||||
|
||||
def css_classes
|
||||
@@ -694,7 +694,13 @@ class Query < ActiveRecord::Base
|
||||
value.push User.current.id.to_s
|
||||
end
|
||||
end
|
||||
"#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " +
|
||||
not_in = nil
|
||||
if operator == '!'
|
||||
# Makes ! operator work for custom fields with multiple values
|
||||
operator = '='
|
||||
not_in = 'NOT'
|
||||
end
|
||||
"#{Issue.table_name}.id #{not_in} IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " +
|
||||
sql_for_field(field, operator, value, db_table, db_field, true) + ')'
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user