Che cos'è questa funzione add_to_serializer in tutti questi plugin

I have seen this code in discourse_signatures plugin

User.register_custom_field_type('see_signatures', :boolean)
User.register_custom_field_type('signature_url', :text)
User.register_custom_field_type('signature_raw', :text)

if SiteSetting.signatures_enabled then
  add_to_serializer(:post, :user_signature, false) {
    if SiteSetting.signatures_advanced_mode then
      object.user.custom_fields['signature_raw']
    else
      object.user.custom_fields['signature_url']
    end
  }

  # I guess this should be the default @ discourse. PR maybe?
  add_to_serializer(:user, :custom_fields, false) {
    if object.custom_fields == nil then
      {}
    else
      object.custom_fields
    end
  }
end

In discourse national flags plugin

User.register_custom_field_type('nationalflag_iso', :text)

if SiteSetting.nationalflag_enabled then
  byebug;
  add_to_serializer(:post, :user_signature, false) {
    object.user.custom_fields['nationalflag_iso']
  }
  byebug;
  # I guess this should be the default @ discourse. PR maybe?
  add_to_serializer(:user, :custom_fields, false) {
    if object.custom_fields == nil then
      {}
    else
      object.custom_fields
    end
  }
end

I am not able to understand what is add_to_serializer is doing.

I checked in def add_to_serializer

def add_to_serializer(serializer, attr, define_include_method=true, &block)
  klass = "#{serializer.to_s.classify}Serializer".constantize rescue "#{serializer.to_s}Serializer".constantize

  klass.attributes(attr) unless attr.to_s.start_with?("include_")

  klass.send(:define_method, attr, &block)

  return unless define_include_method

  # Don't include serialized methods if the plugin is disabled
  plugin = self
  klass.send(:define_method, "include_#{attr}?") { plugin.enabled? }
end

I understand that User.register_custom_field_type('signature_raw', :text) will register a custom field type to User object. But what is add_to_serializer doing? I am not able to understand, can you explain me in plain english?

It’s essentially adding to the information that Discourse serializes out when sending that model to the client. For example, you may see a request to this endpoint when loading up a topic page:

http://meta.discourse.org/t/2349082394.json

which returns some payload like this:

{
  title: "Some topic title",
  archetype: 'regular',
  category_id: 7,
  post_stream: { posts: [...] },
  posts_count: 15,
  (etc etc.. lots more info about the topic in question)
}

Which is the json representation of a Discourse topic.

If I want to know more about the topic because of additional ‘stuff’ I do in my plugin, I can put in a line like

add_to_serializer :topic, :flag_name do
  object.flag_name # <- NB that 'object' here is the topic being serialized
end

(Also, by default, this method simply sends the specified message to ‘object’, meaning that

add_to_serializer :topic, :flag_name

is the same as

add_to_serializer :topic, :flag_name do
  object.flag_name
end

)

Once I’ve added the method to the serializer, I can end up with JSON output which includes that additional info

{
  title: "Some topic title",
  archetype: 'regular',
  category_id: 7,
  post_stream: { posts: [...] },
  posts_count: 15,
  flag_name: "some flag name"
  ...
}

Also note that you could achieve the same thing by overwriting the TopicSerializer class (which is exactly what the code snippet you’ve provided is doing)

# plugin.rb
TopicSerializer.class_eval do
  attributes :flag_name
  def flag_name
    object.flag_name
  end
end

Hi,
When running the following code,

TopicSerializer.class_eval do
  attributes :flag_name
  def flag_name
    object.flag_name
  end
end

I was getting the error “block in activate!’: uninitialized constant TopicSerializer (NameError)”. I think I have to “import” or “require” the TopicSerializer dependency. Can you please tell me what would be the dependency, as I am not able to figure it out.

Add this directly above your code require_dependency 'topic_serializer'

require_dependency 'topic_serializer'
class ::TopicSerializer
  attributes :flag_name
  def flag_name
    object.flag_name
  end
end

Hi thanks, but I got the error " `load’: No such file to load – topic_serializer (LoadError)". Does it pull from the app/serializers folder? I checked in that folder, I could find topic_list_serializer.rb, and many other related to topic, but couldnt find topic_serializer.rb

Right! Try TopicViewSerializer.

require_dependency 'topic_view_serializer'
class ::TopicViewSerializer
  attributes :flag_name
  def flag_name
    object.flag_name
  end
end

Ehi, ho aggiunto un campo personalizzato alla casella di modifica della categoria.

Quando invio il modulo, vedo che questi campi vengono inviati nella console JS:
custom_fields[default_tag][]:good-feedback custom_fields[default_tag][]:one-more-tag

Nel mio file principale del plugin, sto facendo:

add_to_serializer(:basic_category, :default_tag){object.custom_fields[“default_tag”]}

I miei campi personalizzati non vengono salvati nel database.

funziona ora se si fa:

add_to_serializer(:basic_category, :default_tag, false ){object.custom_fields["default_tag"]}

L’avevo risolto in quel momento aggiungendo una funzione all’evento :before_action e convertendo l’array in una stringa delimitata e viceversa durante il recupero.

Non ho approfondito il motivo per cui un array non può essere memorizzato come campo personalizzato senza configurazioni aggiuntive.

Quindi questo potrebbe potenzialmente snellire il codice?

Sì, funzionerebbe se funzionasse in questo caso. Ci proverò tra un po’ e ti farò sapere.

Povero te, dev’essere stato doloroso in quel momento :wink:

Era una domenica sera e la curiosità ha preso il sopravvento. È stato un po’ doloroso ma divertente.
Era qualcosa che @pfaffman stava cercando di fare.

Niente dolore, niente guadagno :wink:

haha, è proprio vero! …

Ciao, ho lo stesso problema (i custom_fields vengono inviati nella console JS, ma non vengono salvati nel database). Ho usato il metodo add_to_serializer(:basic_category, :default_tag, false ){object.custom_fields["default_tag"]} nel mio file principale del plugin.

Consiglieresti ancora questa soluzione?

Ci sono molte domande che sorgono qui. Campi personalizzati di cosa, innanzitutto?

Sto lavorando a un plugin per automatizzare la sincronizzazione dei gruppi di Discourse con LDAP. Ho aggiunto un campo personalizzato a Group (ldap_dn) per salvare il nome del gruppo LDAP. Sto cercando di recuperare il valore del campo personalizzato da un campo di input che ho aggiunto nel plugin-outlet per l’iscrizione e salvarlo nel database per utilizzarlo in seguito.

Per fare questo, ho aggiunto quanto segue al mio file plugin.rb:

Group.register_custom_field_type(‘ldap_dn’, :text)
Group.preload_custom_fields << “ldap_dn” if
Group.respond_to? :preloaded_custom_fields

if SiteSetting.groups_sync_enabled then
add_to_serializer(:group_show, :custom_fields, false) {
object.custom_fields
}
end

Sono nuovo di Rails ed Ember, quindi non sono sicuro se ci sia un altro passaggio da compiere per salvare i custom_fields nel database o dove risieda il problema.

Penso che se aggiungi
register_editable_group_custom_field 'field_name'
al tuo plugin.rb

dovrebbe funzionare.

Nota:
Il Serializer viene utilizzato per inviare i dati al client e non per riceverli.

Ah, ok! Sono un principiante, quindi questa potrebbe essere una domanda molto ‘ovvia’, ma per ricevere i dati, devo farlo tramite l’API?

La mia soluzione darà il via libera al tuo campo quando i dati arriveranno al server. Quindi si tratta di ricevere i dati.