Open aokabin opened 4 years ago
$ npx create-nuxt-app frontend
create-nuxt-app v2.12.0
✨ Generating Nuxt.js project in frontend
? Project name frontend
? Project description My excellent Nuxt.js project
? Author name aokabin
? Choose the package manager Yarn
? Choose UI framework Buefy
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support, DotEnv
? Choose linting tools ESLint, Prettier, Lint staged files, StyleLint
? Choose test framework Jest
? Choose rendering mode Single Page App
? Choose development tools jsconfig.json (Recommended for VS Code)
こんな感じの設定で作った
yarn run v1.16.0
$ eslint --ext .js,.vue --ignore-path .gitignore . --fix
✨ Done in 2.65s.
🎉 Successfully created project frontend
To get started:
cd frontend
yarn dev
To build & start for production:
cd frontend
yarn build
yarn start
To test:
cd frontend
yarn test
とのこと
$ yarn dev
で、3000番アクセスするも、loadingが無限に出続けるな...
? Project name test1
? Project description My marvelous Nuxt.js project
? Author name aokabin
? Choose the package manager Yarn
? Choose UI framework Buefy
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules Axios, DotEnv
? Choose linting tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Choose test framework Jest
? Choose rendering mode Universal (SSR)
? Choose development tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
これは通ったな、、、lintingか?
create-nuxt-app v2.12.0
✨ Generating Nuxt.js project in test1
? Project name test1
? Project description My spectacular Nuxt.js project
? Author name aokabin
? Choose the package manager Yarn
? Choose UI framework Buefy
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support, DotEnv
? Choose linting tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Choose test framework Jest
? Choose rendering mode Universal (SSR)
? Choose development tools jsconfig.json (Recommended for VS Code)
linting以外fullにしても通った
ESLint, Prettierだけ入れてみた
これも通った
create-nuxt-app v2.12.0
✨ Generating Nuxt.js project in test1
? Project name test1
? Project description My premium Nuxt.js project
? Author name aokabin
? Choose the package manager Yarn
? Choose UI framework Buefy
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support, DotEnv
? Choose linting tools ESLint, Prettier, Lint staged files
? Choose test framework Jest
? Choose rendering mode Universal (SSR)
? Choose development tools jsconfig.json (Recommended for VS Code)
Lint staged filesも入れた
create-nuxt-app v2.12.0
✨ Generating Nuxt.js project in test1
? Project name test1
? Project description My premium Nuxt.js project
? Author name aokabin
? Choose the package manager Yarn
? Choose UI framework Buefy
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support, DotEnv
? Choose linting tools ESLint, Prettier, Lint staged files
? Choose test framework Jest
? Choose rendering mode Universal (SSR)
? Choose development tools jsconfig.json (Recommended for VS Code)
ここまで通った
✨ Generating Nuxt.js project in frontend
? Project name frontend
? Project description My majestic Nuxt.js project
? Author name aokabin
? Choose the package manager Yarn
? Choose UI framework Buefy
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support, DotEnv
? Choose linting tools ESLint, Prettier, Lint staged files
? Choose test framework Jest
? Choose rendering mode Universal (SSR)
? Choose development tools jsconfig.json (Recommended for VS Code)
こんな感じで、StyleLint以外を入れた
これで起動するようになったので、色々やっていきたい気持ち
だけど、ログインセッション欲しいが、今の所そんな仕組みないもんなぁ
一旦、railsのプロキシとしてnuxtを扱ってみる?
nuxtからのリクエストをノー認証で通すというパターン これはcsrfを使わないようにすればできそう
まずは、nuxtからバックエンドに適当にリクエストを飛ばしたい こんな感じの環境変数を設定 BACKENDがrailsになる予定
BASE_URL=http://localhost:3000
BACKEND_URL=http://localhost:3001
/login
にアクセスしたら、適当なフォームを表示して、railsにアクセスするようにしてみよう
pages/login.vue
を作った
ここに何書けばいいかは思いついてないなぁ とりあえずh1書いてみるか
<template>
<h1>Hello</h1>
</template>
<script>
export default {
name: 'Login'
}
</script>
あ、なんかちっちゃくhelloって表示されたw
じゃあなんかフォーム作って、この中にidとpwを入れて、送信押したら、railsに問い合わせるようにしてみよう
ログイン、 @submit
みたいな記述、何だろう
へー、バリデーションとかが挟めるんだ、そしてvueの機能か
んー、一旦vueが持つ範囲を知っていた方が、それぞれがどの部分を持っているのか、とかがイメージつかなそうだな
input v-modelでいけそう
<template>
<div class="login-form">
<p>{{ email }}</p>
<input v-model="email" />
</div>
</template>
<script>
export default {
data() {
return {
error: null,
email: '',
password: ''
}
}
}
</script>
お、いい感じ
<template>
<div class="login-form">
<p>{{ email }}</p>
<input v-model="email" />
<p>{{ password }}</p>
<input v-model="password" />
</div>
</template>
<script>
export default {
data() {
return {
error: null,
email: '',
password: ''
}
}
}
</script>
password、隠したいな
普通にtype指定するだけだった、便利だなぁ
<template>
<div class="login-form">
<p>{{ email }}</p>
<input type="email" v-model="email" />
<p>{{ password }}</p>
<input type="password" v-model="password" />
</div>
</template>
<script>
export default {
data() {
return {
error: null,
email: '',
password: ''
}
}
}
</script>
あれー、どうやってmethodsの中でdataの中身読むんだっけ...
<template>
<div class="login-form">
<p>{{ email }}</p>
<input v-model="email" type="email" />
<p>{{ password }}</p>
<input v-model="password" type="password" />
<button v-on:click="login">Login</button>
</div>
</template>
<script>
export default {
data() {
return {
error: null,
email: '',
password: ''
}
},
methods: {
login() {
alert(this.email)
}
}
}
</script>
いけたいけた
何となく
みたいなのが良さげだったので、それを参考に...
lib/backend-client.js を作ってみた
import axios from 'axios'
export const request = (method, url, body) => {
method = method.toLowerCase()
let queryUrl = url
return axios[method](url, body)
}
export const Login = function(parameters = {}) {
const domain = 'http://localhost:3001'
let path = '/login'
let body
if (parameters['body'] !== undefined) {
body = parameters['body']
}
if (parameters['body'] === undefined) {
return Promise.reject(new Error('Missing required parameter: body'))
}
return request('post', domain + path, body)
}
storeも書いてみた
backend.js
import { Login } from '../lib/backend-client'
export const actions = {
login: ({}, { email, password }) => {
const loginService = Login({ email, password })
return loginService
}
}
login.js
export const state = () => ({
email: '',
password: '',
key: ''
})
export const mutations = {
setLoginData: (state, params) => {
state.email = params.email
state.password = params.password
},
setKey: (state, data) => {
state.key = data.key
}
}
export const actions = {
login: ({ commit, state, dispatch }) => {
return new Promise(function(resolve, reject) {
const api = dispatch(
'backend/login',
{
email: state.email,
password: state.password
},
{ root: true }
)
api.then((resp) => {
commit('setKey', resp.data)
})
api.catch((error) => {
console.log('get netstatus got error', error)
})
})
}
}
export const getters = {
accessKey: (state) => {
return state.key
}
}
これができたら、あとは、loginを呼んでみる
この時点で色々できていそうなんだけど、どうやらCORS設定してね、ってなってるな
railsに書いてみようか
railsのCSRF offにした
protect_from_forgery with: :null_session
できてるかわからないけど
そしてCORS、なんか便利なのあるんだなー
CORSをこのように設定
application.rb
config.middleware.insert_before 0, Rack::Cors do
allow do
origins "http://localhost:3000"
resource "*",
headers: :any,
methods: [:get, :post, :put, :delete, :head, :options]
end
end
そしたら、画面は変わらないけど、うまくいったっぽい
Started POST "/login" for ::1 at 2019-11-26 23:51:56 +0900
Processing by SessionsController#create as HTML
Parameters: {"email"=>"", "password"=>"[FILTERED]", "session"=>{"email"=>"", "password"=>"[FILTERED]"}}
HTTP Origin header (http://localhost:3000) didn't match request.base_url (http://localhost:3001)
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 0], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:12:in `current_user'
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", ""], ["LIMIT", 1]]
↳ app/controllers/sessions_controller.rb:26:in `set_user'
Rendering sessions/new.html.erb within layouts/application
Rendered sessions/new.html.erb within layouts/application (Duration: 0.2ms | Allocations: 54)
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 0], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:12:in `current_user'
Filter chain halted as :set_user rendered or redirected
Completed 200 OK in 24ms (Views: 16.5ms | ActiveRecord: 1.2ms | Allocations: 9564)
200帰ってきてるログが出てる
あ、よくみたらemailもpasswordも空ですね session[email] にしなきゃ
なんかダメだな、値渡されてないわ
あーsetLoginDataしてないわ
直接渡す感じにしてみた
export const actions = {
login: ({ commit, dispatch }, { email, password }) => {
return new Promise(function(resolve, reject) {
const api = dispatch(
'backend/login',
{
email,
password
},
{ root: true }
)
api.then((resp) => {
commit('setKey', resp.data)
})
api.catch((error) => {
console.log('get netstatus got error', error)
})
})
}
}
Started POST "/login" for ::1 at 2019-11-26 23:58:13 +0900
Processing by SessionsController#create as HTML
Parameters: {"session[email]"=>"", "session[password]"=>"[FILTERED]", "session"=>{"session[email]"=>"", "session[password]"=>"[FILTERED]"}}
HTTP Origin header (http://localhost:3000) didn't match request.base_url (http://localhost:3001)
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 0], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:12:in `current_user'
Unpermitted parameters: :session[email], :session[password]
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."email" IS NULL LIMIT ? [["LIMIT", 1]]
↳ app/controllers/sessions_controller.rb:26:in `set_user'
Rendering sessions/new.html.erb within layouts/application
Rendered sessions/new.html.erb within layouts/application (Duration: 0.3ms | Allocations: 54)
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 0], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:12:in `current_user'
Filter chain halted as :set_user rendered or redirected
Completed 200 OK in 18ms (Views: 13.3ms | ActiveRecord: 0.5ms | Allocations: 9742)
うーん、なんか変なパラメータで渡されてるなぁ
ん?なんかそのまま行った方が良さそうだぞ?
import { Login } from '../lib/backend-client'
export const actions = {
login: ({ state }, { email, password }) => {
console.log(email)
console.log(password)
const param = {
email,
password
}
const loginService = Login(param)
return loginService
}
}
Started POST "/login" for ::1 at 2019-11-27 00:05:40 +0900
(0.3ms) SELECT sqlite_version(*)
Processing by SessionsController#create as HTML
Parameters: {"session[email]"=>"kabi@mail.com", "session[password]"=>"[FILTERED]", "session"=>{"session[email]"=>"kabi@mail.com", "session[password]"=>"[FILTERED]"}}
HTTP Origin header (http://localhost:3000) didn't match request.base_url (http://localhost:3001)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 0], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:12:in `current_user'
Unpermitted parameters: :session[email], :session[password]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."email" IS NULL LIMIT ? [["LIMIT", 1]]
↳ app/controllers/sessions_controller.rb:26:in `set_user'
Rendering sessions/new.html.erb within layouts/application
Rendered sessions/new.html.erb within layouts/application (Duration: 1.8ms | Allocations: 53)
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 0], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:12:in `current_user'
Filter chain halted as :set_user rendered or redirected
Completed 200 OK in 54ms (Views: 41.2ms | ActiveRecord: 0.5ms | Allocations: 9766)
何でsessionのなかに自動的にemailもpasswordも入っているか不明だな...
import axios from 'axios'
export const request = (method, url, body) => {
method = method.toLowerCase()
return axios[method](url, body)
}
export const Login = function(parameters = {}) {
const domain = 'http://localhost:3001'
const path = '/login'
const body = parameters
body.hoge = 'fuga'
console.log(body)
return request('post', domain + path, body)
}
fugaを強制追加してみた所
Started POST "/login" for ::1 at 2019-11-27 00:14:31 +0900
(0.8ms) SELECT sqlite_version(*)
(0.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by SessionsController#create as HTML
Parameters: {"email"=>"kabi@mail.com", "password"=>"[FILTERED]", "hoge"=>"fuga", "session"=>{"email"=>"kabi@mail.com", "password"=>"[FILTERED]", "hoge"=>"fuga"}}
HTTP Origin header (http://localhost:3000) didn't match request.base_url (http://localhost:3001)
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 0], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:12:in `current_user'
Unpermitted parameter: :hoge
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "kabi@mail.com"], ["LIMIT", 1]]
↳ app/controllers/sessions_controller.rb:26:in `set_user'
Unpermitted parameter: :hoge
Redirected to http://localhost:3001/
Completed 302 Found in 243ms (ActiveRecord: 1.1ms | Allocations: 7673)
fugaがどちらにも入っていた... これは誰の挙動なんだ...
なんか、それっぽくできているんだけど、ちょっとdispatch周りが適当すぎるので、修正していきたい気持ち
↑なんか色々やってたっぽいけど、新たな知見として CORS設定していれば、ブラウザはnuxtのaxiosを使ったrailsへのアクセスにセッションを使ってくれるみたい
そうなのか、、、今まで全部勘違いしてた...
nuxtのmiddlewareで、ログインチェックしたい、どうしたらいいかな? backendのsessionがあるかどうか、か
ちょっと整理した方がいいな?
今やりたいのは、なんとなく、nuxtからrailsにログイン、みたいな感じのイメージだけど ちょっとやり方が微妙な可能性があるな?
ヘルスチェック的なエンドポイント作ってみた じゃあそこをチェックして、falseならログインにリダイレクトするようにしてみようか
んー、jwtにする、やっぱり一旦jwtにして、その検証でやろう
なるほど、jwtをDBに保存する必要あり? やるかー、、、やらなくてよさそう
ログイン自体はWebページでやれば良い、user#checkにアクセスした時に、jwtをjsonで返すようにするか
def check
render :json => payload(current_user)
end
def payload(user)
return {} unless user and user.id
{
auth_token: JsonWebToken.encode({user_id: user.id, exp: (Time.now + 2.week).to_i}),
}
end
こんな感じで
nuxt使ってログインする必要はない、どちらかといえば、jwtとったので、これを使ってリクエストとか送りたいよねとはなる
$ curl http://localhost:3001/items \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE1Nzc4NzY1NDB9.jd7YoKoNiQDaEf6j6lU74auwlzh7zjUWBUj6IPxNGrk"
[{"name":"バナナ","price":200},{"name":"ぶどう","price":300},{"name":"りんご","price":100}]
いけた
これを使ってnuxtでデータ取りたいというのは別のお話...
nuxtするぞ!!!
JWTとか使って、ログイン後のデータにアクセスしたいんだ!!