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

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

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

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

Ruby on Rails

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

ログイン

ログインは、ユーザーがコンピューターシステムにアクセスするプロセスの事を呼びます。

Q&A

解決済

3回答

2196閲覧

ログインフォームをform_forで作成できず、困っています

1234567

総合スコア7

Ruby

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

Ruby on Rails

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

ログイン

ログインは、ユーザーがコンピューターシステムにアクセスするプロセスの事を呼びます。

0グッド

0クリップ

投稿2020/02/08 07:14

編集2020/02/17 05:02

現在Ruby on Rails にて、Twitterのような投稿サービスを作っております。求職用のポートフォリオとしての制作です。

元々progateで勉強をしていたため入力フォームを「form_tag」で理解していました。そして今「form_for」or「form_with」へログインページのフォーム部分を入れ替えているところです。その最中、form_tagでは動いていたログイン機能で、エラーが出るようになってしまいました。

エラー文は、この通りです
イメージ説明

Rails.application.routes.draw do get "home/top" => 'home#top' get "posts/index" => "posts#index" get "posts/new" => "posts#new" post "posts/create" => "posts#create", as: :posts get "posts/:id/edit" => "posts#edit" get "posts/:id" => "posts#show" patch 'posts/:id' => 'posts#update', as: :post post "posts/:id/destroy" => "posts#destroy" get "signnup" => "users#new" post "users/create" => "users#create", as: :users post "login_guest" => "users#login_guest" get "login" => "users#login_form" post "login" => "users#login" post "logout" => "users#logout" get "users/index" => "users#index" get "users/:id" => "users#show" get "users/:id/edit" => "users#edit" patch "users/:id/update" => "users#update", as: :user post "users/:id/destroy" => "users#destroy" end
users.controller class UsersController < ApplicationController before_action :ensure_correct_user, {only: [:edit, :update]} before_action :authenticate_user, {only: [:edit, :update]} before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]} def ensure_correct_user if @current_user.id != params[:id].to_i flash[:notice] = "できません" redirect_to("/login") end end def index @users = User.all.order(created_at: :desc) end def show @user = User.find_by(id: params[:id]) end def new @user = User.new end def login_guest @user = User.find_by(email: "guest_user@example.com", password: "12345") if @user session[:user_id] = @user.id flash[:notice] = "ゲストユーザーとしてログインしました" redirect_to("/posts/index") end end def create @user = User.new(user_params) if @user.save session[:user_id] = @user.id flash[:notice] = "ユーザー登録完了" redirect_to("/users/#{@user.id}") else flash[:notice] = "ユーザー登録失敗" render("users/new") end end def login_form end def login @user = User.find_by(email: params[:email]) if @user && @user.authenticate(params[:password]) session[:user_id] = @user.id flash[:notice] = "ログイン成功" redirect_to("/posts/index") else @error_message = "メールアドレスかパスワードが違います" @email = params[:email] @password = params[:password] render("users/login_form") end end def logout session[:user_id] = nil flash[:notice] = "ログアウトしました" redirect_to("/login") end def edit @user = User.find_by(id: params[:id]) end def update @user = User.find_by(id: params[:id]) if @user.update(user_params) flash[:notice] = "ユーザー情報を変更しました" redirect_to("/users/#{@user.id}") else render("/users/edit") end end def destroy @user = User.find_by(id: params[:id]) @user.destroy redirect_to("/users/index") flash[:notice] = "削除しました" end private def user_params params.require(:user).permit(:name, :email, :password, :image) end end
application_controller class ApplicationController < ActionController::Base before_action :set_current_user def top end def set_current_user @current_user = User.find_by(id: session[:user_id]) end def authenticate_user end def forbid_login_user if @current_user flash[:notice] = "すでにログインしています" redirect_to("/posts/index") end end end
home_controller class HomeController < ApplicationController before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]} def top end end
users/login_form.html.erb <div class = "form-error"> <% if @error_message %> <%= @error_message %> <% end %> </div> <div class="user_login_item"> <h1>既存ユーザーログイン</h1> <div class="user_login"> <%= form_for @user do |f| %> <%= f.label :email, "メールアドレス" %><br> <%= f.text_field :email %><br><br> <%= f.label :password, "パスワード" %><br> <%= f.text_field :password %><br><br> <%= f.submit "ログイン" %> <% end %> </div> </div>
schema.rb ActiveRecord::Schema.define(version: 2020_01_18_054634) do create_table "destroys", force: :cascade do |t| t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end create_table "posts", force: :cascade do |t| t.text "content" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.string "image" t.integer "user_id" t.string "title" t.float "rate" end create_table "sessions_users", force: :cascade do |t| t.string "name" t.string "email" t.string "password" t.string "image" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end create_table "users", force: :cascade do |t| t.string "name" t.string "email" t.string "image" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.string "password_digest" end end
models/User class User < ApplicationRecord has_secure_password mount_uploader :image,ImageUploader validates :name, {presence: true} validates :email, {presence: true} validates :password, {presence: true} def posts return Post.where(user_id: self.id) end paginates_per 8 end
user/edit <div class="user-index"> <h1>ユーザー情報の編集</h1> <% @user.errors.full_messages.each do |message| %> <div class="form-error"> <%= message %> </div> <% end %> <div class="user-edit-container"> <%= form_for @user do |f| %> <div class="user-edit-item"> <%= f.label :name, "ユーザー名(※必須)", class: "form" %><br> <%= f.text_field :name %><br> <%= f.label :image, "画像", class: "form" %><br> <%= f.file_field :image %><br> <%= f.label :email, "メールアドレス(※必須)", class: "form" %><br> <%= f.text_field :email %><br> <%= f.label :password, "パスワード(※必須)", class: "form" %><br> <%= f.text_field :password %><br> <%= f.submit "新規登録", class: "form" %> </div> <% end %> </div> </div>

自分で試したこととしては、form_forの@userがnilなので、login_formアクション内で@userオブジェクトを生成したりもしたのですが、特に変わらず、、
(具体的には、
・@user = User.find_by(email: params[:email], password: params[:password])
・@user = User.find_by(id: params[:id])
など。)

sessionコントローラーなどは用いずに実装したいと考えています。(できないのであれば仕方ないとは考えています)。
また、form_tagで実装すると機能するので、form_tagのままでいいかなとも思いつつ、全体としてform_forで揃えるべきだよな、、とも考えています。

login_formアクション内で@userオブジェクトに何を定義すればいいのでしょうか?もしお分かりの方がいらっしゃいましたら、アドバイスいただけると幸いです。

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

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

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

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

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

guest

回答3

0

ベストアンサー

他の回答者さんもおっしゃっていますが、find_byだとnilを返す可能性があるので、必ずUserインスタンスを返すようにしましょう。

diff

1 def login_form 2+ @user = User.new 3 end

diff

1 def login 2- @user = User.find_by(email: params[:email]) 3+ @user = User.find_or_initialize_by(email: user_params[:email]) 4 5- if @user && @user.authenticate(params[:password]) 6+ if @user.persisted? && @user.authenticate(user_params[:password]) 7 session[:user_id] = @user.id 8 flash[:notice] = "ログイン成功" 9 redirect_to("/posts/index") 10 else 11- @error_message = "メールアドレスかパスワードが違います" 12- @email = params[:email] 13- @password = params[:password] 14 render("users/login_form") 15 end 16 end

form_forにモデルのインスタンスを渡しただけの場合、そのインスタンス情報が新規で作られたものであればcreateに、DBから取り出したものであればeditに向けて送信されます。
今回はそのどちらでもないloginに送信したいわけですので:urlを明示的に指定しましょう。

erb

1<%= form_for @user, url: login_path do |f| %>

投稿2020/02/18 04:03

編集2020/02/18 05:59
Mugheart

総合スコア2349

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

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

1234567

2020/02/18 05:43

回答ありがとうございます。 Mugheartさんの回答の通りに行ったところ、 「 NameError in Users#login_form Showing /Users/sakamotoryou/portfolio.folder/Read-memo/app/views/users/login_form.html.erb where line #10 raised: undefined local variable or method `users_login_path' for #<#<Class:0x00007f96ae8f5ba0>:0x00007f96ae912480> Did you mean? users_index_path 」 と言うエラー文になりました。 :urlで指定したpathがいけないのかと思い、login_pathだけに変更して試してみたところ、login_formページは表示されるようになったのですが、ログイン機能としては動かず、何故か正しいユーザー情報をフォーム入力しても弾かれてログインできない形になりました。 これはpathの指定を間違えてるのか、それともそもそも他の部分に原因があるのでしょうか?
Mugheart

2020/02/18 05:57

あぁ、url は login_path が正しいんだと思います。 routes.rb見てませんでした、失礼。 > 何故か正しいユーザー情報をフォーム入力しても弾かれてログインできない形になりました。 ログイン処理の部分に問題があるんだと思います。 user_params[:email] とか user_params[:password] で入力値を受け取るのでは? 回答編集しておきます。
1234567

2020/02/18 06:31

おっしゃるように、loginアクションを 「 def login @user = User.find_or_initialize_by(email: user_params[:email]) if @user.persisted? && @user.authenticate(user_params[:password]) session[:user_id] = @user.id flash[:notice] = "ログイン成功" redirect_to("/posts/index") else render("users/login_form") end end 」 にしたところ、無事に解決しました。今回の質問に加え、別の質問でもMugheartさんのアドバイスで解決したエラーもあり、非常に感謝しております。どうもありがとうございました!
guest

0

自分で試したこととしては、form_forの@userがnilなので、login_formアクション内で@userオブジェクトを生成したりもしたのですが、特に変わらず、、
(具体的には、
・@user = User.find_by(email: params[:email], password: params[:password])
・@user = User.find_by(id: params[:id])

など。

find_by だと nil になりえるので、

@user = User.new

ではないでしょうか

投稿2020/02/16 04:23

unhappychoice

総合スコア1531

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

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

1234567

2020/02/17 04:44

@user = User.newですと、フォームは現れるようになりますが、新しいアカウント作成の動きをしてしまい、ログインとしては機能しませんでした
guest

0

「login_formアクション内で@userオブジェクトを生成」
が方針としては正解ですが、「特に変わらず」というのは
エラー発生場所もメッセージも全く同じということでしょうか?

だとすると「login_formアクション内で@userオブジェクトを生成」がうまく行っていなかった。
どのように書きましたか?

追記
@user = User.find_by(email: params[:email], password: params[:password])
とありますが、パスワードって生で入れてますか? 暗号化して入れてありますか?
普通は暗号化してあるのでそのつもりで書きますと、
暗号化してあるPASSWORDはparamsにある生のとは一致しないので@userは必ずnilになります。
@user = User.find_by(email: params[:email])
とし、
nilでなく、かつ params[:password]を暗号化した値が DBにある値と一致している
場合にlogin成功 とします

投稿2020/02/08 07:52

編集2020/02/16 04:29
winterboum

総合スコア23567

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

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

1234567

2020/02/09 02:44

@user = User.find_by(email: params[:email], password: params[:password]) @user = User.find_by(id: params[:id]) この2点を試したところ、同じエラー文が出ております、、
winterboum

2020/02/09 02:56

@user = User.find_by(email: params[:email]) DBに入っているpqasswordは生ではないので一致するUserは居ません login画面からは params[:id]って渡ってきますか?
1234567

2020/02/09 03:57

そもそも何故ログインページを取得したいだけなのに@userオブジェクトを生成する必要があるのかが分かりません。form_tagでビューを作ると機能するので、余計に混乱してる状態です、、
winterboum

2020/02/09 04:10

ログインページを取得 ってどういう意味ですか?
1234567

2020/02/09 04:16

ログインページを表示したいってことです!伝え方が悪かったです、すみません。
winterboum

2020/02/09 05:44

emailとPASSWORDの入力画面のことですか? ですと、User の email、passwordを入力するための画面を作りますので、Userのobjectを使っているのでしょう。 なしに作ることも可能ですが、そうするには viewやcontrollerの書き直しが必要になります
1234567

2020/02/17 04:43

元々は暗号化せず生のパスワードだったのですが、追記で頂いた内容を踏まえ、暗号化に修正しました(すでに作成済みだったUserアカウントは全て消去しました)。 そしてlogin_formアクションを 「@user = User.find_by(email: params[:email])」 に変更しましたが、特に結果は変わりませんでした。 別の方が回答くださったように、試しに「@user = User.new」にするとフォームは現れるので、やはり@userオブジェクトの書き方が間違ってるのだと思います。(ログインとして機能しないですが) 調べてみてもこのケースの回答が出てこずでした。何かお分かりになったりしますでしょうか?
winterboum

2020/02/17 04:50

@user = User.find_by(email: params[:email]) の結果が nilであるということは、そういうemailのユーザが居ないということです。 とすると、編集画面を呼び出すview(とそれを書き出すcontroller)に問題があります。 それを載せてください。
1234567

2020/02/17 05:04

user編集画面のview、controllerについて追加致しましたので、確認いただけると幸いです
winterboum

2020/02/17 07:36 編集

ごめん、他の人の質問と混同してました。 編集画面じゃなかったですね、loginだった。 「そういうemailのユーザが居ないということです」がまちがいだった。 login画面へはunhappyさんの言われるように User.new で渡すのが正解です。 で、 「特に結果は変わりませんでした。」というのはどうなったんですか? def login @user = User.find_by(email: params[:email]) if @user && @user.authenticate(params[:password]) なら通るのではとおもうのですが
1234567

2020/02/18 02:25

def login_form @user = User.new end def login @user = User.find_by(email: params[:email]) if @user && @user.authenticate(params[:password]) session[:user_id] = @user.id flash[:notice] = "ログイン成功" redirect_to("/posts/index") else @error_message = "メールアドレスかパスワードが違います" @email = params[:email] @password = params[:password] render("users/login_form") end end 上記のようにすると、新しいアカウントが作成されてしまう事象が起こります。
winterboum

2020/02/18 03:50

ここにあるcodeにはUserをcreate(とかnewしてsaveとか)がないので、それはおかしいです。 存在する emailで作られますか、存在しないemailで作られますか? 存在する方だと user.authenticateが怪しい。ここ自作ですか?載せてください しないほうだと、、、、、 ありえん、、、
1234567

2020/02/18 06:32

無事解決しました。アドバイスいただき、ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問