SSR and user management

#1

Hi everyone.

I am starting an app with SSR and I followed this great article :

Everything worked fine and easy until I reached accounts management. I’d like to know more about handling users Method from accounts-base which apparently are not rechable on server side.

I used to have client rendered apps and it was easy to manage but now I am struggling a lot. For example I like to give an isAdmin boolean to my users and publish it as userData. This boolean is compulsory to reach my /admin panel, and now the only way I found to make this work was this :

export class Admin extends React.Component {
  render () {
		if (Meteor.isClient){
				if(Meteor.user()) {
					if(Meteor.user().isAdmin){
						return (
							<div className="admin">
								Admin
							</div>
						)
					} else {
						return (<Redirect to="/" />)
					}
				} else if(this.props.loggingIn) {
					return null;
				} else {
					return (<Redirect to="/" />)
				}
    } else {
      return (<Redirect to="/" />)
		}
  }
}

export default withTracker(() => {
	if (Meteor.isClient){
		const loggingIn = Meteor.loggingIn()
		return { loggingIn }
	}
	return {}
})(Admin)

Seems very complicated to me, anyone has any idea how I could manage this better ?

#2

You can turn off ssr for admin pages.

#3

Any leads on where to find the doc about this, still very new to SSR. But thanks for the tip.

#4

Here is an example:

onPageLoad(async (sink) => {
  // try to disable server render for some pages
  const { url } = sink.request;
  const adminRegex = new RegExp('^/admin/');
  if (adminRegex.test(url.path)) {
    return;
  }
  // do the rest server render here
}
1 Like
#5

Ok thanks, will try that, though not yet sure or where to put it in relation to the StaticRouter on the server side.

Right now I have this:

onPageLoad((sink) => {
  const context = {};
  const store = createStore(mainReducer, { selectedIndex : 0}, applyMiddleware(thunk))

  const App = props => (
		<Provider store={store}>
			<StaticRouter location={props.location} context={context}>
				{routes}
			</StaticRouter>
		</Provider>
  );

  App.propTypes = {
    location: object.isRequired,
  };

	const preloadedState = store.getState();

  sink.renderIntoElementById('app', renderToString(<App location={sink.request.url} />));

  sink.appendToBody(`
    <script>
      window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
    </script>
  `);
});

Shall I return before I even reach the Router ?

#6

Yes. Try to return on very top of function.

#7

Thanks a lot, seems to work, code now is like that :
render () {

		if(!this.props.ready){
			return null
		}
		if (!this.props.user || !this.props.user.isAdmin){
			return (<Redirect to="/" />)
		}
		return (
			<div className="admin">
				<h1>Admin</h1>
				<AddCategory />
			</div>
		)
	}
}

export default withTracker(() => {
	let subUSerData = Meteor.subscribe('userData');
	const loggingIn = Meteor.loggingIn();
	const user = Meteor.user()
		return { loggingIn, ready: subUSerData.ready(), user }
})(Admin)

and added following lines right after onPageLoad on server side:

  if(['/login','/signup', '/admin'].indexOf(sink.request.url.pathname) > -1){
    return
  }