We've got a model User
, and we're adding in the ability for a user to share their actions on Facebook (and likely other social mediums later on). Obviously, not every user wants to do this, so we want to track their preferences on a per-action-type basis.
I figure there's four ways of handling this:
- Add a boolean column for every setting to the users table.
- Add a JSON hash column to the users table to store all preferences.
- Create a new model (
UserPreference
) and store each setting as a separate boolean column. - Create a new model (
UserPreference
) and perhaps have separate JSON hash columns per social medium (one for Facebook, one for Twitter, etc).
Whichever approach, it'd be really nice to have form objects for just preferences (and ones that handle situations where not all attributes/settings will be available - some users may only have Twitter connected, others only Facebook, etc).
I've currently gone with the second of the above options - a column called preferences
which can store each setting. I'm even tempted to have hashes within the hash, broken down by social medium.
# either
user.preferences #=> {'facebook_share_challenges' => true}
# or
user.preferences #=> {'facebook' => {'share_challenges' => true}}
I'm currently wondering if this is a good approach - maybe a column for each setting in a new model is better (option three) - works within normal conventions of Rails and Reform and other things. Hashes are certainly more flexible, but at what point does the mucking around to get things work become too much of a hassle?
I like the idea of one column for a hash. All you need to to is have an intermediate model
User::Preferences
that just maps all the declaredproperty
s to accessors. Soon, the Disposable gem can take care of this and is integrated into Reform.You then simply instantiate this object and pass it to Reform.
Does that help?
As noted, Reform will soon be able to do the decorating for you (slash Disposable). That's a cool example I could use in my book.
The good thing is this will be reusable in case you start using Roar/Representable for your HTTP APIs (which you wanna do because fun).