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:
$ bundle
Run the installation script:
$ rails g user_preferences:install
This will copy across the migration and add an empty preference definition file in config/
Finally, run the database migrations:
$ rake db:migrate
Add 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 ...
end
This 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: false
You 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: false
Binary 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
- push
This 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: false
API
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') # => false
You can set multiple preferences at once:
user.preferences(:emails).set(notifications: 'instant', newsletter: true) # => true
get
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::Relation
Note: 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 test
Contributing
- 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