Question

I have seen two different approaches in saving user preferences.

APPROACH 1: Serializing them and saving in one of the column of USERS table

APPROACH 2: Creating a separate table PREFERENCES and make a has_many association from USERS to PREFERENCES.

Which one of the above two approaches would you prefer and what are the pros and cons of each over other?

Was it helpful?

Solution

It's usually a good idea to favor normalization. The second solution keeps your models cleaner, allows for easy extensibility if new preferences are added, and keeps your tables uncluttered.

OTHER TIPS

I grappled with this same question so I thought I'd share what I found in a "community wiki" answer.

Serializing in a single attribute

Simple user preferences for your Rails app is a blog post describing how to do this.

Edit a serialized hash in a form? describes how to edit such a hash in a form. A helpful trick is to make the form from OpenStruct.new(@user.preferences) hash to automatically make accessor methods for each hash attribute.

DYE/has_serialized - GitHub lets you treat those attributes in the serialized hash as attributes on the (user) model.

Preferences in a separate table

Best practice to store user settings? has some tips. Below are some libs including two from another answer by @hopeless.

  • rails-settings manages a table of key/value pairs like a Hash stored in you database, using simple ActiveRecord like methods for manipulation. You can store any kind of object: Strings, numbers, arrays, or any object which can be noted as YAML. (Tested with Rails 3.1 and newer including Rails 4.x and Rails 5.x)
  • Preference-fu is good for simple boolean preferences, uses a single column for multiple preferences.(last updated 2009)
  • Preferences is more flexible, uses a separate table, some nice syntactic sugar. (last updated 2011)
  • HasEasy stores the data in a vertical table, but allows you to add validations, pre/post storage processing, types, etc. (Last updated 2008)

You can also try using metaprogramming: Practical Metaprogramming with Ruby: Storing Preferences

An improved version of the first approach can be had if you're on PostgreSQL 9.2/3+ and Rails 4+. You can use store_accessor to store preferences in a PostgreSQL hstore column with support for validations and querying.

class User
  store_accessor :preferences, :receive_newsletter

  validates :receive_newsletter, presence: true
end

user.receive_newsletter => 'true'

User.where("preferences->'receive_newsletter' = 'true'")

See http://mikecoutermarsh.com/using-hstore-with-rails-4/ for more details (migrations) and a special note on handling booleans.

Approach 2

You can add preferences, without cluttering up the user table

There are some Rails plugins to handle this usecase:

  • Preference-fu (good for simple boolean preferences, uses a single column for multiple preferences)
  • Preferences (more flexible, uses a separate table, some nice syntactic sugar)

I'd approach 2 because it is cleaner and easier to update. You will be able to add more preferences as complex as you want.

It will be a bit slower since you have a join to do, but it'll be worth it

In 2016, I would back Option 2.

Why?

User settings tend to become a core piece of every application. If they are retrieved on every request, you’re now making an extra query with each request. Using a separate table makes sense when you have to have individual columns for each setting. But since we’re using jsonb, that’s not an issue. It’s just a single column.

Read more

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top