この記事はDockerをつかってVueとRailsの開発環境にユーザー認証機能を実装するの続編です。
一連の記事
- DockerをつかってVueとRailsの開発環境をつくる
- DockerをつかってVueとRailsの開発環境にユーザー認証機能を実装する
- DockerをつかったVueとRailsの環境にAPIを実装するこの記事!!
この記事の目指すところ
- 前回まで作ってきた環境に新しいAPIを追加する
- 今回はユーザーが出会ったことのある人を登録する機能を作ってみます
サーバー側
テーブルの作成
今回は前回までに作ったuserテーブルのIDに対し外部キーを設定します。
テーブルの構造はこんな感じ
テーブル名:acquaintance
カラム名 | オプション | 説明 |
---|---|---|
user_id | not null, foreign_key | UserテーブルのIDを参照する外部キー |
id | not null | ID |
name | 名前 | |
nickname | あだ名 |
早速コマンドを実行してテーブルを作成しましょう
rails g model acquaintance user:references name:string nickname:string
rails db:migrate
コントローラーの作成
テーブルができたので、コントローラーを作っていきましょう
rails g controller acquaintances
コントローラーが生成されたので、動作を書いていきましょう。
今回書く動作は以下のとおりです。
- create
- 知り合い情報を登録するAPI
- search
- 知り合いを探すAPI
class AcquaintancesController < ApplicationController
def create
@acquaintance = Acquaintance.new(user_id: params[:user_id], name: params[:name], nickname: params[:nickname])
if @acquaintance.save
render json: @acquaintance
else
render json: { errors: @acquaintance.errors.full_messages }, status: 400
end
end
def search
@acquaintance = Acquaintance.where(user_id: params[:user_id]).where(name: params[:name]).or(Acquaintance.where(user_id: params[:user_id]).where(nickname: params[:nickname]))
if @acquaintance != []
render json: @acquaintance
else
render json: { errors: ['ユーザーが見つかりません'] }, status: 404
end
end
end
ルーティング情報の設定変更
コントローラーで動作をかいたので、これを使えるようにルーティング情報を記入しましょう。
Rails.application.routes.draw do
resources :users, only: [ :create ] do
collection do
post 'sign_in'
get 'me'
end
end
post 'login/login'
get 'acquaintance/search' => 'acquaintances#search'
resources :acquaintances do
collection do
post 'create'
get 'index'
end
end
end
フロント側
検索画面を作る
Vueでログイン後の検索画面を作ります。
<template>
<div class="search">
<table>
<tr>
<td>
<el-input
placeholder="名前か、あだ名で検索"
v-model="searchtext"
clearable>
</el-input>
</td>
<td>
<el-button type="primary" icon="el-icon-search" @click="send">検索</el-button>
</td>
<td>
<router-link to="/new_acquaintance">
<el-button type="warning"><i class="el-icon-plus">登録</i></el-button>
</router-link>
</td>
</tr>
</table>
<el-table
:data="acqdata"
stripe
@row-click="user"
style="width: 100%">
<el-table-column
prop="name"
label="名前"
width="180">
</el-table-column>
<el-table-column
prop="nickname"
label="あだ名"
width="180">
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'search',
data () {
return {
searchtext: '',
acqdata: {
name: '',
nickname: ''
}
}
},
components: {
},
mounted () {
this.axios.get('http://0.0.0.0:3000/acquaintances/', {
params: {
user_id: this.$store.state.userinfo.id
},
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + this.$store.state.userinfo.token
}
})
.then((response) => {
this.acqdata = response.data
})
.catch((e) => {
console.log(e)
this.$message.error('情報取得に失敗しました!' + e)
})
},
methods: {
user (val) {
this.$store.dispatch('doRegistrationAcqUser', val)
this.$router.push('/acquaintanceInfo')
},
send () {
this.axios.get('http://0.0.0.0:3000/acquaintance/search', {
params: {
user_id: this.$store.state.userinfo.id,
name: this.searchtext,
nickname: this.searchtext
},
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + this.$store.state.userinfo.token
}
})
.then((response) => {
this.acqdata = response.data
})
.catch((e) => {
console.log(e)
this.$confirm('新しく登録しますか?', 'ユーザーが見つかりませんでした。', {
confirmButtonText: 'OK',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
this.$router.push('new_acquaintance')
}).catch(() => {
})
})
}
}
}
</script>
<style scoped>
.search{
width: 70%;
margin: 3vh auto;
}
table{
width: 100%;
}
</style>
前回からStateの情報も少し変えているので、その修正点も変更していきます。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
userinfo: ''
},
mutations: {
RegistrationToken (state, payload) {
state.userinfo = payload.userinfo
},
},
actions: {
doRegistrationToken ({ commit }, userinfo) {
commit('RegistrationToken', { userinfo })
}
},
modules: {
}
})
知り合いの登録画面の作成
知り合いの登録画面を作成します。
<template>
<div class="new_acquaintance">
<h1>知り合い登録</h1>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="120px" class="demo-ruleForm">
<el-form-item label="氏名" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="あだ名" prop="nickname">
<el-input v-model="ruleForm.nickname"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">Create</el-button>
<el-button @click="resetForm('ruleForm')">Reset</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'new_acquaintance',
data () {
return {
ruleForm: {
user_id: this.$store.state.userinfo.id,
name: '',
nickname: ''
},
rules: {
name: [
{ required: true, message: '名前を入力してください', trigger: 'blur' },
{ min: 1, max: 20, message: '1文字から20文字で入力してください', trigger: 'blur' }
]
}
}
},
components: {
},
methods: {
submitForm (formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.axios.post('http://0.0.0.0:3000/acquaintances/', {
user_id: this.ruleForm.user_id,
name: this.ruleForm.name,
nickname: this.ruleForm.nickname
},
{
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + this.$store.state.userinfo.token
}
})
.then((response) => {
this.$notify({
title: 'Success',
message: '登録にに成功しました!',
type: 'success'
})
})
.catch((e) => {
this.$message.error('登録に失敗しました!' + e)
})
} else {
console.log('error submit!!')
return false
}
})
},
resetForm (formName) {
this.$refs[formName].resetFields()
}
}
}
</script>
<style scoped>
</style>
ルーティング情報の修正
ここまで作ったviewのルーティング情報を追記していきます。
また、ログインしていない場合、Homeにリダイレクトされる処理も書き加えています。
import Vue from 'vue'
import VueRouter from 'vue-router'
import Store from '@/store/index.js'
import Home from '../views/Home.vue'
import Login from '../views/login.vue'
import Signup from '../views/signup.vue'
import Search from '../views/search.vue'
import Newacquaintance from '../views/new_acquaintance.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
meta: {
isPublic: true
},
component: Home
},
{
path: '/login',
name: 'login',
meta: {
isPublic: true
},
component: Login
},
{
path: '/signup',
name: 'signup',
meta: {
isPublic: true
},
component: Signup
},
{
path: '/search',
name: 'search',
component: Search
},
{
path: '/new_acquaintance',
name: 'new_acquaintance',
component: Newacquaintance
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
if (to.matched.some(page => page.meta.isPublic) || Store.state.userinfo.token) {
next()
} else {
next('/')
}
})
export default router
確認
ログイン後のSearch.vueの画面はこんな感じになると思います。
あだ名か、名前を入力するとどちらかが一致するものが帰ってくる感じです。
新規追加画面の様子です。
おわりに
今回はログイン後にAPIをつかいデータの登録と取得の操作をしました。
次回は、これに紐づけたテーブルをもう一つ作り知り合いとの経歴を保存できるようにしていきます。