David Freerksen

Software Engineer

I’ve been working with Spree for a while. I’ve made and helped build a lot of Spree extensions. Some of them open source, some of them private. People don’t seem to understand how to create new preferences. Or if they do, they don’t make posts about it. There are a couple ways to create custom, global preferences in Spree. Each has its own merit and drawback. The first way it to extend the existing Spree preferences. The second way is to create new preferences under a new namespace.

Solidus is the successor to Spree. For the time being, Solidus is still using the Spree namespace. It may change in the future, but custom preferences should still be created the same way in Solidus as they are in Spree.

If the preferences are for the benefit of only your extension, it’s better to create the new preferences under a new namespace. If the preferences are to benefit or create functionality to help Spree core or other extensions, create your preferences under the Spree namespace.

Start off by creating a new Spree extension.

$ spree extension your_engine

You can name your extension whatever you like. I am using your_engine as an example. When generating a spree extension, spree_ gets added as a prefix.

For the first option of creating custom preferences, let’s create the new preferences under the Spree namespace.

Here, we need to extend the existing app_configuration.rb model. In Spree, extending an existing model or controller requires you adding _decorator to the file name. Create a new file named app/models/spree/app_configuration_decorator.rb. Inside it, add the following

Spree::AppConfiguration.class_eval do
  preference :custom_foo, :string, default: "bar"
  preference :custom_count, :integer, default: 1
end

This is all that needs to be done. Access to the preferences can be done the same way as other Spree preferences:

# get
Spree::Config.custom_foo
Spree::Config[:custom_foo]
Spree::Config["custom_foo"]

# set
Spree::Config.custom_foo = "foo"
Spree::Config[:custom_foo] = "foo"
Spree::Config["custom_foo"] = "foo"

The second option for creating custom preferences has only one extra step. Using the SpreeYourEngine extension that we created earlier, start by creating a new file at app/models/spree/your_engine_setting.rb. Inside it, add the following

module Spree
  class YourEngineSetting < Preferences::Configuration
    preference :custom_foo, :string, default: "bar"
    preference :custom_count, :integer, default: 1
  end
end

We also need to initialize the preferences so they can be accessed. Inside lib/spree_your_engine/engine.rb add the following

initializer "your_engine.preferences", before: :load_config_initializers do
  YourEngine::Config = Spree::YourEngineSetting.new
end

Alternatively, you can initialize the preferences in the more traditional Rails way by creating config/initializers/your_engine_preferences.rb and adding the following

module Spree
  YourEngine::Config = Spree::YourEngineSetting.new
end

Access to the preferences is still similar to accessing Spree preferences:

# get
YourEngine::Config.custom_count
YourEngine::Config[:custom_count]
YourEngine::Config["custom_count"]

# set
YourEngine::Config.custom_count = 2
YourEngine::Config[:custom_count] = 3
YourEngine::Config["custom_count"] = 4

Updating custom preferences through a form submit is rather simple too. You can update one by one, or you can run the values through an each to update them. The following would work well

params.each do |name, value|
  next unless YourEngine::Config.has_preference? name

  YourEngine::Config[name] = value
end