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

こんにちは、カテゴリ編集ボックスにカスタムフィールドを追加しました。

フォームを送信すると、JS コンソールでこれらのフィールドが送信されているのが確認できます。
custom_fields[default_tag][]:good-feedback
custom_fields[default_tag][]:one-more-tag

メインのプラグインファイルでは、以下のようにしています。

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

しかし、カスタムフィールドがデータベースに保存されません。

以下のようにすることで、

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

今は動作しますか?

その時は、:before_action イベントで関数を追加し、配列を区切り文字付きの文字列に変換し、取得時にその逆の変換を行うことで解決しました。

カスタムフィールドとして配列をそのまま保存できない理由については、実際には深く追及していません。

これでコードが簡素化される可能性がありますか?

そのケースで機能すれば、そうなりますね。後で試して、改めてご連絡します。

かわいそうに、そのときは辛かったでしょうね :wink:

それは日曜日の夜で、好奇心が勝りました。少し痛かったけれど、楽しかったです。
それは @pfaffman がやろうとしていたことです。

痛みなくして得るものなし :wink:

はは、その通りですね!…

こんにちは、私も同じ問題が発生しています(カスタムフィールドは JS コンソールで送信されていますが、DB に保存されません)。メインのプラグインファイルで add_to_serializer(:basic_category, :default_tag, false ){object.custom_fields["default_tag"]} という方法を使用しました。

この解決策をまだ推奨されますか?

ここで多くの質問が出てきています。まず何のカスタムフィールドについてですか?

Discourse のグループを LDAP と同期させるためのプラグインを作成しています。グループに ldap_dn というカスタムフィールドを追加し、LDAP グループ名を保存できるようにしました。メンバーシップの plugin-outlet に追加した入力フィールドからカスタムフィールドの値を取得し、データベースに保存して後で使用できるようにしようとしています。

そのために、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 に不慣れなため、カスタムフィールドをデータベースに保存するために他にやるべきステップがあるのか、あるいは問題の箇所はどこなのか確信が持てません。

plugin.rb に
register_editable_group_custom_field 'field_name'
を追加すれば、問題が解決するはずです。

注:
Serializer はクライアントへデータを送信するために使用され、受信には使用されません。

ああ、わかった!初心者なので、もしかしたら「そんなの当たり前」的な質問かもしれないけど、データを受け取るには、APIを使うの?

私のソリューションは、データがサーバーに到達した時点で、あなたのフィールドに承認の合図(グリーンフラッグ)を出します。つまり、データを受信することに関するものです。