kadirahq / mantra

Mantra - An Application Architecture for Meteor
https://kadirahq.github.io/mantra/
978 stars 52 forks source link

Conditional redirect #153

Open uiii opened 8 years ago

uiii commented 8 years ago

Hi, in the spect is this:

If you need to redirect upon some condition (for example user is not authorized) use an action instead of route options like FlowRouter’s triggersEnter. Call the action from component or container’s composer function.

Why this? Can you explain it to me? In mantra-kickstarter, there is a redirect preformed directly in route's action, is it correct? I've read in flow-router doc, the route's actions are idempotent, so they are called only once, if I understand.

That's probably the reason why this approach is not working for me, the index route's action isn't called after redirect from logout action:

// routes.js
Router.route('/', {
    name: 'index',
    action() {
        if (! Meteor.userId()) {
            return Router.go('login');
        }

        mount(MainLayoutCtx, {
            content: () => ...
        });
    }
});

// actions/account.js
const actions = {
    logout: ({Meteor, Router}) => {
        Meteor.logout((error) => {
            if (error) {
                ...
            }

            Router.go('index');
        });
    }
};

I didn't try the triggerEnter approach. I don't know if it will work. The composer/component approach will be my next trial probably.

Thank you

makstr commented 8 years ago

We have tried this approach, it works for simple Meteor.userId() but fails if you are basing your redirect on more advanced logic with data attached toMeteor.user() such as profile or roles.

uiii commented 8 years ago

So my composer/component trial failed as well:

Warning: _renderNewRootComponent(): Render methods should be a pure function of props and state; triggering nested component updates from render is not allowed. If necessary, trigger nested updates in componentDidUpdate. Check the render method of Container(UserControls).

// components/layout.jsx
import UserControlsComponent from './user_controls_component.jsx';
import userComposer from '../composers/user.js';

const Layout = ({content = () => null}) => {
    const UserControlsContainer = userComposer(UserControlsComponent);

    return (
        <div>
            <header>
                <UserControlsContainer />
            </header>
            <main>
                {content()}
            </main>
        </div>
    );
};

// composers/user.js
export const composer = ({context}, onData) => {
    const {Meteor, Router} = context();

    const user = Meteor.user();

    if (! user) {
        Router.go('login');
    } else {
        onData(null, {user});
    }
};

// routes.jsx
import MainLayout from './components/layout.jsx';

export default function (injectDeps, {Router}) {
    const MainLayoutCtx = injectDeps(MainLayout);

    Router.route('/', {
        name: 'index',
        action() {
            mount(MainLayoutCtx, {
                content: () => ...
            });
        }
    });
}

The login route is from another module and using different layout.

It is not possible to perform redirect inside composer function?

EDIT: actually, the url has changed but the layout and components for index route are still rendered