O que é esse código add_to_serializer em todos esses 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

Ei, adicionei um campo personalizado à minha caixa de edição de categoria.

Ao enviar o formulário, vejo no console do JS que esses campos são enviados assim:
custom_fields[default_tag][]:good-feedback custom_fields[default_tag][]:one-more-tag

No meu arquivo principal do plugin, estou fazendo:

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

Meus campos personalizados não estão sendo salvos no banco de dados.

fazer:

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

agora funciona?

Naquela época, resolvi o problema adicionando uma função ao evento :before_action e convertendo o array para uma string delimitada, e vice-versa, ao recuperar os dados.

Na verdade, não investiguei por que um array não pode ser armazenado como um campo personalizado nativamente.

Então isso pode potencialmente simplificar o código?

Sim, seria, se funcionasse neste caso. Vou tentar isso daqui a pouco e te retorno.

Que pena, deve ter sido doloroso na época :wink:

Era um domingo à noite e a curiosidade falou mais alto. Foi um pouco doloroso, mas divertido.
Era algo que @pfaffman estava tentando fazer.

Sem dor, sem ganho :wink:

haha, muito verdadeiro! …

Olá, estou com o mesmo problema (os custom_fields são enviados no console do JS, mas não estão sendo salvos no banco de dados). Usei a forma add_to_serializer(:basic_category, :default_tag, false ){object.custom_fields["default_tag"]} no meu arquivo principal do plugin.

Você ainda recomendaria essa solução?

Muitas dúvidas estão surgindo aqui. Campos personalizados de quê, em primeiro lugar?

Estou trabalhando em um plugin para automatizar a sincronização de grupos do Discourse com o LDAP. Adicionei um campo personalizado ao Grupo (ldap_dn) para armazenar o nome do grupo LDAP. Estou tentando recuperar o valor do campo personalizado a partir de um campo de entrada que adicionei no plugin-outlet de associação e salvá-lo no banco de dados para uso posterior.

Para fazer isso, adicionei o seguinte ao meu arquivo 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

Sou novo em Rails e Ember, então não tenho certeza se há outra etapa que deveria realizar para salvar os custom_fields no banco de dados ou onde está o problema.

Acho que, se você adicionar
register_editable_group_custom_field 'field_name'
no seu plugin.rb

isso deve resolver o problema

Nota:
O Serializer é usado para enviar dados ao cliente, não para recebê-los.

Ah, tudo bem! Sou iniciante, então essa pode ser uma pergunta muito óbvia, mas para receber os dados, devo fazê-lo usando a API?

Minha solução dará um sinal verde para o seu campo quando ele chegar ao servidor. Então, trata-se de receber os dados.