質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

0回答

1211閲覧

[Swift]Swift側でもRailsのcurrent_userの値を保持した状態でログアウト処理を実行したい

yasukun252

総合スコア34

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/09/05 08:43

編集2021/09/05 10:29

前提・実現したいこと

Ruby on RailsとSwiftUIで以下のようなログイン機構を実装しております。

Rails側でデバッグするとログイン処理中はcurrent_userが取得できますが
違う部分でAPIを叩くとcurrent_userがnilになってしまいます。

ログイン処理は正確に動きますが、ログアウト処理の部分が動きません。

ログアウトの場合も.deleteでAPIにリクエストを送りたいのですが、そのためには上記のログイン処理中にSwift側でもcurrent_userを保持しておく必要があると思いますが、どのような処理を実装してログアウトの.deleteでAPIではどのようなパラメータを送れば良いでしょうか?

ruby

1routes.rb 2post '/login', to: 'sessions#create' # ログイン 3delete '/logout', to: 'sessions#destroy' # ログアウト

Ruby

1helper/session_helper.rb 2module SessionsHelper 3 # 渡されたユーザーでログインする 4 def log_in(user) 5 session[:user_id] = user.id 6 end 7 8# 現在ログイン中のユーザーを返す 9 def current_user 10 if session[:user_id] 11 @current_user ||= User.find_by(id: session[:user_id]) 12 end 13 end 14 15#受け取ったユーザーがログイン中のユーザーと一致すればtrueを返す 16 def current_user?(user) 17 user == current_user 18 end 19 20# ユーザーがログインしていればtrue、その他ならfalseを返す 21 def logged_in? 22 !current_user.nil? 23 end 24 25# 現在のユーザーをログアウトする 26 def log_out 27 session.delete(:user_id) 28 @current_user = nil 29 end 30end

ruby

1controllers/sessions_controller.rb 2 3class SessionsController < ApplicationController 4   # ログイン処理 http://127.0.0.1:3000/login.json 5 def create 6 user = User.find_by(email: params[:session][:email].downcase) 7 if user && user.authenticate(params[:session][:password]) 8 log_in user 9 render json: { status: 'SUCCESS LOGIN', user: user } 10 else 11 render json: { status: 'SUCCESS FAILD', user: user } 12 end 13 end 14 15   # ログアウト処理 http://127.0.0.1:3000/logout.json 16 def destroy 17 log_out if logged_in? <- Swift側からAPIを叩くとここでcurrent_userがnilになる(swift側でcurrent_userの値を保持できていない) 18 redirect_to root_url 19 end 20end

Swift側は以下のようになっております。

Swift

1ContentView.swift 2 3import SwiftUI 4import Alamofire 5 6class AppState: ObservableObject { 7 @Published var isLogin = false 8} 9 10struct ContentView: View { 11 @State private var email: String = "" 12 @State private var password: String = "" 13 14 @EnvironmentObject var appState: AppState 15 16 var body: some View { 17 NavigationView { 18 VStack { 19 20 NavigationLink(destination: HomeView(), isActive: self.$appState.isLogin) { 21 EmptyView() 22 } 23 24 TextField("メールアドレス", text: $email) 25 TextField("パスワード", text: $password) 26 Button(action: { 27 28 let parameters = [ 29 "user": [ 30 "email": self.email, 31 "password": self.password 32 ] 33 ] 34 35 AF.request("http://127.0.0.1:3000/login.json", 36 method: .post, 37 parameters: parameters, 38 encoder: JSONParameterEncoder.default) 39 .validate(contentType: ["application/json"]) 40 .responseJSON { response in 41 if response.response?.statusCode == 200 { 42 if let json = response.value as? NSDictionary { 43 print(json) 44 if json["status"] as? String == "SUCCESS LOGIN" { 45 self.appState.isLogin = true 46 debugPrint(response) 47 print("SUCCESS LOGIN") 48 } else if json["status"] as? String == "INVALID" { 49 debugPrint(response) 50 print("IN ¥VALID") 51 } 52 } 53 } 54 } 55 }, label: { 56 Text("ログインする") 57 }) 58 }.padding() 59 } 60 } 61} 62 63 64struct HomeView: View { 65 @EnvironmentObject var appState: AppState 66 var body: some View { 67 if appState.isLogin == false { 68 ContentView().environmentObject(AppState()) 69 } 70 VStack { 71 Text("ホーム画面") 72 73 Button(action: { 74 75 let parameters = [ <- ここのパラメータにどのような値をセットすればよいか分からないため、.delete(ログアウト処理)は失敗する 76 "": "" 77 ] 78 79 AF.request("http://127.0.0.1:3000/logout.json", 80 method: .delete, 81 parameters: parameters, 82 encoder: JSONParameterEncoder.default) 83 .validate(contentType: ["application/json"]) 84 .responseJSON { response in 85 debugPrint(response) 86 } 87 self.appState.isLogin = false 88 }, label: { 89 Text("ログアウトする") 90 }) 91 } 92 .navigationBarBackButtonHidden(true) 93 .navigationBarHidden(true) 94 } 95}

コードの部分が長くなりましたが、是非アドバイスなどよろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/09/05 21:32

Rails よく分かりませんが、そもそもセッション管理ができてない (logout 以外でもエラーになる) のでは…。
yasukun252

2021/09/05 22:04

Rails側では、以下の部分でセッションを使っておりますが、swift側でも別にセッション管理が必要という事でしょうか? def log_in(user) session[:user_id] = user.id end
yasukun252

2021/09/05 22:24

ありがとうございます‼︎ かなり難しいですね… あまりよく分からないのですが、Swift側ではAlamofireとNSUserDefaultsを使ってセッション管理をするという事でしょうか?
hoshi-takanori

2021/09/05 22:34

自分も Alamofire は使ってないので詳しくはないのですが、さっきの記事はちょっと古いかもですね…。 あとでもうちょっと調べてみます。
yasukun252

2021/09/05 23:01

ありがとうございます!! 何卒よろしくお願い致します。 私も調べてみます!!
hoshi-takanori

2021/09/06 08:00

Rails で API サーバーを書いて実験してみましたが、Alamofire はデフォルトで Cookie を処理してくれますね。 なので、Rails 側の問題のような気がします。直接 API を叩いて結果 (レスポンスヘッダーに Set-Cookie があるか) を確認できますか? もしかすると application.rb に config.middleware.use を 2 行追加すればいいのかも。 https://qiita.com/someone7140/items/b89863c1ef395e63ee2b#applicationrb
hoshi-takanori

2021/09/06 08:10

あと、SessionsController ですが、ログイン失敗した時に user 情報を返すのは情報漏洩でまずいですね。 また、API なのでログアウト時にリダイレクトする意味もないような…。
yasukun252

2021/09/06 09:02

ありがとうございます!! APIを叩くと以下のようにレスポンスヘッダーにSet-Cookieは表示されるのですが。 Set-Cookie: _session_id=ef7cfaf18c7f9f0060edc3e377c7af18; path=/; HttpOnly この値をどのようにSwift側で保存してログアウトの処理のパラメータに設定するかは、まだ分かっていないです。Swift側でもRails側と同じようにcurrent_userみたいな形で保持するためには、どのようにすればよいのでしょうか? 例)user.name <- ログインしているuserのnameを表示する
hoshi-takanori

2021/09/06 09:48

レスポンスに Set-Cookie があれば、次回からのリクエストにはその値が自動的に送られてサーバー側ではセッションが認識されるはずですね。 アプリ側でユーザー名などを表示するには、login の際にユーザー情報が返ってきてるはずなので、それを保存して使えば良いでしょう。
yasukun252

2021/09/06 10:15

なるほどですね!! Swift側では、ユーザー情報を保存する場合は、UserDefaultsを使うと良いのでしょうか? ちなみに、ユーザーのstructは以下のようになってます。 struct User: Decodable, Identifiable, Encodable { var id: Int var name: String var email: String var deleted_at: String? var created_at: String var updated_at: String } loginの際に返ってくるユーザーの情報をどのようにして上記の構造体として保存するのでしょうか? すみません、あまりコード実装のイメージが分かりません。
hoshi-takanori

2021/09/06 21:58

User 構造体を JSONEncoder でエンコードして UserDefaults に保存すれば良いのでは。
yasukun252

2021/09/07 17:36

ありがとうございます!! やってみます。
yasukun252

2021/09/26 14:03

すみません、以下のようにして色々と試してみたのですが、User構造体をJSONEncoderでエンコードして UserDefaults に保存する方法の書き方が分かりませんでした。 let user = User( id: json["id"] as! Int, name: json["name"] as! String email: json["email"] as! String deleted_at: json["deleted_at"] as! String created_at: json["created_at"] as! String updated_at: json["updated_at"] as! String ) let jsonEncoder = JSONEncoder() jsonEncoder.keyEncodingStrategy = .convertToSnakeCase guard let data = try? jsonEncoder.encode(user) else { return } UserDefaults.standard.set(data, forKey: "user") このやり方ですと、アプリがクラッシュしてしまいます。 もう少しだけ、アドバイスして頂けますでしょうか? ご迷惑をお掛けしますが、何卒よろしくお願い致します。
yasukun252

2021/09/26 15:38

alamofireでのAPIの結果は以下のようになっております。 [Result]: success(Optional(6030 bytes)) { status = "SUCCESS LOGIN"; user = { id = 1; name = test01; email = "test01@example.com"; "created_at" = "2021-03-04T06:31:57.896+09:00"; "updated_at" = "2021-03-07T20:43:18.051+09:00"; "deleted_at" = "<null>"; }; }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問