UserPreferences
An ActiveRecord backed user preference library that supports:
- Categories (currently non-optional)
- Binary and non-binary preferences
- Default values
- Value validation
- Retrieving users scoped by a particular preference
Installation
Add this line to your application's Gemfile:
gem 'user_preferences'And then execute:
$ bundleRun the installation script:
$ rails g user_preferences:installThis will copy across the migration and add an empty preference definition file in config/
Finally, run the database migrations:
$ rake db:migrateAdd preferences to your model
Assuming you have a model called User, you can associate it with preferences as
follows:
class User < ActiveRecord::Base
has_preferences
# the rest of your code ...
endThis declaration takes no arguments, and simply sets up the correct associations along with making available the rest of the methods described in the API section below.
Defining preferences
Your preferences, along with their default values, are defined in config/user_preferences.yml. You define each of your
preferences within a category. This example definition for a binary preference implies that users receive emails notifications by default but not newsletters:
emails:
notifications: true
newsletters: falseYou can configure non-binary preferences. For example, if users could choose periodical notification digests, the configuration might look like this:
emails:
notifications:
default: instant
values:
- off
- instant
- daily
- weekly
newsletters: falseBinary preferences can be enhanced to support multiple values while maintaining backwards compatibility on the API side:
emails:
notifications:
default: true
acts_as_binary: true
values:
- false
- true
- email
- pushThis will support setting the preference using integers, booleans, and strings for the first 2 values.
You can add as many categories as you like:
emails:
notifications: true
newsletters: false
beta_features:
two_factor_authentication: false
the_big_red_button: falseAPI
set
Similar to ActiveRecord, setting a preference returns true or false depending on whether or not it was successfully persisted:
user.preferences(:emails).set(notifications: 'instant') # => true
user.preferences(:emails).set(notifications: 'some_typo') # => falseYou can set multiple preferences at once:
user.preferences(:emails).set(notifications: 'instant', newsletter: true) # => trueget
A single preference:
user.preferences(:emails).get(:notifications) # => 'instant'all
All preferences for a category:
user.preferences(:emails).all # => { notifications: 'instant', newsletter: true }reload
Reload the preferences from the database; since something else might have changed the user's state.
user.preferences(:emails).reload # => { notifications: 'instant', newsletter: true }Scoping users
newsletter_users = User.with_preference(:email, :newsletter, true) #=> an ActiveRecord::RelationNote: this will include users who have not overridden the default value if the value incidentally matches the default value.
Other useful stuff
Single preference definition
- Get your preference definition (as per your .yml) as a hash:
UserPreferences.definitions - Get the definition for a single preference:
preference = UserPreferences[:emails, :notifications]
preference.default # => 'instant'
preference.binary? # => false
preference.permitted_values # => ['off', 'instant', 'daily', 'weekly']- Retrieve the default preference state with
UserPreferences.defaults. You can also scope to a category:UserPreferences.defaults(:emails)
Testing
$ rake testContributing
- Fork it ( http://github.com/mubi/user_preferences/fork )
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create new Pull Request