Udemy - Nuxt JS with Laravel API - Building SSR Vue JS Apps 笔记15 Laravel Nuxt–Update and Delete

Topic Update

首先更新api.php添加一个route

批注 2020-05-16 115643

TopicController.php增加这个update方法。

update方法需要一个Request参数,直接用custom request 来处理,这样字段验证也方便。

执行:

php artisan make:request TopicUpdateRequest
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class TopicUpdateRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'title' => 'required|string|max:255',
        ];
    }
}

批注 2020-05-16 120207

Postman测试:

批注 2020-05-16 120430

批注 2020-05-16 120452

批注 2020-05-16 120526

或者raw方式:

批注 2020-05-16 120658

接下来实现:只有创建topic的用户才能更新topic,所以需要Policy

Topic Update Policy

执行:

php artisan make:policy TopicPolicy
<?php

namespace App\Policies;

use App\Topic;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class TopicPolicy
{
    use HandlesAuthorization;

    /**
     * Create a new policy instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    public function update(User $user, Topic $topic)
    {
        return $user->ownsTopic($topic);
    }

}


然后user模型 中新建这个ownsTopic方法。

批注 2020-05-16 121724

然后更新AuthServiceProvider.php,注册这个policy:

批注 2020-05-16 122437

然后更新TopicController.php:

批注 2020-05-16 122036

PostMan测试,如果没有权限:

批注 2020-05-16 122154

Topic Delete Policy

添加api.php中一个route处理delete

批注 2020-05-16 123229

TopicController中新建destroy方法:

批注 2020-05-16 123309

同样需要一个Policy方法验证当前用户是否有权限:

批注 2020-05-16 123349

Postman测试:

批注 2020-05-16 123428

Topic Update – Nuxt

首先需要在pages/topics/index.vue中添加一个 逻辑 只有属于登录用户的topic才能被该用户更新及删除。

由于判断是根据用户id来判断,之前后端返回的值没有id,所以添加之:

批注 2020-05-16 125756

pages/topics/index.vue

批注 2020-05-16 130038

效果:不属于本用户的Topic 看不到Edit

批注 2020-05-16 130113

新建pages/topics/edit/index.vue文件:

批注 2020-05-16 130555

更新pages/topics/index.vue

批注 2020-05-16 130637

这个nuxt-link to参数中name是自动generate的,可以看:

批注 2020-05-16 130749

稍微更新一下style

批注 2020-05-16 130914

在nuxt.config.js中:

批注 2020-05-16 131023

topics/index.vue:

批注 2020-05-16 131225

效果如下:

批注 2020-05-16 131257

Update Topic Title

pages/topics/edit/index.vue更新:

<template>
  <div class="container">
    <h2>Update Topic Title</h2>
    <form @submit.prevent="update">
      <div class="form-group mt-5">
        <input type="text" class="form-control" v-model="topic.title">
        <small class="form-text text-danger" v-if="errors.title">{{errors.title[0]}}</small>
      </div>

      <button class="btn btn-outline--success">Update</button>
    </form>
    <p class="mt-5 btn btn-outline-warning">
      <nuxt-link to="/topics">Back to Topics</nuxt-link>
    </p>
  </div>
</template>

<script>
  export default {
    name: "index",
    data() {
      return {
        topic: {
          title: '',
        }
      }
    },
    async asyncData({$axios, params}) {
      let {data} = await $axios.$get(`/topics/${params.id}`);
      return {
        topic: data,
      }
    },
    methods: {
      async update() {
        await this.$axios.patch(`/topics/${this.$route.params.id}`,
          {title: this.topic.title});
        //redirect
        this.$router.push('/topics');
      },
    }
  }
</script>

<style scoped>

</style>

更新优化一下:

把topics/edit文件夹及内部的index.vue迁移到topics/_id文件夹内:

批注 2020-05-16 134138

根据.nuxt/router.js中这个name

批注 2020-05-16 134202

更新topics/index.vue:

批注 2020-05-16 134300

效果:

批注 2020-05-16 134352

批注 2020-05-16 134415

这样url就带有id了;

Delete Topic

topics/index.vue更新:

<template>
  <div class="container">
    <h2>Latest Topics</h2>
    <div v-for="(topic,index) in topics" :key="index" class="bg-light mt-5 mb-5" style="padding: 20px">
      <nuxt-link :to="{name:'topics-id',params:{id:topic.id}}">{{topic.title}}</nuxt-link>
      <div v-if="authenticated">
        <div v-if="user.id===topic.user.id">
          <nuxt-link :to="{name:'topics-id-edit',params:{id:topic.id}}">
            <button class="btn btn-outline-success fa fa-edit fa-2x pull-right">Edit</button>
          </nuxt-link>
          <button class="btn btn-outline-danger fa fa-trash fa-2x pull-right"
                  @click.prevent="deleteTopic(topic.id)">
            Delete
          </button>
        </div>
      </div>
      <p class="text-muted">{{topic.created_at}} by {{topic.user.name}}</p>
      <div v-for="(content,index) in topic.posts" :key="index" class="ml-5 content">
        {{content.body}}
        <p class="text-muted">{{content.created_at}} by {{content.user.name}}</p>
      </div>
    </div>
    <nav>
      <ul class="pagination justify-content-center">
        <li v-for="(key,value) in links" class="page-item">
          <a @click.prevent="loadMore(key)" class="page-link">{{value}}</a>
        </li>
      </ul>
    </nav>
  </div>
</template>

<script>
  export default {
    name: "index.vue",
    data() {
      return {
        topics: [],
        links: [],
      }
    },
    async asyncData({$axios}) {
      let {data, links,} = await $axios.$get('/topics');
      return {
        topics: data,
        links,
      }
    },
    methods: {
      async loadMore(key) {
        if (key === null) {
          return;
        }
        let {data, links} = await this.$axios.$get(key);
        return this.topics = {...this.topics, ...data};
      },
      async deleteTopic(id) {

        await this.$axios.$delete(`/topics/${id}`);

        this.$router.push('/');
      }
    }
  }
</script>

<style scoped>
  .content {
    border-left: 10px solid white;
    padding: 0 10px 0 10px;
  }

  .btn-outline-danger, .btn-outline-success {
    border: none;
  }

</style>

测试:

批注 2020-05-16 135004

Add Post to Topic

backend中实现添加post的逻辑
api.php:

批注 2020-05-16 140427

创建PostController执行

php artisan make:controller PostController

创建一个PostCreateRequest来处理创建请求的验证,执行

php artisan make:request PostCreateRequest

PostCreateRequest.php:

批注 2020-05-16 140742

PostController.php:

批注 2020-05-16 140832

用Postman测试:

批注 2020-05-16 141244

批注 2020-05-16 141225

Update and Delete Post

api.php:

<?php

use \Illuminate\Support\Facades\Route;

Route::post('register', 'AuthController@register')->middleware('guest');
Route::post('login', 'AuthController@login')->middleware('guest');
Route::get('user', 'AuthController@user')->middleware('auth');
Route::post('logout', 'AuthController@logout')->middleware('auth');


Route::group(['prefix' => 'topics'], function () {
    Route::post('/', 'TopicController@store')->middleware('auth');
    Route::get('/', 'TopicController@index');
    Route::get('/{topic}', 'TopicController@show');
    Route::patch('/{topic}', 'TopicController@update')->middleware('auth');
    Route::delete('/{topic}', 'TopicController@destroy')->middleware('auth');


    //post group
    Route::group(['prefix' => '/{topic}/posts'], function () {
        Route::post('/', 'PostController@store')->middleware('auth');
        Route::patch('/{post}', 'PostController@update')->middleware('auth');
        Route::delete('/{post}', 'PostController@destroy')->middleware('auth');
    });

});



更新request使用custom request ,执行:

php artisan make:request PostUpdateRequest

PostUpdateRequest.php:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class PostUpdateRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'body' => 'required|string|max:2000',
        ];
    }
}

更新删除都添加Policy:

执行:

php artisan make:policy PostPolicy
<?php

namespace App\Policies;

use App\Post;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    /**
     * Create a new policy instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    public function update(User $user, Post $post)
    {
        return $user->ownsPost($post);
    }

    public function destroy(User $user, Post $post)
    {
        return $user->ownsPost($post);
    }
}

AuthServiceProvider中注册PostPolicy:

批注 2020-05-16 142544

在User.php用户模型中添加一个ownsPost方法:

批注 2020-05-16 142312

PostController.php:

<?php

namespace App\Http\Controllers;

use App\Http\Requests\PostCreateRequest;
use App\Http\Requests\PostUpdateRequest;
use App\Http\Resources\PostResource;
use App\Post;
use App\Topic;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function store(PostCreateRequest $request, Topic $topic)
    {
        $post = new Post;
        $post->body = $request->get('body');
        $post->user()->associate(auth()->user());

        $topic->posts()->save($post);

        return PostResource::make($post);
    }

    public function update(PostUpdateRequest $request, Topic $topic, Post $post)
    {

        $this->authorize('update', $post);

        $post->body = $request->get('body');
        $post->save();
        return PostResource::make($post);
    }

    public function destroy(Request $request, Topic $topic, Post $post)
    {
        $this->authorize('destroy', $post);

        $post->delete();

        return response(null, 204);
    }
}

PostMan测试:

批注 2020-05-16 142656

批注 2020-05-16 143045

如果未授权:

批注 2020-05-16 143354

Create Post


更新pages/topics/_id/index.vue:

<template>
  <div class="container">
    <div class="bg-light mt-5 mb-5" style="padding: 20px;">
      <h2>{{topic.title}}</h2>
      <p class="text-muted">{{topic.created_at}} by {{topic.user.name}}</p>
      <div v-for="(content,index) in topic.posts" :key="index" class="ml-5 content">
        {{content.body}}
        <p class="text-muted">{{content.created_at}} by {{content.user.name}}</p>
      </div>
    </div>
    <div class="mt-5 ml-5 mb-5" v-if="authenticated">
      <form @submit.prevent="create">
        <div class="form-group">
          <h4>Add a new Post</h4>
          <textarea class="form-control" placeholder="Write Something" v-model="body" autofocus rows="5"></textarea>
          <small class="form-text text-danger" v-if="errors.body">{{errors.body[0]}}</small>
        </div>
        <button class="btn btn-outline-success">Add Post</button>
      </form>
    </div>
  </div>
</template>

<script>
  export default {
    name: "index.vue",
    data() {
      return {
        topic: '',
        body: '',
      }
    },
    async asyncData({$axios, params}) {
      const {data} = await $axios.$get(`/topics/${params.id}`);
      return {
        topic: data,
      }
    },
    methods: {
      async create() {
        await this.$axios.post(`/topics/${this.$route.params.id}/posts`,
          {
            body: this.body,
          });
        //redirect
        this.$router.push(`/topics`);
      },
    }
  }
</script>

<style scoped>

</style>

效果:

批注 2020-05-16 144910

Update Post


新建pages/topics/_id/posts/_postid/edit/index.vue文件

批注 2020-05-16 151112

<template>
  <div class="container">
    <h2>Topic Posts Edit Page</h2>
  </div>
</template>

<script>
  export default {
    name: "index"
  }
</script>

<style scoped>

</style>

更新pages/topics/_id/index.vue文件:

<template>
  <div class="container">
    <div class="bg-light mt-5 mb-5" style="padding: 20px;">
      <h2>{{topic.title}}</h2>
      <p class="text-muted">{{topic.created_at}} by {{topic.user.name}}</p>
      <div v-for="(content,index) in topic.posts" :key="index" class="ml-5 content">
        <p>{{content.body}}</p>
        <div v-if="authenticated">
          <div v-if="user.id===content.user.id">
            <nuxt-link :to="{name:'topics-id-posts-postid-edit',params:{id:topic.id,postid:content.id}}">
              <button class="btn btn-outline-success fa fa-edit pull-right">Edit</button>
            </nuxt-link>
            <button class="btn btn-outline-danger fa fa-trash pull-right"
                    @click.prevent="deletePost(content.id)">
              Delete
            </button>
          </div>
        </div>
        <p class="text-muted">{{content.created_at}} by {{content.user.name}}</p>

      </div>
    </div>
    <div class="mt-5 ml-5 mb-5" v-if="authenticated">
      <form @submit.prevent="create">
        <div class="form-group">
          <h4>Add a new Post</h4>
          <textarea class="form-control" placeholder="Write Something" v-model="body" autofocus rows="5"></textarea>
          <small class="form-text text-danger" v-if="errors.body">{{errors.body[0]}}</small>
        </div>
        <button class="btn btn-outline-success">Add Post</button>
      </form>
    </div>
  </div>
</template>

<script>
  export default {
    name: "index.vue",
    data() {
      return {
        topic: '',
        body: '',
      }
    },
    async asyncData({$axios, params}) {
      const {data} = await $axios.$get(`/topics/${params.id}`);
      return {
        topic: data,
      }
    },
    methods: {
      async create() {
        await this.$axios.post(`/topics/${this.$route.params.id}/posts`,
          {
            body: this.body,
          });
        //redirect
        this.$router.push(`/topics`);
      },
      async deletePost(postId) {
        await this.$axios.delete(`/topics/${this.$route.params.id}/posts/${postId}`);
        //redirect
        this.$router.push('/topics');
      },
    }
  }
</script>

<style scoped>

</style>

Return Single Post

api.php添加:

批注 2020-05-16 151248

PostController.php:

批注 2020-05-16 151411

Postman测试:

批注 2020-05-16 151455

Update Single Post

更新pages/topics/_id/posts/_postid/edit/index.vue:


<template>
  <div class="container">
    <h2>Update Post</h2>
    <form @submit.prevent="update">
      <div class="form-group mt-5">
        <textarea class="form-control" v-model="post.body" rows="5"></textarea>
        <small class="form-text text-danger" v-if="errors.body">{{errors.body[0]}}</small>
      </div>

      <button class="btn btn-outline-success">Update</button>
    </form>
    <p class="mt-5 btn btn-outline-warning">
      <nuxt-link to="/topics">Back to Topics</nuxt-link>
    </p>
  </div>
</template>

<script>
  export default {
    name: "index",
    data() {
      return {
        post: {
          body: '',
        }
      }
    },
    async asyncData({$axios, params}) {
      let {data} = await $axios.$get(`/topics/${params.id}/posts/${params.postid}`);
      return {
        post: data,
      }
    },
    methods: {
      async update() {
        await this.$axios.patch(`/topics/${this.$route.params.id}/posts/${this.$route.params.postid}`,
          {body: this.post.body});
        //redirect
        this.$router.push('/topics');
      },
    }
  }
</script>

<style scoped>

</style>

效果:

批注 2020-05-16 152321

批注 2020-05-16 152405

源代码:

前端

https://github.com/dzkjz/laravel-backend-nuxt-frontend-frontpart

选择:

批注 2020-05-16 152751

后端:

https://github.com/dzkjz/laravel-backend-nuxt-frontend

选择:

批注 2020-05-16 153012

posted @ 2020-05-16 13:52  dzkjz  阅读(76)  评论(0编辑  收藏  举报