nodejs peepcode tutorial - can't get it to work - javascript

I bought the latest nodejs peepcode tutorial and followed it, however I can't get past the initial step.
I'm getting frustrated after spending several hours to find out where I got an error since debugging nodejs is a riddle for me.
app structure looks like this:
example
|__public
|__views
|__assets
|__apps <- instead of routes
server.js
package.json
Here is my simple code:
server.js
/**
* Module dependencies.
*/
require('coffee-script');
var express = require('express');
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// routes
require('./apps/authentication/routes')(app);
app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
/apps/authentication/routes.coffee:
routes = (app) ->
app.get '/login', (req, res) ->
res.render "views/login",
title: 'Login'
stylesheet: 'login'
module.exports = routes
apps/authentication/views/login.jade template:
form(action='/sessions', method='post')
label
| Username
input(type='text', name='user')
label
| Password
input(type='password', name='password')
input(type='submit', name='Submit')
nothing fancy, i got a stylesheet file and login.css in public/stylesheet/login.css
instead of a login template from authentication/routes.coffe when browsing http://localhost:3000/
Cannot GET /
no any other error message from node either:
Express server listening on port 3000 in development mode
I can't figure out where the problem is and this is really frustrating.
Probably some dumb typo somewhere but I can't figure this out :(

You do not have a route configured for the root '/'. Navigating to http://localhost:3000/login should return your login view as specified by the route to the resource '/login'. You need to add something along the lines of:
app.get '/', (req, res) ->
#if not logged-in then send to /login else
res.render('/views/authenticated', 'Home', 'index')
For more details on routing see http://expressjs.com/guide.html#routing.

It looks like everything is working as intended. The problem is that you haven't defined a route that matches the request GET /. You've only defined a route matching GET /login in your routes.coffee; also, GET /anythinginyourpublicdir will work thanks to the express.static middleware.

Related

Express res.render is not rendering the page

I am trying to get an input from my main site. After the input is submitted the page should redirect to /view. It seems like it successfully redirects to /view (because console.log() is getting triggered, but res.render is not working. If i manually go to /view it is rendering the page.
Here is the code of my app.js file:
// load the things we need
var express = require('express');
var app = express();
let bodyParser = require("body-parser");
let article = '';
//Set the view engine to ejs
app.set('view engine', 'ejs');
app.use('/static', express.static('static'))
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
//Index page
app.get('/', function (req, res) {
res.render('index')
});
//Get the input from the form
app.post('/searcharticle', function (req, res) {
article = req.body.article;
res.redirect('/view')
return article;
});
//Page to output the input
app.get('/view', function (req, res) {
console.log(article)
res.render('view', {
article: article
})
})
app.listen(8080);
console.log('Server on 8080');
And here is my
folder structure
Thank you for your help!
use view engine first then set the directory where to use it.
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
and for static files use
app.use('/static',express.static(PATH.join(__dirname+'/static'));
You have to mention the layout
app.get('/', function (req, res) {
res.render('index',{layout:false})
});
supposed you have al your .ejs files in views folder try adding this line in your code:
const path = require('path'); //npm install -S path in your console to install path.
//Set the view engine to ejs
app.set('views', path.join(__dirname, 'views')); // add this one, change 'views' for your folder name if needed.
app.set('view engine', 'ejs');
app.use('/static', express.static('static'))
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
If you are running your server from a diff directory than static you need to add a relative path
app.use('/static', express.static(__dirname+'/static'))
I was just given the solution to a very similar problem by my wonderful tutor. The login form 'submit' was passed to jQuery on('click') and after authetication called a Res.Render of the results of an API call. The API call result set was log-abled, but the page never rendered, and there was no error.
He told me that jQuery acts as a 'shadow' DOM, and that the Res.Render was likewise taking place in that shadow DOM. I changed the login form to a form Post instead of the jQuery on Click.
That WORKED!
I worked on this for several days without ever thinking jQuery could cause that obstacle.
My way is to go back the version of ejs to 2.5.2, and that works. However, I don't know the reason why it cannot support the version 3..

node js routing with ejs res.render does not work, but res.send does

I am setting up the environment for a node js app.
But the views/ejs files are not being rendered. If i do:
app.get("/", function(req, res){
res.send('Something');
});
This works. But, if I do(having an index,ejs file):
app.get("/", function(req, res){
res.render(index);
});
It does not work, I get "index is not defined" on the cleint side in the web, but no error in the command line.
Here is the app.js:
var express = require("express");
var path = require("path");
var app = express();
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.static(path.join(__dirname, 'public')));
app.get("/", function(req, res){
res.send('Something');
});
app.get("/", function(req, res){
res.render(index);
});
const port = process.env.PORT || 3000
app.listen(port, function () {
console.log(`Express is running on port ${port}`)
})
IS there something wrong with the app.set parameters, or has something changed? I am following a tutorial which might be out dated, but checking the docs, I do not see an issue.
So, what is wrong here, is there a new way to do the routing with ejs? I know partials are gone now. Does this mean no ejs files at all anymore, and if so, how is it supposed to be done now? By rendering an html file?
Thanks
Well, I'm not a pro of express but here index is not defined because you write it like a variable. Try using something like this
res.render(path.resolve(__dirname + "/views/index"));

Route an entire folder and its content

I want to protect a folder and its content by redirecting the user back to index.
I've tried this, but it only works partially.
var express = require('express');
var path = require('path');
var http = require('http');
var app = express();
app.set('port', 8080);
app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, 'views')));
app.get('/', function(req, res) {
res.render('index.ejs');
});
app.get('/protected/*', function(req, res, next) {
res.redirect('/');
next();
});
//activating server
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
This routes, for example, "localhost:8080/protected" and "localhost:8080/protected/asdf", but not "localhost:8080/protected/otherPage.html".
In this case asdf is not an actual file, but otherPage.html is. So if the file is there it doesn't redirect, but if it is not then it redirects. Why is this?
Your line dealing with static files app.use(express.static(path.join(__dirname, 'views'))); appears before app.get('/protected') so its being matched first.
If you moved the static handler to later in the code this would work as you require.
However, I would recommend splitting the static items into a separate folder to guard against accidentally revealing any server-side code you might be including in ejs files in the views folder.

Default route in Express.js

I'm writing an application with node.js and express.
I have setup a default route as this :
app.get('/', function(req, res){
res.sendfile('./views/index.html');
});
This works fine when I goto /localhost:port/
But in the URL when I type anything after that, /localhost:port/blah I get 404 ERROR which makes sense.
I want to setup a default route so that no matter what I type in the URL after localhost:port/ it should all get back the same html file.
I tried changing / to * :
app.get('*', function(req, res){
res.sendfile('./views/index.html');
});
but after I do this I start getting this error in the console and nothing shows up:
Uncaught SyntaxError: Unexpected token <
in all of my Javascript files: :3000/scripts/myscript.js:1
somehow my javascript file show the content of HTML
===EDIT====
I used this and it worked fine for first level urls: like loclhost:port/blah
app.use(function(req, res){
res.sendfile('./views/index.html');
});
but when the URLs are multilevel, I see the same problem as described earlier localhost:port/blah/foo
The problem here is that router is looking for public directory under /blah folder for all the javascript and CSS files in this case, which does not exist. And it's returning the default HTML file. How do I fix this?
==================EDIT POSTING THE WHOLE CODE =========================================
var http = require('http');
var express = require('express');
var api = require('./routes/api');
var mongoose = require('mongoose');
var app = express();
mongoose.connect('mongodb://localhost/mydb');
app.set('port', process.env.PORT || 3000);
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.get('/api/user/:userid', api.getUserInfo);
app.get('/', function(req, res){
res.sendfile('./views/index.html');
});
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
In addition to this, I have an HTML with a myscript linked in it,
<script type="text/javascript" src="./scripts/myscript.js" ></script>
Add this route at the after of all your previous routes
app.get('*',function (req, res) {
res.redirect('/');
});
This will redirect any route not handled to the index "/"
As stated here, you can add this middleware just after your routing logic:
app.use(function(req, res){
res.send(404);
});
You might find this answer also useful.
Of course, you need to adapt the res.send() part to meet your needs.
With the newer version of express I would suggest using res.sendStatus as res.send has been deprecated.
Express v3
app.use(function(req, res){
res.send(404);
});
Express v4
app.use(function(req, res){
res.sendStatus(404);
});

How do you avoid a crash if someone tries to access a page without loging in?

Hey so when I try to go to a page that cannot be accessed without logging in, the app crashes. How do I avoid this? The reason why it crashes is because when they try to access that page, the page tries to load data that is undefined.
The error is
TypeError: Cannot read property 'firstName' of null.
This loads up after I try to access a UserProfile page.
I am not sure where to put that a person cannot access any other pages but the home, login, register page basically unless they are logged in already?
app.js file:
var express = require('express')
, app = express()
, dbUserModel = require('./models/user')
, db = require('./db')
, pass = require('./config/passport')
, passport = require('passport')
, routes = require('./routes/index')
, user = require('./routes/user')
, path = require('path')
, http = require('http')
, connect = require('connect')
, mongoose = require('mongoose')
, mongoConnect = mongoose.connect('mongodb://localhost/test5');
// all environments
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.cookieParser('sabkdasdkjhakhfkahf7232ujdijaw9jok&^&^#88'));
//app.use(express.cookieSession());
app.use(express.methodOverride());
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
app.get('/', routes.index);
app.get('/register', user.register);
app.post('/register', user.registerPost);
app.get('/login', user.login);
app.post('/login', user.loginPost);
app.get('/userProfile', user.userProfile);
//app.get('/contacts', user.contacts);
app.get('/editUserProfile', user.editUserProfile);
app.post('/editUserProfile', user.editUserProfilePost);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
console.log('Users: ' + db.collections.users);
});
The straightforward way would be to add a middleware to all routes where a user has to be logged in. In that middleware you decide what to do if the user is not logged in. Depending on the kind of page, you could render a general page or redirect to the login page.
The middleware, let's call it user.mustBeLoggedIn, would look something like this:
exports.mustBeLoggedIn = function (req, res, next) {
// Assuming passport always sets req.user when logged in
if(!req.user) {
// You could add a redirect query param if you want to be nice and redirect
// the user back to this page
res.writeHead(302, { 'Location': '/login' });
return res.end();
}
// If the user is logged in just let the next middleware in the middleware chain handle the request
next();
};
Then where declaring the routes you would ad that middleware before any route that requires the user to be logged in:
app.get('/login', user.login);
app.post('/login', user.loginPost);
app.get('/userProfile', user.mustBeLoggedIn, user.userProfile);
If you also put all routes that requires being logged in under a directory you could further simplify the code by putting the middleware in a single rule for eg all /user/*:
app.get('/user/*', user.mustBeLoggedIn);
app.get('/user/profile', user.userProfile);
app.get('/user/editProfile', user.editUserProfile);
app.get('/user/etc', user.etc);
This technique can be further enhanced to for example require different user levels, but that's outside the scope of this answer.

Categories