前提・実現したいこと
userを削除したいのですが
destroyアクションがうまく機能しません
発生している問題・エラーメッセージ
エラーメッセージが表示されません
該当のソースコード
users_controller
ruby
1class UsersController < ApplicationController 2 include SessionsHelper 3 4 5 def destroy 6 user = User.find(params[:id]) 7 #binding.pry 8 user.destroy 9 redirect_to root_url 10 end 11 12 13
drinks/index.html.erb
erb
1<%= link_to "退会する", user_path(current_user),method: :delete %>
current_userは自分で定義したヘルパーメソッドです
sessions_helper.rb
ruby
1 # 現在ログインしているユーザーの情報を取得 2 def current_user 3 # DBの問い合わせの数を可能な限り小さくしたい 4 # logged_in?メソッドでも使われてるし、、、 5 if user_id = session[:user_id] 6 # セッションがある場合 7 # すなわちログインしてる時のみ 8 9 # sessionにアクセスした結果を変数に 10 # 入れておいてあとで使いまわした方が 11 # 早くなる 12 @current_user ||= User.find_by(id: user_id) 13 # find_byでデータベースにクエリを投げる 14 # ブラウザのセッションにあるuser_idをもとにUser定義 15 16 # find_byの実行結果をインスタンス変数に保存する 17 # ことで、1リクエスト内におけるデータベースへの 18 # 問い合わせは最初の一回だけになり、 19 # 以後の呼び出しではインスタンス変数の結果を 20 # 再利用する 21 22 # すでに@current_userが存在する場合って何? 23 # 一回current_userを実行したら、 24 # @current_userがあるのでそれを使ってね 25 26 # sessionのuser_idがあるということは 27 # 既にログインしてるといてDBにユーザーの情報があるはず。 28 # だからsessionのuser_idをDBでfind_byかければいい 29 elsif (user_id = cookies.signed[:user_id]) 30 # sessionが張られてなかったらcookiesにあるかも 31 user = User.find_by(id: user_id) 32 if user && user.authenticated?(cookies[:remember_token]) 33 # nilガード 34 # クッキーのuser_idとremember_tokenが一致してる 35 log_in user 36 @current_user = user 37 end 38 end 39 end
user.rb
ruby
1class User < ApplicationRecord 2 attr_accessor :remember_token 3 # remember_tokenというメソッドを作成 4 # password,password_comfirmationみたいな 5 # 変数のように扱える 6 # u.remember_token的なことができる 7 has_many :drinks, dependent: :delete_all 8 before_save { self.email = email.downcase } 9 has_secure_password 10 validates :nickname, presence: true, length: { maximum: 50 } 11 VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+.[a-z]+\z/i 12 validates :email, presence: true, length: { maximum: 255 }, 13 format: { with: VALID_EMAIL_REGEX }, 14 uniqueness: { case_sensitive: false } 15 validates :password, presence: true, length: { minimum: 6 },allow_nil: true 16 # ユーザー更新時に空のパスワードでも大丈夫 17 # has_secure_passwordの方でpasswordの存在性を検証するから大丈夫 18 19 20 21 # 渡された文字列のハッシュ値を返す 22 def User.digest(string) 23 cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : 24 BCrypt::Engine.cost 25 BCrypt::Password.create(string, cost: cost) 26 end 27 28 # ランダムなトークンを返す 29 def User.new_token 30 SecureRandom.urlsafe_base64 31 end 32 33 # 永続的にログインするためにトークンをDBに保存 34 def remember 35 self.remember_token = User.new_token 36 # 何のトークンか分かりやすいから 37 # remember_tokenって名前を作った 38 update_attribute(:remember_digest,User.digest(remember_token)) 39 # ハッシュ化したトークンをremember_digestに保存 40 end 41 42 # 渡されたトークンがダイジェストと一致したらtrue 43 # を返す 44 def authenticated?(remember_token) 45 return false if remember_digest.nil? 46 # 二種類のブラウザを使用してログアウトした場合 47 # cookiesのremember_tokenはあるけど、 48 # サーバー側でremember_digestをnilにしてるから 49 # nilに対して.is_password?とかやるとfor nil classエラーが起きちゃう 50 # remember_digestがnilの場合はfalseを返して、処理を止める 51 52 # 後置if文に当てはまる条件があれば処理を止めて! 53 # って場合はreturnとかで明示的に書くとif ~ else ~ end 54 # とか書かなくて済む 55 BCrypt::Password.new(remember_digest).is_password?(remember_token) 56 end 57 58 # ユーザーのログイン情報を破棄する 59 def forget 60 update_attribute(:remember_digest,nil) 61 end 62end 63
Drink.rb
ruby
1class Drink < ApplicationRecord 2 belongs_to :user 3 with_options presence: true do 4 validates :name 5 validates :explain 6 end 7end 8
:20201116073717_create_users.rb
ruby20201116073717_create_users.rb
1class CreateUsers < ActiveRecord::Migration[6.0] 2 def change 3 create_table :users do |t| 4 t.string :nickname 5 t.string :email 6 t.string :password_digest 7 8 t.timestamps 9 end 10 end 11end
/20201118162753_create_drinks.rb
ruby
1class CreateDrinks < ActiveRecord::Migration[6.0] 2 def change 3 create_table :drinks do |t| 4 t.string :name 5 t.integer :price 6 t.text :explain 7 t.references :user,null: false,foreign_key: true 8 t.timestamps 9 end 10 end 11end 12
routes.rb
ruby
1Rails.application.routes.draw do 2 root to: 'drinks#index' 3 get '/login', to: 'sessions#new' 4 post '/login', to: 'sessions#create' 5 delete '/logout', to: 'sessions#destroy' 6 resources :users 7 resources :drinks, only: [:index,:new,:show,:create,:destroy] 8end
退会リンクをusers/showに移動しました
エラーも起きていませんし、@userの定義もしっかりできていて、@user.nameとかやってもしっかり表示できているので、リンクの指定はあってると思います
このログを見るとリンクを踏んだ後にrootに戻ってるように見えます
補足情報(FW/ツールのバージョンなど)
ruby 2.6.5
rails 6.0.3
モデルはどのようなコードですか?
(モデル単体でdestroyしてロールバックがかかるということは、モデルに入ったバリデーションが影響していることが考えられます)
ありがとうございます、追加しましたのでご確認のほどよろしくお願いします
irbでuser.destroyを行って失敗した直後にuser.errorsを確認することはできますか?
```
irb(main):003:0> user = User.first
Traceback (most recent call last):
5: from /Users/soichirohara/.rbenv/versions/2.6.5/bin/irb:23:in `<main>'
4: from /Users/soichirohara/.rbenv/versions/2.6.5/bin/irb:23:in `load'
3: from /Users/soichirohara/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
2: from (irb):3
1: from (irb):3:in `rescue in irb_binding'
NameError (uninitialized constant User)
```
rails c 的な感じで実行したら上手くいかないので、どのようなコマンドを打つべきか教えて下されば幸いです。
すみません、単なるirbではなくてrails cから行ってください(アドバイスが悪かったです)。
[2] pry(main)> u = User.first
(0.7ms) SET NAMES utf8mb4, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
User Load (0.3ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> #<User:0x00007fcf0c065aa8
id: 26,
nickname: "はらそう",
email: "harasou@gmail.com",
created_at: Mon, 23 Nov 2020 21:33:48 UTC +00:00,
updated_at: Mon, 23 Nov 2020 21:33:48 UTC +00:00,
password_digest: [FILTERED],
remember_digest: nil>
[3] pry(main)> u.destroy
(3.9ms) BEGIN
Drink Load (0.3ms) SELECT `drinks`.* FROM `drinks` WHERE `drinks`.`user_id` = 26
Drink Destroy (7.2ms) DELETE FROM `drinks` WHERE `drinks`.`id` = 8
User Destroy (0.9ms) DELETE FROM `users` WHERE `users`.`id` = 26
(2.0ms) COMMIT
=> #<User:0x00007fcf0c065aa8
id: 26,
nickname: "はらそう",
email: "harasou@gmail.com",
created_at: Mon, 23 Nov 2020 21:33:48 UTC +00:00,
updated_at: Mon, 23 Nov 2020 21:33:48 UTC +00:00,
password_digest: [FILTERED],
remember_digest: nil>
質問の内容とは違い、今度はしっかり削除できてるような気がしますが、
実際に自分で作ったアプリ上から削除すると上手くいきません、、
link_toの記述が間違ってるのかな、、と思ったのですが
ログでは
Started DELETE “/users/27” for ::1 at 2020-11-24 17:38:11 +0900
Processing by UsersController#destroy as HTML
Parameters: {“authenticity_token”=>“6XlOECeU2iBZQO559AgCQDtxvC0AgRzJQcgyfFuDfrL8t8xQvTxCN9Hz4MowyrDFhnqM55Ob1VfpjerBDPqFDg==“, “id”=>“27"}
User Load (0.3ms) SELECT users.* FROM users WHERE users.id = 27 LIMIT 1
↳ app/helpers/sessions_helper.rb:53:in `current_user’
Redirected to http://localhost:3000/
Filter chain halted as :correct_user rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.3ms | Allocations: 978)
このようにしっかりdestroyに飛ばせてるような気がします、、、
Rails内ではdrinkのdestroyに失敗しているようですが、(Userではなく)そちらではどうでしょうか?
4] pry(main)> drink = Drink.first
Drink Load (0.6ms) SELECT `drinks`.* FROM `drinks` ORDER BY `drinks`.`id` ASC LIMIT 1
=> #<Drink:0x00007fcf02f82a90
id: 9,
name: "そうちゃんの投稿",
price: 0,
explain: "aaaa",
user_id: 1,
created_at: Tue, 24 Nov 2020 10:29:37 UTC +00:00,
updated_at: Tue, 24 Nov 2020 10:29:37 UTC +00:00>
[5] pry(main)> drink.destroy
(0.4ms) BEGIN
Drink Destroy (0.6ms) DELETE FROM `drinks` WHERE `drinks`.`id` = 9
(1.8ms) COMMIT
=> #<Drink:0x00007fcf02f82a90
id: 9,
name: "そうちゃんの投稿",
price: 0,
explain: "aaaa",
user_id: 1,
created_at: Tue, 24 Nov 2020 10:29:37 UTC +00:00,
updated_at: Tue, 24 Nov 2020 10:29:37 UTC +00:00>
こーゆーことでよろしいのでしょうか、、?
問題なく削除できていますね…ちょっとわからないです。
ですよね、、、、いえいえ!ありがとうございます!
migrationをお見せいただくことは可能でしょうか?
userとdrinkです。
追加しました、よろしくお願いします!
なるほど
ちょっと予測していたmigrationとは違い、間違いはないようでした。
そこで、divさんのこれまでの返答を更に深く読んでいると、
「Filter chain halted as :correct_user rendered or redirected
Completed 302 Found」
という非常に興味ぶかい記述、、、
非常にお手間をおかけして誠に申し訳有りませんが、
routes.rbをお見せいただくことは可能でしょうか?
ログの意味がよく分からないので非常に助かります、、、!
いえいえとんでもないです、情報を追加したのでよろしくお願いします!
ちょっと調べてみました。
間違っているかもしれませんが、
resources :users
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
root to: 'drinks#index'
resources :drinks, only: [:index,:new,:show,:create,:destroy]
↑これでいかがでしょうか?
解決できました、、、!原因はbefore_actionで何故かdestroyをフィルタリングしてたことが原因でした、、、、
ご解決おめでとうございます^^
力になれず申し訳有りませんでした。
いえいえとんでも無いです、助けて頂いてありがとうございました、、!
質問欄にbefore_actionを記述しておくべきでした。
回答1件
あなたの回答
tips
プレビュー