There are a few ‘how to start’ guides for working with Discourse already and a wealth of useful info on meta, but I thought it might help to give an insight to the mental processes of starting from little, if any, prior coding experience to building substantial Discourse plugins.
Discourse is written by experienced developers and has a large codebase. This can feel intimidating. This intimidation factor can be a significant barrier for novice developers. This is a kind of ‘psychological primer’ to building stuff for Discourse.
I’m not an expert at coding. I only taught myself how to code last year by playing around with Discourse. I’m partly putting this here because this is the basic approach I use to answer any questions I (or others) have when working with Discourse and it will be useful to link to.
1. Know the basics
Despite it’s size, the Discourse codebase is easy to navigate if you know some basics. This is a testament to the quality of the work that has gone into it.
You have to start with understanding roughly how things work. That makes building new things a lot easier.
Specifically you need to understand:
Time: about 30 minutes to 1 hour.
The basics of how templates, views, controllers, models and routes work in Ember.js. You can cover this by reading the Ember.js guide.
Time: about 30 minutes.
The basic structure of the application so you know where to look for stuff:
- The ‘client’ is mostly in the
- The ‘server’ is mostly in the other folders in
app. It is also in the
Time: 10 mins.
- The ‘client’ is mostly in the
The basics of how to build a plugin. Just read the 6-part guide to building plugins and you’re done.
Time: 30 mins
The basics of how ruby on rails works (optional). There are hundreds of RoR guides and how-tos out there. Actually the only ‘text’ on ruby I’ve read is Why’s Poignant Guide, which is very readable and quite funny.
Time: about 1 hour.
How the Discourse server interacts with the Discourse client. Simply put all server / client interactions happen through ajax requests. Invariably, the answer to any question like “How do I get this data?” is that you retrieve it form the server via ajax. Do a search for
Discourse.ajaxin the github repository and you will see lots of examples.
Time: 10 mins.
This background reading and absorption should take a couple of hours. You could do it one Saturday morning in your PJs.
2. Start with what you know (and can see).
Question: How do I get the information about a user on their summary page? (e.g. Profile - angus - Discourse Meta)
Answer: The best way to find what you’re looking for is to start from what you know.
We know that the information we want is available at
/users/[username]/summary. So how does that page get the information? Well let’s start by having a look at the template or whatever is actually rendering the information. That is the next level down from “I am seeing the information on the screen”.
In this case, the the user summary has a template. We know from our reading that all the templates are in this folder. Look through the folder for things that look relevant. There’s a folder named ‘User’. This data is about a user, so let’s look in there. In that folder, there’s a template called ‘Summary’. That’s a word that’s used in the path where we know the info is. Cool, looks like we found it.
Hm, looks like the information that’s being rendered is coming from a model.
We know from our reading that in Ember.js the model is loaded by a route file (see this part of the guide). We know from our reading that the route file for
/user/[username]/summary is in
user-summary looks like it’s relevant.
Thankfully, it’s nice and simple. It’s using the method
summary from the
User model. So let’s have a look at the
User model method
Turns out that this is exactly what we’re after. This is a ajax request from the client to the server. We know that this is how the client gets all its info from the server.
So we already have our answer. We can do exactly the same thing in a plugin. Start by copying that ajax request and then modify it to suit your needs. This leads us to the next point.
3. Copy and use the Discourse code.
Discourse is an open source project. It’s a very well written open source project. So if Discourse already does something, or does something similar to what you want to do, start by copying or using what Discourse does.
For example, I started writing my Quick Messages plugin by literally copying swathes of code from the composer controller and the code that, prior to the widgetized header, displayed the header menu items. You can see that perhaps the most important method in the whole plugin, the method that saves a new post, is just a modified version of the same method in Discourse.
If Discourse actually does exactly what you want to do, but just in a different context, then there’s no need to re-invent the wheel. In most cases it is possible to use the existing Discourse solution in a different context. This is easy to do with ECMAScript 6 modules. For example, the Topic Previews Plugin imports a bunch of existing Discourse helpers that solve various issues it needs overcome.
Another trick I like to use is to start by actually modifying the Discourse code itself, before trying to work with it in the context of a plugin. You want to add another icon to the header? Start by trying to add another item to the header directly in the Discourse codebase on your local machine. Find the code that renders the current items, then just try to add some additional items by directly modifying that code. Once you’ve managed to do that, then try to apply that approach within your plugin. This approach removes additional sources of errors that can arise when working in the context of a plugin. If things are going wrong in your plugin it may be because you’re not using the plugin api correctly, or it may be because you’re not using the virtual dom correctly. Sometimes it helps to start by reducing the scope of the source of your errors.
4. Keep it simple and open
As the Discourse codebase is large, you can sometimes get lost in it. Sometimes it can feel like your search for a solution is leading you down a rabbit-hole of complexity.
Always remember that in 99% of cases the answer to your current problem will be simple. It’s a matter of finding the simple solution. One way to find that solution is to use the community, either by posting on meta or by opening up your code to use and scrutiny. There’s a good discussion of how this open approach works in Eric Raymond’s The Cathedral and the Bazaar:
“Given enough eyeballs, all bugs are shallow.” I dub this: “Linus’s Law”. My original formulation was that every problem “will be transparent to somebody”. Linus demurred that the person who understands and fixes the problem is not necessarily or even usually the person who first characterizes it. “Somebody finds the problem,” he says, “and somebody else understands it. And I’ll go on record as saying that finding it is the bigger challenge.” … In the bazaar … you assume that bugs are generally shallow phenomena—or, at least, that they turn shallow pretty quickly when exposed to a thousand eager co-developers
On an individual scale, this means that you should stay focused on what you know and what you want to achieve. Don’t get lost in trying to understand the inner workings of everything. In most cases, the basic background knowledge listed at the beginning of this post are enough to achieve what you want to do.
If you get stuck, either use the community, or simply persevere. 99% of problems are a matter of time and patience, not some deep technical understanding.
I hope that helps somebody.