[Solved] Help finding the mistake in my code - subscriptions are never ready


#1

I can’t understand what I’ve done that is incorrect. Perhaps it’s a typo, I’m not sure, but I’m trying server side rendering - which gets the collection fine - obviously.

But when it then switches over to client, the subscription is never ready. Here’s my code:

/imports/api/collections.js

export const Blog = new Mongo.Collection('blog');
...
export const Categories = new Mongo.Collection('categories');

/imports/api/blog/server/publications.js

import { Meteor } from 'meteor/meteor';
import { Blog } from '/imports/api/collections.js';

Meteor.publish('blog', () => {
  return Blog.find({
    fields: Blog.publicFields
  });
});

Then the same thing for categories. Next I render the contents using WithTracker .

/imports/ui/containers/AppContainer.js

import { Meteor } from 'meteor/meteor';
import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import { Blog , Categories } from '/imports/api/collections.js';

import App from '/imports/ui/App.js';

export default AppContainer = withTracker (() => {
  const blogHandle = Meteor.isClient ? Meteor.subscribe('blog') : {ready: () => true };
  const categoryHandle = Meteor.isClient ? Meteor.subscribe('categories') : {ready: () => true};
  const blogs = Blog.findOne();
  const categories = Categories.findOne();

  console.log(blogHandle.ready());

  return {
    blogs,
    categories,
  }

})(App);

I do that ternary operator because you can’t subscribe server side. Also on server side I force ready() to return true because then I can use the same code for rendering the component based on the subscription returning true.

However when we console.log - as soon as it is client side rendered, we get false every time. What do I have to do to make the collection ready?


#3

Shouldn’t we need query in the publish code?

Try changing this

Meteor.publish('blog', () => {
  return Blog.find({
    fields: Blog.publicFields
  });
});

to this

Meteor.publish('blog', () => {
  return Blog.find({},{
    fields: Blog.publicFields
  });
});

you were mentioning fields attribute without giving empty query


#4

Well, I’ve managed to solve it but I’m not sure why. I also found a few errors in my code along the way. So let’s first discuss the major point.

Incorrect Location of Publication Files

I had my publications located in /imports/api/{collectionName}/server/publication.js. This was incorrect. Moving the publications to the /server/ directory allowed the publish to work.

Next, I had some errors in my code:

/server/publications/blog

import { Meteor } from 'meteor/meteor';
import { Blog } from '/imports/api/collections.js';

Meteor.publish('blog', () => {
  return Blog.find({}, {
    fields: Blog.publicFields
  });
});

Where as previously I was only sending the second object as a query, I now see I needed to send a first object (empty or not).

Finally, I needed to change my container a little bit. This could be simplified but the following works fine.

/imports/ui/containers/AppContainer.js

import { Meteor } from 'meteor/meteor';
import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import { Blog , Categories } from '/imports/api/collections.js';

import App from '/imports/ui/App.js';

export default AppContainer = withTracker (() => {
  if (Meteor.isClient) {
    const blogHandle = Meteor.subscribe('blog');
    const categoryHandle = Meteor.subscribe('categories');

    return {
      blog: Blog.findOne(),
      categories: Categories.find().fetch(),
      from: 'client',
    }
  }

  const blogs = Blog.findOne();
  const categories = Categories.find().fetch();

  const from = 'server';

  return {
    blog: blogs,
    categories,
    from,
  }

})(App);

#5

Yep, found that. But still, I had to move the code to the /server/ directory for it even to register as a publish event.


#6

I don’t think you needed to move the publications, but you needed to import them from the server startup file.

If you’re following the convention in the Meteor Guide, that would be in imports/startup/server.js


#7

Yo @coagmano - do you know off hand if there’s a way to force meteor to wait to switch over to client?