See discourse/instance.rb at main · discourse/discourse · GitHub for the plugin-related methods Discourse provides.
GitHub - literatecomputing/discourse-google-group-link is a simple plugin that does most of the plugin basics:
- adds a custom category field
- adds it to the serializer
- adds some stuff to a page
- uses a callback to make code fire when a topic is created
Custom Field Types
For simple additions to a model, MODEL_custom_fields
are the way to go. A few lines of code enable you to add a new field to a model. The Google Group Link plugin adds a custom category field to indicate whether new topics in the category should be scanned for the Google Group name, and a custom topic field to hold the link to the message in Google Groups.
Here’s another example:
register_category_custom_field_type("ratings_list", :string)
Will add a string custom category field (that will be a |
-delimited string of custom items (that will be added to topics in that category).
register_topic_custom_field_type("rating_topic_id", :integer)
Will add a field for the topic that this rating is discussing.
These helper methods are defined in instance.rb.
Adding data to the serializer
Not all fields in an object are made available to the front end (or sent out in .json
routes), so when we add a field that we want to be made available to the front end, we need to add it to the serializer.
TODO: Insert here a way to find out what the serializers are.
Here is how the Google Group plugin adds the Google Group link to the topic serializer, so that when Rails renders a topic in the serializer, this new field will be a part of it. It is then up to the front end (Ember) to do something with that information, like display it or use it in Javascript to make something else happen.
The above code checks to make sure that there is a value to render to avoid causing an error by trying to render nil
. A well-written plugin would include specs that have tests to see that the expected data get added to the serializer and that conditions like nil values do not cause errors.
The example below will add to the category serializer the custom ratings that are to be included in topics created in that category. (I don’t know right now if this will actually get the information where we need it for the plugin that I am currently planning, but that’s only important to me.)
add_to_serializer(:category, :ratings_list) do
next unless (self.category.custom_fields[RATINGS_LIST]
value = self.category.custom_fields[RATINGS_LIST]
end
Adding methods to a class
In addition to adding attributes (aka customfields fields) to a model, you can also add methods. Ruby and Rails provide a means to override an existing class, but Discourse provides this helper method to make things easier. This method, called later from a callback, checks if the field has been populated already, then parses the raw
text of the message to look for the Google Group link, and if it finds it, stores it in the custom field and saves the record. It includes a rescue
to catch and log any errors generated when it runs.
self
is the instance of the model being added to. In this example, a variable topic
is created to make that more clear, but then the code uses self
rather than the more readable topic
.
You might also add methods if you need to add some value to a serializer that needs to be computed at the time that a page’s data is rendered.
Adding callbacks
Callbacks make it possible to execute code when something happens (see Active Record Callbacks — Ruby on Rails Guides for details and a list of available callbacks).
This example runs after a new topic is committed. As with the add_to_class
helper, self
is the instance of the model being modified. Here the category is looked up to gain access to the category custom field defined earlier. We check to make sure that a category was found, which can happen when a PM is created. We might also have used t.archetype
to avoid looking for a category when none can exist.
(Next, we break out if this category is not a mailinglist_mirror
. @pfaffman is quite confused, as mailinglist_mirror
isn’t defined anywhere, and is pretty sure that the code was working when it was deployed.)
The custom method add_google_group_link
is used to add the link to the topic_custom_field
.