Qu'est-ce que ce code add_to_serializer dans tous ces plugins

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

Salut, j’ai ajouté un champ personnalisé à ma boîte d’édition de catégorie.

Lorsque je soumets le formulaire, je vois dans la console JS que ces champs sont soumis :
custom_fields[default_tag][]:good-feedback custom_fields[default_tag][]:one-more-tag

Dans mon fichier principal de plugin, je fais :

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

Mes champs personnalisés ne sont pas enregistrés dans la base de données.

Est-ce que faire :

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

désormais fonctionner ?

Je l’avais résolu à l’époque en ajoutant une fonction sur l’événement :before_action et en convertissant le tableau en une chaîne délimitée, et vice versa lors de la récupération.

Je n’ai pas vraiment creusé pour savoir pourquoi un tableau ne pouvait pas être stocké directement en tant que champ personnalisé.

Cela pourrait donc potentiellement simplifier le code ?

Oui, ce serait le cas si cela fonctionnait dans ce cas précis. Je vais essayer cela dans un moment et je reviendrai vers vous.

Pauvre toi, ça a dû être douloureux à l’époque :wink:

C’était un dimanche soir et la curiosité a pris le dessus. C’était un peu douloureux mais amusant.
@pfaffman essayait de faire quelque chose de ce genre.

Pas de douleur, pas de gain :wink:

haha, c’est tellement vrai ! …

Bonjour, je rencontre le même problème (les custom_fields sont envoyés dans la console JS, mais ne sont pas enregistrés dans la base de données). J’ai utilisé la méthode add_to_serializer(:basic_category, :default_tag, false ){object.custom_fields["default_tag"]} dans mon fichier principal de plugin.

Recommanderiez-vous toujours cette solution ?

Il y a beaucoup de questions qui se posent ici. Des champs personnalisés de quoi, avant tout ?

Je travaille sur un plugin pour automatiser la synchronisation des groupes Discourse avec LDAP. J’ai ajouté un champ personnalisé au modèle Group (ldap_dn) pour y stocker le nom du groupe LDAP. J’essaie de récupérer la valeur de ce champ personnalisé depuis un champ de saisie que j’ai ajouté dans le plugin-outlet membership, puis de la sauvegarder en base de données pour une utilisation ultérieure.

Pour cela, j’ai ajouté ceci à mon fichier 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

Je débute avec Rails et Ember, donc je ne suis pas sûr de savoir s’il y a une autre étape à effectuer pour que les custom_fields soient bien enregistrés en base de données, ou où se situe le problème.

Je pense que si vous ajoutez
register_editable_group_custom_field 'field_name'
dans votre fichier plugin.rb

cela devrait faire l’affaire

Note :
Le serializer est utilisé pour envoyer les données au client et non pour les recevoir.

Ah d’accord ! Je suis débutant, donc c’est peut-être une question très ‘évidente’, mais pour recevoir les données, dois-je le faire via l’API ?

Ma solution donnera un feu vert à votre champ lorsqu’il arrivera sur le serveur. Il s’agit donc de recevoir les données.