Rails plugin generator

(Joffrey Jaffeux) #1

This is a dev feature for our beloved plugin authors.

With this commit DEV: rails generator to create plugin skeleton (#6332) · discourse/discourse@ef36fdf · GitHub you can now use rails generators to create plugins:

rails g plugin --help
rails g plugin DiscourseRacoon

This will create a complete discourse plugin skeleton in your plugins directory:

rails g plugin DiscourseRacoon --no-scheduled-job
      create  plugins/discourse-racoon/README.md
      create  plugins/discourse-racoon/LICENSE
      create  plugins/discourse-racoon/plugin.rb
      create  plugins/discourse-racoon/assets/stylesheets/common/discourse-racoon.scss
      create  plugins/discourse-racoon/assets/javascripts/initializers/discourse-racoon.es6

It’s currently doing very few things #pr-welcome on this if you see things to improve or options to add.

@angus @joebuhlig Happy to hear your thoughts on this.

Thanks @david for pushing me to write this as a generator.

How to create a new plugins?
Plugin Tutorial #1 - How to manipulate the text in the composer?
About the Plugin category
Discourse 2.1.0.beta6 Release Notes
Guide or Documentation for creating a Plugin?
Beginner's Guide to Creating Discourse Plugins - Part 1

goodness … almost like ember cli … /gets coat :male_detective: :wink:

Joking aside, that’s not just a productivity boost, but a nice help for newbies too, thanks!

(Robin Ward) #3

I really :heart: this.

It might be worth going back through all our guides/tutorials and updating them to use this.

(Dan Ungureanu) #7

Congratulations! It looks nice. :+1:

I started something similar. I am glad that a plugin generator is finally available, hopefully it will motivate other people to write more plugins!

(Christoph) #8

Except that plugin newbies like myself have (almost) no clue what this machine does :woozy_face: I guess that’s not the kind of newbies you meant…


@tophee it’s not the easiest skill to pick up but I’ve started to hit my stride after a few false starts.

Take a look at:

The most important tip is this: have something you passionately want to build in/add … then you will climb the required mountains :wink:

(Angus McLeod) #10

This is awesome :slight_smile: :tada:

A few quick thoughts:

  • You could add notes in the plugin.rb and the initializer to direct the author to discourse-specific methods they can use in each context. Something like

    after_initialize do
      # see lib/plugin/instance.rb for the methods available in this context
    withPluginApi('0.8.x', api => {
      // see app/assets/javascripts/discourse/lib/plugin-api for the functions available via the api object.
  • On first blush I wondered whether it makes sense to create the module and engine out of the box. A number of plugins don’t need any new server methods. But on balance I think it makes sense, as it indicates the way to go about it, and there’s no harm in having an unused module.

  • I reckon the about should be blank rather than AWESOME_PLUGIN.

  • It’s cool that the url defaults to github.com/${author} however this was a little unexpected. Sometimes folks put their full name in that field and sometimes there are multiple authors (e.g. the polls plugin), which could make this problematic. Perhaps the CLI could explicitly ask for the author’s github username then use that for both the author and to generate the url.

Generally, how far do you want to go down the path of explicit direction / hand-holding?

If the goal is to make it easier for new plugin devs to find their feet, there are a number of other things we could add such as more notes or links to helpful meta topics, examples of overriding existing Discourse methods and other common plugin patterns.

(Mittineague) #11

There’s going to need to be an arbitrary “scope” for this. eg. always, optional but common, advanced rarely, etc.

I think heavily commented and URLs to “man” pages would be good.

I also think having config locale and spec / acceptance folders might encourage more plugin authors to l10n and write tests.

(Joffrey Jaffeux) #12

Thanks! I pinged you knowing you would have very good insights, not disappointed :smiley:

There’s indeed a decision to take between: skeleton or skeleton + help build your first plugin

Maybe we could have an option: “–beginner” on by default, which would add comments at multiple places?

(Joffrey Jaffeux) #13

Most of your comments should be addressed by:

(Angus McLeod) #14

I was just testing a theory about the origin of an issue in the elections and qa plugins, and needed to test some logic in isolation. Normally I would create a new plugin by hand to do this, but this time it was much easier using the plugin generator, just a single command. Useful already :slight_smile: Thanks.

I was getting a NameError though on initial load after generating a plugin (I had removed tmp). The plugin.rb includes an auto-generated enabled_site_setting out of the box, but the setting isn’t defined in config/settings.yml. If you add the setting, the error goes away. We’ll need to either remove the auto-generated enabled setting or add a config/settings.yml with the auto-generated enabled setting included by default.

(Joffrey Jaffeux) #15


Should be now correctly handled by:

(Joffrey Jaffeux) #16

This is adding support for controller/routes/spec/acceptance:

(Joe Buhlig) #17

:heart_eyes: Absolutely love this, @joffreyjaffeux! I have a local templated plugin that I use for this exact purpose. I can create the git repo and then copy/paste the files into the directory to create the “Initial commit.” So I can easily see us using this heavily at ProCourse.

Notes about potential enhancements:

  • Looks like you have MIT as the license that comes with this. Most of our plugins are license free since they are proprietary and private. The code is owned by the client. But we have a fair number of clients who choose to share their commissioned work with the world and as such we drop in a GNU GPL v2 license on the repo. It’s been a challenge nailing down a license to use for those, but the general thinking is that it should follow core. My ask here is whether or not it should allow us to choose a license to be included.

  • Include license URL in about section? We do this as part of themes already. It would likely be a good thing to do the same for plugins and then link to the license on the /admin/plugins page.

  • I have a tendency to build plugins using a dedicated /my-plugin/lib/my-plugin/engine.rb file with an associated /config/routes.rb file. The plugin.rb file is great for showing me where to start, but I use it as a collecting zone for the structure of the plugin. The actual logic is stored in the engine file. I’d love for this to allow a one liner that creates that structure automatically.

  • I can see how this could evolve in the future as well. Maybe a way to standardize the way plugins are built. For example, from the plugin directory, rails g plugin i18n en.js.my-plugin.my-localization-string. But it could be used to add plugin settings, routes, jobs, etc… Not sure how much I would personally use this because I know these structures and how they work. But for those new to the system, it could lower the learning curve a bit.

  • More flexible about section? We use the Author line as ProCourse for every new plugin as opposed to the GitHub username. We also make sure the URL of the plugin is a full URL and not a link to the GitHub profile. Maybe it’s just me, but it seems like you could take the Name sent to the generator and the GitHub username and assume the repo name matches the name of the plugin (lowercased and dasherized). But I could see that causing issues in some places as well.

  • Local defaults? This may just be the nature of my business, but I find myself (or a team member) creating a new plugin structure two to four times a week, sometimes more. And we have a set structure for the about section that we use. It would be great if we could save some defaults locally that work every time without the need to answer the questions each run.

That’s my first run through it. I’ve run it a couple times and can already see it speeding up the process significantly. Thank you! :hugs:

(Joffrey Jaffeux) #18

Thx, great points. Could you send me (in PM if necessary) an example plugin demonstrating the above points please ?

(Joe Buhlig) #19

I just finished creating a public version of this. That way others can use it as well and I can share links to specifics since I realized there are some more points that I do.

  • Whenever I add custom routes to a plugin, I always use a Constraint that ties to the plugin enabled setting. This prevents the routes from existing unless the site setting is true. I wish I saw this more in plugins as custom routes shouldn’t be allowed just because the plugin is installed.

  • This template includes a Rails controller and an Ember route. These are only used in about half of the plugins I do, but it’s nice to have them there just so the structure already exists. I don’t know that this generator needs to include these pieces, but it’s helpful on my end.

  • I always start my stylesheets with a global class selector. Every time I add HTML to the plugin, I start with a wrapper div with class="discourse-plugin-template". That ensures that my styles only apply to my custom code. Sometimes I need to add CSS outside of that selector, but it seems like most cases don’t have that requirement.

(David Taylor) #20

The ‘built-in’ method for this is to use requires_plugin in the plugin controller. I agree that this isn’t used as much as it should be though, even in official plugins. (Example here, defined here)

(Sivert) #21

Just created a plugin with name “TrustLevelGroups” using plugin generator, after that can’t run server cause an error