Preferences
This guide covers how to manage and configure preferences within Spree. After reading it, you should be familiar with:
- How preferences are managed by Spree
- How to change the value of a preference from its default
- How to add a new preference to the Spree core
- How to create a new set of preferences for your custom extensions.
1 Overview
Spree Preferences support general application configuration and preferences per model instance. Spree comes with preferences for your store like site name and description. Additional preferences can be added by your application or included extensions.
Preferences for models can be added without modifying the database. All instances will use the default value unless a value has been set for a specific record. For example, you could add a preference to User for “e-mail notifications”. Users would have the ability to modify this value without adding a column to your database table.
Extensions may add to the Spree General Settings or create their own namespaced preferences.
The first several sections of this guide describe preferences in a very general way. If you’re just interested in making modifications to the existing preferences, you can skip ahead to the Configuring Spree Preferences section. If you would like a more in-depth understanding of the underlying concepts used by the preference system, please read on.
2 Motivation
Preferences for models within an application are very common. Although the rule of thumb is to keep the number of preferences available to a minimum, sometimes it’s necessary if you want users to have optional preferences like disabling e-mail notifications.
General Settings for an application like “site name” are also needed to customize your Spree store.
Both use cases are handled by the Spree Preferences. They are easy to define, provide quick cached reads, persist across restarts and do not require additional columns to be added to your models.
The system was heavily refactored in Spree 1.0 for performance.
3 General Settings
Spree comes with many application wide preferences. They are defined in core/app/models/spree/app_configuration.rb and made available to your code through Spree::Config, e.g., Spree::Config.site_name.
A limited set of the general settings are available in the admin interface (/admin/general_settings).
You can add additional preferences under the spree/app_configuration namespace or create your own subclass of Preferences::Configuration.
# These will be saved with key: spree/app_configuration/hot_salsa Spree::AppConfiguration.class_eval do preference :hot_salsa, :boolean preference :dark_chocolate, :default => true preference :color, :string preference :favorite_number preference :language, :string, :default => 'English' end # Spree::Config is an instance of Spree::AppConfiguration Spree::Config.hot_salsa = false # Create your own class # These will be saved with key: kona/store_configuration/hot_coffee Kona::StoreConfiguration < Preferences::Configuration preference :hot_coffee, :boolean preference :color, :string, :default => 'black' end KONA::STORE_CONFIG = Kona::StoreConfiguration.new puts KONA::STORE_CONFIG.hot_coffee
4 Models
4.1 Defining Preferences
You can define preferences for a model within the model itself:
class User < ActiveRecord::Base preference :hot_salsa, :boolean preference :dark_chocolate, :default => true preference :color, :string preference :favorite_number, :integer preference :language, :string, :default => 'English' end
In the above model, five preferences have been defined:
- hot_salsa
- dark_chocolate
- color
- favorite_number
- language
For each preference, a data type is provided. The types available are:
- boolean
- string
- password
- integer
- text
An optional default value may be defined.
5 Accessing preferences
Once preferences have been defined for a model, they can be accessed either using the shortcut methods that are generated for each preference or the generic methods that are not specific to a particular preference.
5.1 Shortcut methods
There are several shortcut methods that are generated. They are shown below.
Query methods:
user.prefers_hot_salsa? # => false user.prefers_dark_chocolate? # => false
Reader methods:
user.preferred_color # => nil user.preferred_language # => "English"
Writer methods:
user.prefers_hot_salsa = false # => false user.preferred_language = 'English' # => "English"
Check if a preference is available
user.has_preference? :hot_salsa
5.2 Generic methods
Each shortcut method is essentially a wrapper for the various generic methods shown below:
Query method:
user.prefers?(:hot_salsa) # => false user.prefers?(:dark_chocolate) # => false
Reader method:
user.preferred(:color) # => nil user.preferred(:language) # => "English" user.get_preference :color user.get_preference :language
Write method:
user.set_preference(:hot_salsa, false) # => false user.set_preference(:language, "English") # => "English"
5.3 Accessing all preferences
You can get a hash of all stored preferences by accessing the preferences helper:
user.preferences # => {"language"=>"English", "color"=>nil}
This hash will contain the value for every preference that has been defined for the model, whether that’s the default value or one that has been previously stored.
5.4 Type and Default
You can access the default value for a preference:
user.preferred_color_default # => 'blue'
Types are used to generate forms or display the preference. You can also get the type defined for preference:
user.preferred_color_type # => :string
6 Saving preferences
Preferences are saved immediately for models. They are keyed by the id of the model.
7 Configuring Spree Preferences
Up until now we’ve been discussing the general preference system that was adapted to Spree. This has given you a general idea of what types of preference features are theoretically supported. Now, let’s start to look specifically at how Spree is using these preferences for configuration.
7.1 Reading the Current Preferences
At the heart of Spree preferences lies the Spree::Config constant. This object provides general access to the configuration settings anywhere in the application.
These settings can be accessed from initializers, models, controllers, views, etc.
The Spree::Config constant returns an instance of Spree::AppConfiguration which is where the default values for all of the general Spree preferences are defined.
You can access these preferences directly in code. To see this in action, just fire up script/console and try the following.
>> Spree::Config.site_name => "Spree Demo Site" >> Spree::Config.default_locale => "en-US"
The above examples show the default configuration values for these preferences. The defaults themselves are coded within the Spree::AppConfiguration class.
class Spree::AppConfiguration < Configuration
#... snip ...
preference :site_name, :string, :default => 'Spree Demo Site'
#... snip ...
preference :default_locale, :string, :default => 'en-US'
#... snip ...
end
If you are using the default preferences without any modifications, then nothing will be stored in the database. If you set a value for the preference it will save it to spree_preferences. It will use a memory cached version to maintain performance.
7.2 Overriding the Default Preferences
The default Spree preferences in Spree::AppConfiguration can be changed using the set method of the Spree::Config module. For example to set the default locale for Spain we could do the following:
$ script/console >> Spree::Config.default_locale = "es" => nil >> Spree::Config.default_locale => "es"
Here we are changing a preference to something other then the default as specified in Spree::AppConfiguration. In this case the preference system will persist the new value in the spree_preferences table.
Console settings may be lost if the database is rebuilt. See the advice above about preservation of settings.
7.3 Configuration Through the Spree Initializer
During the Spree installation process an initializer file is created within your applications source code. The initializer is found under config/initializers/spree.rb:
Spree.config do |config|
# Example:
# Uncomment to override the default site name.
# config.site_name = "Spree Demo Site"
end
The Spree.config block acts as a shortcut to setting Spree::Config multiple times. If you have multiple default preferences you would like to override within your code you may override them here. Using the initializer for setting the defaults is a nice shortcut, and helps keep your preferences organized in a standard location.
For example if you would like to change the site name and default locale you can accomplish this by doing the following:
Spree.config do |config|
config.site_name = 'My Awesome Spree Site'
config.default_locale = 'es'
end
Initializing preferences available within the Admin will overwrite any changes that were made through the user interface when you restart.
7.4 Configuration Through the Admin Interface
The Spree admin interface has several different screens where various settings can be configured. For instance, the admin/general_settings URL in your Spree application can be used to configure the values for the site name and the site URL. This is basically equivalent to calling Spree::Config.set site_name => "Whatever", :site_url => "http://whatever.com") directly in your Ruby code.
8 Site-Wide Preferences
8.1 Defining Site-Wide Preferences
You can define preferences that are site wide and don’t apply to a specific instance of a model by creating a configuration file that inherits from Spree::Preferences::Configuration.
class Spree::MyApplicationConfiguration < Spree::Preferences::Configuration
preference :theme, :string, :default => 'Default'
preference :show_splash_page, :boolean
preference :number_of_articles, :integer
end
In the above configuration file, three preferences have been defined:
- theme
- show_splash_page
- number_of_articles
It is recommended to create the configuration file in the lib/ directory.
Extensions can also define site-wide preferences. For more information on using preferences like this with extensions, check out the Creating Extensions Guide.
8.2 Configuring Site-Wide Preferences
The recommended way to configure site wide preferences is through an initializer. Let’s take a look at configuring the preferences defined in the previous configuration example.
module Spree
Spree::MyApp::Config = Spree::MyApplicationConfiguration.new
end
Spree::MyApp::Config[:theme] = "blue_theme"
Spree::MyApp::Config[:show_spash_page] = true
Spree::MyApp::Config[:number_of_articles] = 5
The above example will configure the preferences we defined earlier. Take note of the second line. In order to set and get preferences using Spree::MyApp::Config, we must first instantiate the configuration object.
