Custom field casting affected by recent update?

There have been multiple bug reports for the events plugin in the last two days that all seem to be type-casting issues with custom fields. The events plugin hasn’t been substantively updated in a few months.

The plugin.rb file casts event_start as an integer:

Topic.register_custom_field_type('event_start', :integer)

The error is being thrown here:

def has_event?
  self.custom_fields['event_start']&.nonzero?
end

The error itself follows this format:

NoMethodError (undefined method `nonzero?' for [1563127206, 1563127206]:Array)

As far as I understand register_custom_field_type it should ensure that the custom_field always returns as the defined type (perhaps I’m misunderstanding it).

Looking at the has_custom_fields.rb concern, there have been a few changes in the past week that could have affected this, in particular

https://github.com/discourse/discourse/commit/72bac61c90044407f7a2029b15f6ac043a8bccf0#diff-712e064741bd664591e6392a52eb409e

@eviltrout Any thoughts on this?

6 Likes

In case this is indeed the bug causing problems, here I explain the consequences (it may make your site unusable):

This was a known bug with custom fields.

In very specific conditions, it would save the value multiple times, thus creating an Array, when you only want an Integer.

You can fix this by making sure there’s only 1 row per custom field in the database.

5 Likes

Yes, it’s cropped up a few times in the past. This latest rash seems to coincide with recent work on the has_custom_fields.rb concern, so there may be something to review there.

This doesn’t fix it, but helps to address it if it arises:

https://github.com/discourse/discourse/pull/7886

My general recommendation here is that as a plugin author you should always add indexes in a migration to properly enforce the constraint. In fact majority of plugins we right these days avoid custom fields unless absolutely needed and prefer using custom tables which are far easier to reason about. In this specific case you want an index of:

create unique index idxStartEvent on topic_custom_fields(topic_id) where name = 'start_event'

Not sure what else really we need to do in core here, we have considered a revamp of custom fields but are somewhat worried about it. One thing I am considering is simply dropping array support from custom fields cause they are just causing enormous amounts of issues over the years.

3 Likes

Sorry for bumping this up but one of the conditions is when you use a symbol index i.e. custom_fields[:hello] while updating the existing value, it added another field instead of updating and hence the giving an array. This might be the only condition IMO.

This should fix the caused side-effect most certainly.
https://github.com/discourse/discourse/pull/10486

2 Likes