Forem Creators and Builders 🌱

Andrew Brown
Andrew Brown

Posted on

How to create your own Plugin for Forem server (or how to override template files)

Forem does not yet have an official plugin system, but I suspect that will be architected sometime in the future.

In the meantime I am going to create my own solution that aims to extend or override the code but be as self-contained in a Rails Engine so we can avoid future merge conflicts.

# Preparing our Plugin

Our plugin is going to be a Rails Engine. A Rails Engine is essentially a mountable rails app that is loaded as a gem.

We might want to add many custom plugins in the future, and so it will be a good idea to lay the groundwork by creating a script just for plugins, to reduce merge conflicts in the future.

So here I am including two new lines in the Gemfile:

require_relative 'forem_plugins'
load_forem_plugins
Enter fullscreen mode Exit fullscreen mode

The exact placement in my Gemfile

# coding: utf-8
require_relative 'forem_plugins'
git_source(:github) { |name| "https://github.com/#{name}.git" }
source "https://rubygems.org"
ruby File.read(File.join(File.dirname(__FILE__), ".ruby-version")).strip
load_forem_plugins
Enter fullscreen mode Exit fullscreen mode

Within the load_forem_plugins I create a single function to contain my plugins.

I am referencing a gem to a local path (which I have yet to create)

def load_forem_plugins
  gem "forem_custom_styles", path: '~/Sites/forem-plugins/forem_custom_styles'
end
Enter fullscreen mode Exit fullscreen mode

Generate a new Rails Engine

I am going to create a new Rails Engine in my ~/Sites/forem-plugins/ directory

rails plugin new forem_custom_styles --full
Enter fullscreen mode Exit fullscreen mode

It will generate a skeleton Rails Engine:

      create
      create  README.md
      create  Rakefile
      create  forem_custom_styles.gemspec
      create  MIT-LICENSE
      create  .gitignore
      create  Gemfile
         run  git init from "."
Initialized empty Git repository in /Users/andrewbrown/Sites/forem-plugins/forem_custom_styles/.git/
      create  app/models
      create  app/models/.keep
      create  app/controllers
      create  app/controllers/.keep
      create  app/mailers
      create  app/mailers/.keep
      create  app/jobs
      create  app/jobs/.keep
      create  app/assets/images/forem_custom_styles
      create  app/assets/images/forem_custom_styles/.keep
      create  app/helpers
      create  app/helpers/.keep
      create  app/views
      create  app/views/.keep
      create  config/routes.rb
      create  lib/forem_custom_styles.rb
      create  lib/tasks/forem_custom_styles_tasks.rake
      create  lib/forem_custom_styles/version.rb
      create  lib/forem_custom_styles/engine.rb
      create  app/assets/config/forem_custom_styles_manifest.js
      create  app/assets/stylesheets/forem_custom_styles
      create  app/assets/stylesheets/forem_custom_styles/.keep
      create  bin/rails
      create  test/test_helper.rb
      create  test/forem_custom_styles_test.rb
      append  Rakefile
      create  test/integration/navigation_test.rb
  vendor_app  test/dummy
Enter fullscreen mode Exit fullscreen mode

We need to update the forem_custom_styles.gemspec information anywhere it says TODO otherwise it will complain when go to bundle install the gem.

In my Forem app I am going to do a bundle install to see if the engine installs without issue:

bundle install
Enter fullscreen mode Exit fullscreen mode

Overriding Erb Files

I want to add my my own stylesheet link that references an external stylesheet.

Opening lib/forem_custom_styles/engine.rb and update it with the following.

module ForemCustomStyles
  class Engine < ::Rails::Engine
    config.after_initialize do
      engine_views = ForemCustomStyles::Engine.root.join('app','views').to_s
      paths = ActionController::Base.view_paths.collect{|p| p.to_s}
      paths = paths.unshift engine_views
      ActionController::Base.view_paths = paths
    end
  end
end
Enter fullscreen mode Exit fullscreen mode


`

view_paths is an array of locations that the Rails application will look for when attempting to load erb files. So what we are doing is telling our application to always look at the view directory within our plugin.

So if we create any erb file with the same directory structure we can override the original application.

So I will create a app/views/layouts/_styles.html.erb in my plugin with the following content:


<%= stylesheet_link_tag "minimal", media: "all", id: "#{qualifier}-minimal-stylesheet" %>
<%= stylesheet_link_tag "views", media: "all", id: "#{qualifier}-views-stylesheet" %>
<%= stylesheet_link_tag "crayons", media: "all", id: "#{qualifier}-crayons-stylesheet" %>
<%= stylesheet_link_tag ENV['FOREM_CUSTOM_STYLES_OVERRIDE_URL'], media: "all", id: "forem-custom-styles-override-stylesheet" %>

So the last line is new code, where if I provide an a url to an css file for FOREM_CUSTOM_STYLES_OVERRIDE_URL in my .env file then it will load a css file that will override the styling.

Conclusion

So there you go, you can override nearly any erb file of your choosing.

You can either publish your gem, or you can include the gem within the forem codebase and create your image. Either way you'll be have to a custom image which will cover next.

Top comments (2)

Collapse
 
lee profile image
Lee

Ahh this makes sense, so when an eco system of plugins in the future comes online for things like video support and other stuff, this could be an approach to take. Interesting stuff!

Collapse
 
sidthedev profile image
Siddharth Chaudhary

Thanks so much for this