Rails: Best practice to store user settings?
Asked Answered
E

5

27

I'm wondering what the best way is to store user settings? For a web 2.0 app I want users to be able to select certain settings. At the moment is it only when to receive email notifications.

The easiest way would be to just create a Model "Settings" and have a column for every setting and then have a 1-1 relationship with users.

But is there a pattern to solve this better? Is it maybe better to store the info in the user table itself? Or should I use a table with "settings_name" and "settings_value" to be completely open about the type of settings stored there (without having to run any migrations when adding options)?

What is your opinion?

Thanks

Entry answered 5/11, 2009 at 17:6 Comment(0)
C
7

We use the helpful plugin called HasEasy. It stores the data in a vertical table, but allows you to add validations, pre/post storage processing, types, etc.

Copt answered 5/11, 2009 at 17:17 Comment(3)
That sounds interesting, but the link you posted is dead. Also Google didn't help. Any hints on where to find the plugin?Entry
Ok, I have no clue why the link doesn't work the first time. You refresh the page after you get the page not found and it goes right to it.Copt
@tokland I was hoping maintained meant updated every week or so. It hasn't been updated in 4 years..Silvern
A
13

If you use PostgreSQL, the best solution is to use https://github.com/diogob/activerecord-postgres-hstore/. It's a simple, fast and reliable way to store hashes in the database. Since it's not just a serialised text field, you can search on it also, and you don't need to create a new table, as in HasEasy.

def User
  serialize :preferences, ActiveRecord::Coders::Hstore
end

user = User.create preferences: { theme: "navy" }
user.preferences['theme']
Affidavit answered 12/8, 2013 at 7:3 Comment(1)
You don't need a gem for it any longer on rails4! Check this how-toEllipticity
K
11

The "open" table approach makes it difficult to model with AR, since you have to worry about the types of the data (boolean, int, string, etc). I've always added prefs as columns on the users table, and then move them out to a user_preferences table if there are "too many" of them. It's simple, and it's easy to work with.

Koy answered 5/11, 2009 at 17:14 Comment(1)
this is how i'm modeling a current project, however, i wonder, how are you accessing the User preferences site-wide? I've been reading lots of posts about how it's bad to try to access the current user within a model, that all session data should be managed in the controller. in my case though I have models/views that depend on the current user. For instance, if Current-User is browsing over Cars, I always want to show the car tank size as either "Liters" or "Gallons" depending on current user settings. Is it really necessary to do this everytime I want to see @car.tank_size(current_user)?Ier
D
11

If the user settings are not meant to be findable (via a User.find_by_x_preference, e.g.) you could also store them in a serialized column as a hash. This is the use case described in the rails docs (http://www.railsbrain.com/api/rails-2.3.2/doc/index.html?a=M002334&name=serialize#), actually.

class User < ActiveRecord::Base
  serialize :preferences
end

u = User.new
u.preferences = {:favorite_color => "green", :favorite_book => "Moby Dick"}
Digitalize answered 5/11, 2009 at 20:5 Comment(4)
nice and clean but it's a "lookup + parse" instead of just "lookup". if you're using the settings frequently for app logic this could slow you down.Henriettehenriha
it would be cool if this can integrate well with form builderLeporide
The problem I've run into with this technique is that when you add a new preference i.e. :favorite_food => pizza there is no simple way to set default settings for all users, which there would be if there were a straightforward DB column.Consultation
@Consultation you could just make a method when loading the settings, to check if the new setting exists otherwise add it and save it. Not beautiful, but a way to do it.Emplace
C
7

We use the helpful plugin called HasEasy. It stores the data in a vertical table, but allows you to add validations, pre/post storage processing, types, etc.

Copt answered 5/11, 2009 at 17:17 Comment(3)
That sounds interesting, but the link you posted is dead. Also Google didn't help. Any hints on where to find the plugin?Entry
Ok, I have no clue why the link doesn't work the first time. You refresh the page after you get the page not found and it goes right to it.Copt
@tokland I was hoping maintained meant updated every week or so. It hasn't been updated in 4 years..Silvern
S
3

Rails 6 supports ActiveRecordStore that can be used to solve this problem. The gem that improves ActiveRecordStore, by adding type definition, is activerecord-typedstore.

Define attributes in your model:

class User < ApplicationRecord
  typed_store :settings do |s|
    s.boolean :public, default: false, null: false
    s.string :email
    s.datetime :publish_at
    s.integer :age, null: false
  end
end

And use can use it:

shop = Shop.new(email: '[email protected]')
shop.public?        # => false
shop.email          # => '[email protected]'
shop.published_at   # => nil
Spiraea answered 28/11, 2019 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.