title: What is best practice for app/user settings in Meteor.js?
body: <p>I've looked around quite a bit for Meteor examples showing how to implement app settings and user specific settings. The only thing I found was <a href="http://telesc.pe" rel="noreferrer">Telesc.pe</a>. And it uses a <code>Settings</code> collection. However, it only has a global (meaning same for everyone) app settings.</p>
  
  <p>Building on that example, I've created my own <code>settings</code> collections which is available on both the server and the client.</p>
  
  <pre><code>// Server and Client
  Settings = new Meteor.Collection('settings');
  </code></pre>
  
  <p>In each <code>Settings</code> record there is a <code>userId</code> field which is equal to 'Default' or the user's id.</p>
  
  <pre><code>{
    ...
    userId: 'Default' // &lt;-- 'Default' or Meteor.userId()
  }
  </code></pre>
  
  <p>I have my publish function publishing both the Default (app) settings AND the user's settings. (Side note: in this app everyone IS logged in, no guests allowed)</p>
  
  <pre><code>// Server
  Meteor.publish('settings', function() {
    return Settings.find({userId: {$in: [this.userId, 'default']}});
  });
  </code></pre>
  
  <p>The idea here is that the user will use the Default settings until they change a settings thereby reducing the number of records in the collection.</p>
  
  <p>I've also tried to abstract away a lot of the tedious stuff and create a few helpers to get and set settings for the user.</p>
  
  <pre><code>// Server and Client
  
  // get user specific settings, fallback to default settings
  // (not sure if this is the best way, but it works)
  settings = function() {
    return Settings.findOne({userId:Meteor.userId()}) 
        || Settings.findOne({userId:'default'});
  };
  
  // Get value of a specific setting
  getSetting = function(key) {
    return Session.get('settingsLoaded') ? settings()[key] : undefined;
  };
  
  // Set value of a specific setting
  setSetting = function(key, value) {
     // bunch of logic here to see if a user specific record exists
     // if so, do update
     // if not, do insert
  };
  </code></pre>
  
  <p>So far, this implementation seems to be working fairly well. I can set and get settings in the console via m helper functions.</p>
  
  <pre><code>// in the console...
  setSetting('foo', 'bar');
  getSetting('foo') // == 'bar'
  </code></pre>
  
  <p>The issue I'm having happens when I go to start making my app act differently based on certain settings. For example, I have a template called 'phrases' with a variable inside called 'phrases'. I want to change how they are sorted based on the user's settings.</p>
  
  <pre><code>Template.phrases.phrases = function () {
    var sort = {};
  
    var sortKey = getSetting('sortPhrasesBy'); // if I console.log this it is ALWAYS equal to 'title', 'body', or 'date', which is what I want.
    sort[sortKey] = 1;
  
    // returns cursor with all phrases, sorted
    return Phrases.find({}, {sort:sort});
  };
  </code></pre>
  
  <p>Except that I keep getting <code>Deps</code> exceptions and I can't tell what is wrong.</p>
  
  <pre><code>Exception from Deps recompute: TypeError: Cannot read property 'nodeName' of null
  at Patcher.match (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1540:12)
  at http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1364:23
  at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1320:11)
  at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1321:9)
  at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1321:9)
  at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1321:9)
  at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1321:9)
  at patch (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1334:3)
  at http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:698:7
  at LiveRange.operate (http://localhost:3000/packages/liverange.js?b3097d72d458e645fd4f0021c8ff5189abe8d98a:491:9)
  </code></pre>
  
  <p>I have no idea what could be causing this. :/</p>
  
  <p>However, this code actually works! It does actually sort the phrases based on what the user has set. But in the console I can see this exception being thrown every time the settings are changed. First load is fine.</p>
  
  <p>So, am I doing something fundamentally wrong here? I must admit I don't yet have my head fully wrapped around what Meteor is doing behind the curtain yet.</p>
  
  <p>I don't know if this is helpful or not. But before I tried implementing a settings collection, I used the <code>Session</code> object. So I had something like this:</p>
  
  <pre><code>// on client
  Session.setDefault('sortPhrasesBy', 'title);
  
  Template.phrases.phrases = function () {
    var sort = {};
  
    var sortKey = Session.get('sortPhrasesBy');
    sort[sortKey] = 1;
  
    // returns cursor with all phrases, sorted a certain way
    return Phrases.find({}, {sort:sort});
  };
  </code></pre>
  
  <p>This worked without issue. It's just not real flexible.</p>
  
  <p>Is there another way I should be doing this? I'd love to know what the guys building meteor are doing for settings in there personal testing/projects if anyone happens to know.</p>
  
  <p>Sorry so long of a post, I was trying to anticipate what questions might be asked about what I already tried and such.</p>
  
  <p>Thanks for any help you can provide!</p>