Ruby on Rails密码文本框输入无法被识别的问题排查
Ruby on Rails密码文本框输入无法识别问题
相关文件配置
1. 数据库迁移文件
- create_users.rb
class CreateUsers < ActiveRecord::Migration[7.0] def change create_table :users do |t| t.string :name t.string :email t.timestamps end end end
- add_index_to_users_email.rb
class AddIndexToUsersEmail < ActiveRecord::Migration[7.0] def change add_index :users, :email, unique: true end end
- add_password_digest_to_users.rb
class AddPasswordDigestToUsers < ActiveRecord::Migration[7.0] def change add_column :users, :password_digest, :string end end
2. schema.rb
ActiveRecord::Schema[7.0].define(version: 2023_03_09_015742) do enable_extension "plpgsql" create_table "microposts", force: :cascade do |t| t.text "content" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| t.string "name" t.string "email" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "password_digest" t.index ["email"], name: "index_users_on_email", unique: true end end
3. 用户注册表单(form.html.erb)
<%= form_with(model: user) do |form| %> <% if user.errors.any? %> <div style="color: red"> <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2> <ul> <% user.errors.each do |error| %> <li><%= error.full_message %></li> <% end %> </ul> </div> <% end %> <div class="container h-100"> <div class="row align-items-center h-100"> <div class="col-6 mx-auto"> <div class="jumbotron"> <form> <div class="form-group"> <%= form.label :name, style: "display: block" %> <%= form.text_field :name, class: "form-control" %> </div> <div class="form-group"> <%= form.label :email, style: "display: block" %> <%= form.text_field :email, class: "form-control" %> </div> <div class="form-group"> <%= form.label :password, style: "display: block" %> <%= form.text_field :password, class: "form-control" %> </div> <br/> <div class="center"> <%= form.submit class: 'btn btn-outline-success' %> </div> </form> </div> </div> </div> </div> <% end %>
4. Users控制器
class UsersController < ApplicationController before_action :set_user, only: %i[ show edit update destroy ] # GET /users or /users.json def index @users = User.all end # GET /users/1 or /users/1.json def show end # GET /users/new def new @user = User.new end # GET /users/1/edit def edit end # POST /users or /users.json def create @user = User.new(user_params) respond_to do |format| if @user.save format.html { redirect_to user_url(@user), notice: "User was successfully created." } format.json { render :show, status: :created, location: @user } else format.html { render :new, status: :unprocessable_entity } format.json { render json: @user.errors, status: :unprocessable_entity } end end end # PATCH/PUT /users/1 or /users/1.json def update respond_to do |format| if @user.update(user_params) format.html { redirect_to user_url(@user), notice: "User was successfully updated." } format.json { render :show, status: :ok, location: @user } else format.html { render :edit, status: :unprocessable_entity } format.json { render json: @user.errors, status: :unprocessable_entity } end end end # DELETE /users/1 or /users/1.json def destroy @user.destroy respond_to do |format| format.html { redirect_to users_url, notice: "User was successfully destroyed." } format.json { head :no_content } end end #show micropost for the user def show @user = User.find(params[:id]) @micropost = @user.microposts.first end private # Use callbacks to share common setup or constraints between actions. def set_user @user = User.find(params[:id]) end # Only allow a list of trusted parameters through. def user_params params.require(:user).permit(:name, :email) end end
问题详情
提交注册表单时,明明输入了sample_password1234这类密码,却始终弹出错误提示:
Password can't be blank
Password is too short (minimum is 6 characters)
控制台沙箱里创建用户操作正常,但一开始控制器的user_params没允许password参数。后来加上password参数后能创建用户了,但查询user.password返回的是nil。
解决方案
1. 修复表单嵌套问题
你的ERB表单里嵌套了两层<form>标签:外层是form_with生成的Rails表单,内层又手写了原生<form>,这会导致表单提交时,密码参数无法被Rails表单助手正确捕获,根本没传到后端。
删掉内层的<form>和</form>标签,同时把密码输入框从text_field改成password_field(标准做法,避免密码明文显示),修改后的表单代码:
<%= form_with(model: user) do |form| %> <% if user.errors.any? %> <div style="color: red"> <h2><%= pluralize(user.errors.count, "错误") %> 阻止了用户创建:</h2> <ul> <% user.errors.each do |error| %> <li><%= error.full_message %></li> <% end %> </ul> </div> <% end %> <div class="container h-100"> <div class="row align-items-center h-100"> <div class="col-6 mx-auto"> <div class="jumbotron"> <div class="form-group"> <%= form.label :name, style: "display: block" %> <%= form.text_field :name, class: "form-control" %> </div> <div class="form-group"> <%= form.label :email, style: "display: block" %> <%= form.text_field :email, class: "form-control" %> </div> <div class="form-group"> <%= form.label :password, style: "display: block" %> <%= form.password_field :password, class: "form-control" %> </div> <br/> <div class="center"> <%= form.submit class: 'btn btn-outline-success' %> </div> </div> </div> </div> </div> <% end %>
2. 更新控制器参数白名单
确保user_params包含password参数,修改后的代码:
def user_params params.require(:user).permit(:name, :email, :password) end
3. 完善User模型配置
你已经添加了password_digest字段,但还需要在app/models/user.rb里启用has_secure_password,Rails才会自动处理密码加密存储,同时提供密码验证逻辑:
class User < ApplicationRecord has_secure_password # 可选:添加密码长度验证,和错误提示对应 validates :password, length: { minimum: 6 } end
4. 关于user.password返回nil的说明
使用has_secure_password后,password是虚拟属性,不会被存储到数据库,数据库里只有加密后的password_digest。所以查询user.password返回nil是正常现象,验证用户登录时用authenticate方法即可:
user = User.find_by(email: params[:email]) if user&.authenticate(params[:password]) # 登录成功逻辑 else # 登录失败逻辑 end
内容的提问来源于stack exchange,提问作者JS3
相关产品推荐
相关产品推荐

