所有这些插件中的 add_to_serializer 这个代码是什么

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:

哈哈,太对了!…

你好,我也遇到了同样的问题(custom_fields 在 JS 控制台中已提交,但未能保存到数据库)。我在主插件文件中使用了 add_to_serializer(:basic_category, :default_tag, false ){object.custom_fields["default_tag"]} 这种方式。

您仍然推荐这个解决方案吗?

这里出现了很多问题。首先,是哪些自定义字段?

我正在开发一个插件,用于自动化 Discourse 群组与 LDAP 的同步。我为 Group 添加了一个自定义字段(ldap_dn),用于保存 LDAP 群组名称。我试图从我在 membership plugin-outlet 中添加的输入字段中获取 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 保存到数据库中,或者问题出在哪里。

我认为,如果你在 plugin.rb 中添加
register_editable_group_custom_field 'field_name'
应该就能解决问题。

注意:
Serializer 用于将数据发送给客户端,而不是接收数据。

啊,好的!我是新手,所以这可能是个特别“显而易见”的问题,但为了接收数据,我需要通过 API 来获取吗?

我的解决方案会在数据到达服务器时,为字段发出绿灯信号。因此,这关乎于接收数据。