← Back to Upcase

Best Practice for Creating "Settings" Sections


(Javier Carballo) #1

Hello,

I wanted to hear opinions on a scenario where I have found myself a few times. Here is an example:

We have an app that has a Company, and the company has a settings page where they can change what notifications their employees get; what features are enabled, can employees use the Chat? can employees upload images, etc.

So what I have done is this, I created a CompanySettings model, which contains the serialized settings. To give it a bit of order, I have a column for Notification settings, features, etc.

Here is the model:
class CompanySettings < ActiveRecord::Base
belongs_to :company
serialize :point_rules, Hash
serialize :notification_rules, Hash

Notifications Rules

%w[daily_recap smile_create shout_mention].each do |key|
define_method(“notification_#{key}”) do
notification_rules && notification_rules[key]
end

define_method("notification_#{key}=") do |value|
  self.notification_rules = (notification_rules || {}).merge(key => value)
end

end

Point Rules

%w[goal_create task_mark_as_complete task_create].each do |key|
define_method(“point_rule_#{key}”) do
point_rules && point_rules[key]
end

define_method("point_rule_#{key}=") do |value|
  self.point_rules = (point_rules || {}).merge(key => value)
end

end

end

class Company < ActiveRecord::Base

default_scope includes(:settings)

belongs_to :user

has_many :activities
has_many :shouts
has_many :smile_images

has_one :settings, class_name: “CompanySettings”

Users

has_many :employments
has_many :members, through: :employments, class_name: “User”, source: :user
has_many :departments
has_many :teams
has_many :all_points, class_name: "Point"
has_many :roles

Actions

has_many :props
has_many :goals
has_many :smiles
has_many :events
has_many :answers
has_many :questions
has_many :feedbacks
has_many :suggestions
has_many :announcements

def activities_cache
@activities ||= activities
end

def points
@points ||= all_points
end

def employees
@employees ||= members
end

def name
@name ||= settings.name
end
end

What do you think are the practices for cases like this?


(Joel Quenneville) #2

Hi @javiercarballo,

I use meta-programming very sparingly in my code due to the higher cognitive overhead it entails for both my future self and other developers who will have to interact with this code. In this case, you could use a regular ActiveRecord model with attributes for each of the settings rather than serializing and using ‘magic’ methods. The result would be the same but the code would be much clearer.