简体   繁体   English

Meteor.js中应用程序/用户设置的最佳做法是什么?

[英]What is best practice for app/user settings in Meteor.js?

I've looked around quite a bit for Meteor examples showing how to implement app settings and user specific settings. 我已经看了很多关于Meteor的例子,展示了如何实现应用程序设置和用户特定设置。 The only thing I found was Telesc.pe . 我发现的唯一一件事就是Telesc.pe And it uses a Settings collection. 它使用一个Settings集合。 However, it only has a global (meaning same for everyone) app settings. 但是,它只有一个全局(对每个人来说都是一样的)app设置。

Building on that example, I've created my own settings collections which is available on both the server and the client. 基于该示例,我创建了自己的settings集合,可在服务器和客户端上使用。

// Server and Client
Settings = new Meteor.Collection('settings');

In each Settings record there is a userId field which is equal to 'Default' or the user's id. 在每个Settings记录中都有一个userId字段,它等于'Default'或用户的id。

{
  ...
  userId: 'Default' // <-- 'Default' or Meteor.userId()
}

I have my publish function publishing both the Default (app) settings AND the user's settings. 我的发布功能发布了默认(app)设置和用户设置。 (Side note: in this app everyone IS logged in, no guests allowed) (旁注:在这个应用程序中,每个人都登录,不允许任何客人)

// Server
Meteor.publish('settings', function() {
  return Settings.find({userId: {$in: [this.userId, 'default']}});
});

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. 这里的想法是用户将使用默认设置,直到他们更改设置,从而减少集合中的记录数。

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. 我还试图抽象出很多繁琐的东西,并创建一些帮助来获取和设置用户的设置。

// 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
};

So far, this implementation seems to be working fairly well. 到目前为止,这种实现似乎运作良好。 I can set and get settings in the console via m helper functions. 我可以通过m辅助函数在控制台中设置和获取设置。

// in the console...
setSetting('foo', 'bar');
getSetting('foo') // == 'bar'

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'. 例如,我有一个名为'phrase'的模板,里面有一个名为'phrase'的变量。 I want to change how they are sorted based on the user's settings. 我想根据用户的设置更改它们的排序方式。

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});
};

Except that I keep getting Deps exceptions and I can't tell what is wrong. 除了我不断得到Deps例外,我不知道出了什么问题。

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)

I have no idea what could be causing this. 我不知道是什么原因引起的。 :/ :/

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. 第一次加载很好。

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. 我必须承认,我还没有把头完全缠绕在Meteor正在幕后做的事情上。

I don't know if this is helpful or not. 我不知道这是否有用。 But before I tried implementing a settings collection, I used the Session object. 但在我尝试实现设置集合之前,我使用了Session对象。 So I had something like this: 所以我有这样的事情:

// 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});
};

This worked without issue. 这没有问题。 It's just not real flexible. 这不是真正灵活的。

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. 如果有人知道的话,我很想知道那些建造流星的人正在做个人测试/项目的设置。

Sorry so long of a post, I was trying to anticipate what questions might be asked about what I already tried and such. 对不起这么长的帖子,我试图预测可能会询问我已经尝试过的问题等等。

Thanks for any help you can provide! 感谢您的任何帮助,您可以提供!

The Meteor Accounts system (ex. accounts-password) has the concept of user-specific settings built-in as the 'profile' field of the user object. Meteor Accounts系统(例如accounts-password)具有用户特定设置的概念,内置为用户对象的“profile”字段。 It is automatically published and is reactive as well (since Meteor.user() is reactive). 它会自动发布并且也是被动的(因为Meteor.user()是被动的)。

Here are the relevant docs: http://docs.meteor.com/#meteor_user 以下是相关文档: http//docs.meteor.com/#meteor_user

Regarding the "nodeName" error, it is hard to debug but generally when I get that error it is because I am trying to access part of the DOM in a template helper that doesn't actually exist. 关于“nodeName”错误,它很难调试,但通常当我得到该错误时,这是​​因为我试图访问实际上不存在的模板助手中的部分DOM。 I've also seen it when I accidentally had two DOM elements with the same ID (fairly easy to do with sub-templates). 当我意外地有两个具有相同ID的DOM元素时(我很容易使用子模板),我也看到了它。

To track it down I remove code until it stops happening then add it back piece-by-piece until I find the root cause. 为了追踪它,我删除代码,直到它停止发生,然后逐个添加它,直到我找到根本原因。

The user-session smart package I wrote for Meteor is perfect for this use-case. 我为Meteor编写的用户会话智能包非常适合这种用例。

It's basically like Meteor's Session , but each variable is related to a user. 它基本上类似于Meteor的Session ,但每个变量都与用户有关。 It's reactive, and all the changes are persistent. 它是被动的,所有的变化都是持久的。 It's available on the client, and on the server with an additional userId argument. 它可以在客户端上使用,也可以在服务器上使用其他userId参数。

The error here looks like you have created a server side Meteor.publish() but not a corresponding Meteor.subscribe() in the client. 这里的错误看起来像是在客户端创建了服务器端Meteor.publish()而不是相应的Meteor.subscribe()。 You are returning an empty set and attempting to change properties on it. 您将返回一个空集并尝试更改其上的属性。 You can put the subscribe in a Deps.autorun block, or just include it directly in the helper, like so: 您可以将订阅放在Deps.autorun块中,或者直接将其包含在帮助程序中,如下所示:

Template.phrases.phrases = function () {
  var sort = {};
  Meteor.subscribe('settings');

  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});
};

You probably would want to use a package like iron-router, which has hooks to insure youactually have your subscription before the data is loaded. 您可能希望使用像铁路由器这样的软件包,它具有钩子以确保您在加载数据之前实际拥有订阅。 See Iron Router . 铁路由器

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM