What is this code add_to_serializer in all these 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

Heyy, I have added a custom field to my category edit box.

When I submit the form, I can see something these fields are submitted in the js console
custom_fields[default_tag][]:good-feedback custom_fields[default_tag][]:one-more-tag

in my main plugin file, I am doing

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

My custom fields aren’t getting saved to the db.

does doing:

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

now work?

I had solved it that time by adding a function on :before_action event and converted the array to a delimited string and vice versa while retrieving.

I didn’t actually dig into why an array couldn’t be stored as custom field out of the box.

So this might streamline the code potentially?

Yes it would if it worked in this case. I’ll try this in sometime and get back to you.

Poor you that must’ve been painful at the time :wink:

It was a sunday evening and curiosity took over. It was somewhat painful but fun.
It was something that @pfaffman was trying to do.

No pain no gain :wink:

haha, so true! …

안녕하세요, 저도 같은 문제를 겪고 있습니다. (custom_fields가 js 콘솔에는 제출되지만 데이터베이스에 저장되지 않음) 메인 플러그인 파일에서 add_to_serializer(:basic_category, :default_tag, false ){object.custom_fields[“default_tag”]} 방식을 사용했습니다.

여전히 이 해결책을 권장하시나요?

여기서 많은 질문이 제기됩니다. 우선, 무엇의 커스텀 필드인가요?

Discourse 그룹 동기화를 LDAP와 자동화하기 위한 플러그인을 개발 중입니다. LDAP 그룹 이름을 저장하기 위해 Group에 사용자 정의 필드(ldap_dn)를 추가했습니다. 멤버십 플러그인 아웃렛에 추가한 입력 필드에서 custom_field 값을 가져와 데이터베이스에 저장하고 나중에 사용하려고 합니다.

이를 위해 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

Rails와 Ember에 익숙하지 않아 custom_fields가 데이터베이스에 저장되도록 해야 할 다른 단계가 있는지, 아니면 문제가 어디에 있는지가 명확하지 않습니다.

플러그인.rb 파일에
register_editable_group_custom_field 'field_name'
을 추가하면

원하는 대로 동작할 것입니다.

참고:
Serializer는 데이터를 클라이언트로 전송하는 데 사용되며, 데이터를 수신하는 데에는 사용되지 않습니다.

아, 알겠습니다! 저는 초보자라서 너무 당연한 질문일 수도 있겠지만, 데이터를 받으려면 API를 사용해야 하나요?

제 솔루션은 데이터가 서버에 도달하면 해당 필드에 대해 녹색 신호를 보내줍니다. 따라서 이는 데이터 수신에 관한 것입니다.