If you need to send some data to your javascript files in Discourse and you don't want to do this the long way, winding way through views and parsing and other strange framework headaches, consider using the gon gem.
Here, I will show you a very simple way to set up gon for Discourse.
Step 1: Enable inline javascript in your Discourse site settings
Add 'unsafe-inline' (with single quotes) to your Discourse site settings for content security policy script src
. For example my Discourse site setting setup looks like this:
You must use the single quotes just like in the picture. This will permit inline javascript to be easily added.
Step 2: Add the gon gem in your plugin.rb
file
gem 'gon', '6.2.0'
require 'gon'
You are almost there. There is one more step required. The way I do this may not be the "best way" but it works for me.
Step 3: Add <%= include_gon %>
to layout/application.html.erb
The way I do this is by using Discourse pups in the container build process by adding this line in my container yaml files:
Modifying the container file below is not required as of version 0.1.6 because the plugin does this for us. See this post.
## Remember, this is YAML syntax - you can only have one block with a name
run:
- exec: echo "Beginning of custom commands"
- exec: sed -i '/<\/head>/c\<%= include_gon %>\n</head>' /var/www/discourse/app/views/layouts/application.html.erb
If you have done all of these three steps (and rebuilt your container), you can now write any ruby plugin code you wish and assign ruby values directly to a javascript variable which can be used in both Discourse theme components and in your plugin code including EmberJS code.
Discourse Example
plugin.rb
after_initialize do
if GlobalSetting.container_main.to_s.length > 1
Gon.global.container_main = GlobalSetting.container_main.dup
Gon.global.container_data = GlobalSetting.container_data.dup
end
end
In the above example, we read two custom site settings we set up in our container YAML file, like this:
env:
DISCOURSE_CONTAINER_MAIN: 'socket-only2'
DISCOURSE_CONTAINER_DATA: 'data'
and we read thse value and set a gon global variable in Ruby. The can be just about any Ruby variables, but a typical use case would be a variable from a Rails controller.
Gon.global.container_main
Gon.global.container_data
Now, we can use this the javascript variable just about anywhere we want in Discourse as:
gon.global.container_main
gon.global.container_data
Here is an example from the real world, in Discourse looking at the console:
Vanilla Rails Example
Here is a example from a Rails controller using Bootstrap and chart.js
gon.myRunLables = ["A", "B", "C", "C"]
gon.myRunValues = [
Run.where(grade: "A", season: @this_season).sum(:cwt),
Run.where(grade: "B", season: @this_season).sum(:cwt),
Run.where(grade: "C", season: @this_season).sum(:cwt),
Run.where(grade: "D", season: @this_season).sum(:cwt),
]
Now, these gon variables set in the Rails controller can be used directly in chart.js
, for example:
var myBarChart = new Chart(ctx, {
type: "bar",
data: {
labels: gon.myRunLables,
datasets: [
{
label: "Revenue",
backgroundColor: "rgba(0, 97, 242, 1)",
hoverBackgroundColor: "rgba(0, 97, 242, 0.9)",
borderColor: "#4e73df",
data: gon.myRunValues,
},
],
Summary
If you are looking for a very easy way to get your Rails variables into your javascripts, consider the gon gem. It works well and with a little bit of work, it can work well with Discourse.
Reference:
See Also: