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
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
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
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
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
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
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
`
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)
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!
Thanks so much for this