My first RubyMotion application is rapidly nearing completion. As it involves user preferences that have to be stored both locally and remotely, I was investigating the available Rails gems for user preferences and really didn’t like what was presently out there. I don’t really have time to maintain another gem, but maybe someone else has run into this problem and wants a quick and easy solution for creating user preferences. If so, then this code’s for you.
Setting Up Preferences
You need a preference model. It should look like this:
1 2 3 4 5 6 7 |
|
I used this migration to create it:
1 2 3 4 5 6 7 8 9 |
|
You might note that the value of all preferences, regardless of if they’re supposed to be Boolean or datetime, is a string. Keep this in mind when you have to query this field later. (That is, if you want to search for all preferences where the value is true, you’ll want to search for “1”. And similarly, doing user.preferences.first.true?
will always return true
, as any string value is true. So, coder beware!)
Using Them
Ideally, this is what we want the user model to look like.
1 2 3 4 5 6 7 8 9 |
|
Simple but straightforward: we include the module and then define each preference, with its name first and default value second. Ideally we don’t want to save default values to the database, since that would just make a lot of unnecessary records.
The Preferences Module
So let’s make that happen in that include Preferences
line! This is the real heart of the preferences engine.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
This is really pretty simple. Upon inclusion it tells the model that it’s a part of that it has_many :preferences
and sets up a class variable hash to store preferences and their defaults. When you declare preference :chime, true
it records that in the class variable, and then all instances will respond to either user.chime = true
or user.write_preference(:chime, true)
. You can read values with user.chime
or user.read_preference(:chime)
. If a value isn’t written in the database, it returns the default value instead.
This probably has a level or two of refactoring that could happen around it. Maybe when I have time I will turn it into a more sensible gem, but until then, if anyone needs quick and dirty preferences… here you go.