Global settings held in database

My full stack app allows users to manage the sites settings, as an example, they can change the site title which is displayed in a header partial. This value is held in the database in a table called settings along with many other settings.

I don’t want to have to load this table and pass its values into every view every time I render a view, I want those settings to be loaded by default on every request.

I have tried using View globals like this

hooks.after.providersBooted(() => {
  const Env = use('Env')
  const Setting = use('App/Models/Setting')
  const View = use('View')

  View.global('siteSettings', function async(setting) {
    var settings = await Setting.find(1)
    return settings[setting]
  })

  ...

but that just causes the site to crash, so I assume you can not use async code in view Globals.

An example of how i would use this, is that in any view where I wanted to access global site settings. I would use something like

{{siteSettings.logo_path}}

or

{{siteSettings.site_title}}

I seem to have found a solution, but don’t know if it’s OK to do this.

In a provider I have added this code to the boot method

 async boot() {
    const View = use('View')
    const Setting = use('App/Models/Setting')
    var values = await Setting.find(1)

    View.global("siteSettings", (setting) => {
      return values[setting]
    })
  }

As you can see there is a View.global registered, but my access to the database is done prior to the global being registered and stored in a local variable values.

It seems to work OK.

I noticed a slight problem with my solution above, the boot method only runs literally when the app first boots, so even when the user changes the site title in the database, the new database is not read again.

In my case the settings table only contains one record and about 10 columns, so I have fixed it by adding a setInterval() in my boot method. It runs every 5 seconds and checks for changes to the settings table, I also check the database before the setInterval just to pre populate the values variable.

Where there’s a will there’s a way

async boot() {
    console.log("Boot")
    const View = use('View')
    var Setting = use('App/Models/Setting')
    var values = await Setting.find(1)
    setInterval(async () => {
      console.log("Boot")
      values = await Setting.find(1)
    }, 5000)

    View.global("siteSettings", (setting) => {
      return values[setting]
    })
  }

This is the way to do it using middleware, see this post.