ga-wdi-boston / team-project

Other
2 stars 39 forks source link

Creating controller for nested schema #377

Closed jingrid closed 7 years ago

jingrid commented 7 years ago

Hello

We're trying to create the controller for our nested schema, but we're having trouble referencing the right things.

Essentially, we have a schema/model for Blog, and we are trying to make Posts nested within Blog.

cpearce31 commented 7 years ago

Can you post what you have so far? Are you getting errors?

jingrid commented 7 years ago

We took the Blog controller and just changed it to make it work for Posts

'use strict'

const controller = require('lib/wiring/controller')
const models = require('app/models')
const Blog = models.blog

const authenticate = require('./concerns/authenticate')
const setUser = require('./concerns/set-current-user')
const setModel = require('./concerns/set-mongoose-model')

const index = (req, res, next) => {
  Blog.post.find()
    .then(posts => res.json({
      posts: posts.map((e) =>
        e.toJSON({ virtuals: true, user: req.user }))
    }))
    .catch(next)
}

const show = (req, res) => {
  res.json({
    blog: req.blog.toJSON({ virtuals: true, user: req.user })
  })
}

const create = (req, res, next) => {
  const post = Object.assign(req.body.blog.post, {
    _owner: req.blog._id
  })
  Blog.post.create(post)
    .then(post =>
      res.status(201)
        .json({
          post: post.toJSON({ virtuals: true, blog: req.blog })
        }))
    .catch(next)
}

const update = (req, res, next) => {
  delete req.body._owner  // disallow owner reassignment.
  req.blog.update(req.body.blog)
    .then(() => res.sendStatus(204))
    .catch(next)
}

const destroy = (req, res, next) => {
  req.blog.remove()
    .then(() => res.sendStatus(204))
    .catch(next)
}

module.exports = controller({
  index,
  show,
  create,
  update,
  destroy
}, { before: [
  { method: setUser, only: ['index', 'show'] },
  { method: authenticate, except: ['index', 'show'] },
  { method: setModel(Blog), only: ['show'] },
  { method: setModel(Blog, { forUser: true }), only: ['update', 'destroy'] }
] })

However, when we try to create a Post, we are getting a 500 error: "{"error":{"message":"Cannot read property 'post' of undefined","error":{}}}"

Our curl request is as follows:

!/bin/bash

API="http://localhost:4741" URL_PATH="/blogs"

curl "${API}${URL_PATH}/${ID}/posts" \ --include \ --request POST \ --header "Content-Type: application/json" \ --header "Authorization: Token token=${TOKEN}" \ --data '{ "post": { "title": "'"${TITLE}"'", "body": "'"${BODY}"'" } }'

echo

Our custom route is: .post('/blogs/:id/posts', 'posts#create')

cpearce31 commented 7 years ago

Cannot read property 'post' of undefined suggests that you have some code like thing.post, where thing is undefined. You should be able to confirm that's what's happening with some console.logs.

payne-chris-r commented 7 years ago

Refactored your code a lil bit by adding "``js" and "bash" around your curl script.

payne-chris-r commented 7 years ago

We took the Blog controller and just changed it to make it work for Posts

'use strict'

const controller = require('lib/wiring/controller')
const models = require('app/models')
const Blog = models.blog

const authenticate = require('./concerns/authenticate')
const setUser = require('./concerns/set-current-user')
const setModel = require('./concerns/set-mongoose-model')

const index = (req, res, next) => {
  Blog.post.find()
    .then(posts => res.json({
      posts: posts.map((e) =>
        e.toJSON({ virtuals: true, user: req.user }))
    }))
    .catch(next)
}

const show = (req, res) => {
  res.json({
    blog: req.blog.toJSON({ virtuals: true, user: req.user })
  })
}

const create = (req, res, next) => {
  const post = Object.assign(req.body.blog.post, {
    _owner: req.blog._id
  })
  Blog.post.create(post)
    .then(post =>
      res.status(201)
        .json({
          post: post.toJSON({ virtuals: true, blog: req.blog })
        }))
    .catch(next)
}

const update = (req, res, next) => {
  delete req.body._owner  // disallow owner reassignment.
  req.blog.update(req.body.blog)
    .then(() => res.sendStatus(204))
    .catch(next)
}

const destroy = (req, res, next) => {
  req.blog.remove()
    .then(() => res.sendStatus(204))
    .catch(next)
}

module.exports = controller({
  index,
  show,
  create,
  update,
  destroy
}, { before: [
  { method: setUser, only: ['index', 'show'] },
  { method: authenticate, except: ['index', 'show'] },
  { method: setModel(Blog), only: ['show'] },
  { method: setModel(Blog, { forUser: true }), only: ['update', 'destroy'] }
] })

However, when we try to create a Post, we are getting a 500 error: "{"error":{"message":"Cannot read property 'post' of undefined","error":{}}}"

Our curl request is as follows:

#!/bin/bash

API="http://localhost:4741"
URL_PATH="/blogs"

curl "${API}${URL_PATH}/${ID}/posts" \
  --include \
  --request POST \
  --header "Content-Type: application/json" \
  --header "Authorization: Token token=${TOKEN}" \
  --data '{
    "post": {
      "title": "'"${TITLE}"'",
      "body": "'"${BODY}"'"
    }
  }'

echo

Our custom route is:

.post('/blogs/:id/posts', 'posts#create')
payne-chris-r commented 7 years ago

See @cpearce31 's suggestion.

jordanallain commented 7 years ago

perhaps this line?

Blog.post.create(post)

can you see what Blog is at that point in your create action?

Fcarrion001 commented 7 years ago

I have figured out how to target the posts array in the blog object and I can access the data I want to push into it but my promise chain seems to be not returning data to be passed on and I cannot figure out why


const create = (req, res, next) => {
  // const post = Object.assign(req.body.post, {
  //   _owner: req.user._id
  // })
  console.log('this is req.params: ', req.params)
  console.log('this is Blog', Blog)
  return Blog.find(req.params.id)
  .then(blog => console.log('this is req.body.posts ', req.body))
  .then(blog => console.log('this is blog.posts ', blog[0].posts))
    .then(blog => blog[0].posts.push(req.body.posts)
      .then((blog) => blog.save())
      .then(() => res.sendStatus(204))
        .json({
          post: blog.toJSON({ virtuals: true, blog: req.blog })
        }))
    .catch(next)
}
Fcarrion001 commented 7 years ago

This is the error I am receiving ~/wdi/projects/Project-3-backend (blog) $ TOKEN=IJ27sSn03JI2OG2l2EBmMM/WK1ruhBuIBRonoh8poNo=--VTtumr8xDzNgrN/Ln91X98L3xysay5RWeij1bcxfSso= ID=5989bdac1e09c5de6ff8a525 TITLE=BLOG1 BODY=DSKJFLFJDSLKFJDLSKFJDLKJS sh scripts/posts/create-post.sh HTTP/1.1 500 Internal Server Error X-Powered-By: Express Access-Control-Allow-Origin: http://localhost:7165 Vary: Origin Content-Type: application/json; charset=utf-8 Content-Length: 72 ETag: W/"48-5HVhgdyPUn6SQhuWh0tFROztoWY" Date: Tue, 08 Aug 2017 14:44:13 GMT Connection: keep-alive

{"error":{"message":"Cannot read property '0' of undefined","error":{}}} ~/wdi/projects/Project-3-backend (blog) $

jordanallain commented 7 years ago

so likely somewhere in there that you have blog[0] it isn't what you think it is? have you logged the data getting passed into each .then?

Fcarrion001 commented 7 years ago

the chain stops after the first .then regardless of what I pass in as the first callback. If I console.log it as the first .then() it is what I am looking for

This is what I am console.logging and then what is being pushed

.then(blog => console.log('this is blog.posts ', blog[0].posts))
  .then(blog => console.log('this is req.body.posts ', req.body.posts))
    .then(blog => blog[0].posts.push(req.body.posts)

This is what the terminal feeds back

(node:57545) DeprecationWarning: open() is deprecated in mongoose >= 4.11.0, use openUri() instead, or set the useMongoClient option if using connect() or createConnection(). See http://mongoosejs.com/docs/connections.html#use-mongo-client Server listening on port 4741 this is req.params: { id: '5989bdac1e09c5de6ff8a525' } this is Blog function model(doc, fields, skipId) { if (!(this instanceof model)) { return new model(doc, fields, skipId); } Model.call(this, doc, fields, skipId); } this is blog.posts [] this is req.body.posts { title: 'BLOG1', body: 'DSKJFLFJDSLKFJDLSKFJDLKJS' } POST /blogs/5989bdac1e09c5de6ff8a525/posts 500 44.480 ms - 72

Fcarrion001 commented 7 years ago

Correction it makes it past both console.logs

Fcarrion001 commented 7 years ago

but as you can see I am targeting the array and the object that I want to be pushed to the array

Fcarrion001 commented 7 years ago

bump

jordanallain commented 7 years ago

it says req.body.posts is an object no? you can use .push on an object?

Fcarrion001 commented 7 years ago

Im pushing the object to the array Im calling .push on the array shouldn't that work?

Fcarrion001 commented 7 years ago

I think It might be a promise problem but I do not know what to do about it

jordanallain commented 7 years ago

so is the problem that the object isn't getting pushed into the array?

Fcarrion001 commented 7 years ago

Update

Console.logs where returning undefined and there was a syntax error that resulted in one big nested promise chain

cpearce31 commented 7 years ago

Were you able to sort out the nested promises once you discovered the syntax error?