Rails - 错误部分未呈现

Rails - errors partial not rendering

我对 Rails 和一般的全栈开发还很陌生。我刚刚完成了 Michael Hartl 在 Rails 教程第 6 版中的 Ruby 并再次浏览它以构建我的第一个项目(即与书中构建的示例应用程序不同的应用程序,但借鉴了很多相同的课程)。问题是新项目正在使用 Rails 7.

在我 运行 解决第 7 章的问题之前一切顺利;对于向新用户表单提交错误,我的应用程序不会呈现带有错误消息的部分。 partial 中的代码执行(通过调试器验证,然后使用 puts 语句在控制台上输出),但 HTML 不输出(即在 [=80= 中检查页面时无法找到它) ]).有一个 CSS 问题与较新版本的 bootstrap 相关,但我什至尝试从书中 (3.4.1) 降级到 bootstrap 版本,但没有成功。 (有问题的 CSS 部分在下面被注释掉了)

我已经为此苦苦思索了几个小时。希望这只是我想念的愚蠢的东西。如果它是 Bootstrap 与 Importmaps 或其他东西的更广泛问题,我也很感激学习这些的好地方的参考。我非常感谢任何想法!

编辑 这绝对不是将局部变量传递给局部变量的问题;请参阅此 post.

末尾添加的代码片段和评论

app/views/users/new.html.erb:

<% provide(:title, 'Create New User') %>
<h1>Create New User</h1>

<div class="row">
    <div class="col-md-6 col-md-offset-3">

        <%= form_with(model: @user, local: true) do |f| %>
            <%= render 'shared/error_messages' %>
            
            <%= f.label :email %>* <i>required</i>
            <%= f.email_field :email %>      

            <%= f.label :first_name %>
            <%= f.text_field :first_name %>
            
            <%= f.label :last_name %>
            <%= f.text_field :last_name %>
            
            <%= f.label :phone_number %>
            <%= f.text_field :phone_number %>
            
            <% # f.label :admin, "Company Admin" %> 
            <% # f.radio_button :admin, "True" %> 
            <% # f.label :admin, "Regular User" %>
            <% # f.radio_button :admin, "False", :checked => true %> 
            
            
            <%= f.submit "Create New User", class: "btn btn-primary" %>
        <% end %>
    </div>
</div>

app/views/shared/_error_messages.html.erb:

<% if @user.errors.any? %>
  <% puts "the error partial was called" %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>
    </div>
    <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>

提交错误数据时服务器输出示例(电子邮件验证失败):

 Started POST "/users" for 24.85.170.222 at 2022-02-14 01:01:56 +0000
Cannot render console from 24.85.170.222! Allowed networks: 127.0.0.0/127.255.255.255, ::1
Processing by UsersController#create as TURBO_STREAM
  Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"email"=>"no123@good-email", "first_name"=>"Jeff", "last_name"=>"Lebowski", "phone_number"=>""}, "commit"=>"Create New User"}
   (0.1ms)  SELECT sqlite_version(*)
  ↳ app/controllers/users_controller.rb:13:in `create'
  TRANSACTION (0.1ms)  begin transaction
  ↳ app/controllers/users_controller.rb:13:in `create'
  User Exists? (0.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "no123@good-email"], ["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:13:in `create'
  TRANSACTION (0.1ms)  rollback transaction
  ↳ app/controllers/users_controller.rb:13:in `create'
  Rendering layout layouts/application.html.erb
  Rendering users/new.html.erb within layouts/application
the error partial was called
  Rendered shared/_error_messages.html.erb (Duration: 1.8ms | Allocations: 701)
  Rendered users/new.html.erb within layouts/application (Duration: 6.2ms | Allocations: 2949)
  Rendered layouts/_rails_default.html.erb (Duration: 6.7ms | Allocations: 6277)
  Rendered layouts/_shim.html.erb (Duration: 0.5ms | Allocations: 153)
  Rendered layouts/_header.html.erb (Duration: 0.8ms | Allocations: 318)
  Rendered layouts/_footer.html.erb (Duration: 0.8ms | Allocations: 258)
  Rendered layout layouts/application.html.erb (Duration: 18.8ms | Allocations: 11238)
Completed 200 OK in 35ms (Views: 23.0ms | ActiveRecord: 0.8ms | Allocations: 16412)

Gemfile:

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.0.3"

gem "rails", "~> 7.0.1"   
gem "sprockets-rails"
gem "puma", "~> 5.0"
gem "importmap-rails"
gem "turbo-rails"           # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "stimulus-rails"        # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "jbuilder"              # Build JSON APIs with ease [https://github.com/rails/jbuilder]


gem "bootsnap", require: false
gem "sassc-rails"           # Use Sass to process CSS 

gem 'image_processing'#,           '1.9.3'
gem 'mini_magick'#,                '4.9.5'
gem 'active_storage_validations'#, '0.8.9'
gem 'bcrypt'#,                     '3.1.13'
gem 'faker'#,                      '2.11.0'
gem 'will_paginate'#,              '3.3.0'
gem 'bootstrap-will_paginate'#,    '1.0.0'
gem 'bootstrap-sass'#,             '3.4.1'

group :development, :test do
  gem "sqlite3", "~> 1.4" 
  gem "debug", platforms: %i[ mri mingw x64_mingw ] 
end

group :development do
  gem "web-console"     
  gem "rack-mini-profiler"   
  gem "spring"              
end

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "selenium-webdriver"
  gem "webdrivers"
  
  gem 'rails-controller-testing'#, '1.0.5'
  gem 'minitest'#,                 '5.11.3'
  gem 'minitest-reporters'#,       '1.3.8'
  gem 'guard'#,                    '2.16.2'
  gem 'guard-minitest'#,           '2.4.6'
end

group :production do
  gem "pg"
  gem 'aws-sdk-s3', require: false
end

app/assets/stylesheets/custom.scss:

@import "bootstrap-sprockets";
@import "bootstrap";

/* mixins, variables, etc. */

$gray-medium-light: #eaeaea;

/* universal */

body {
  padding-top: 60px;
}

section {
  overflow: auto;
}

textarea {
  resize: vertical;
}

.center {
  text-align: center;
  h1 {
    margin-bottom: 10px;
  }
}

@mixin box_sizing {
  -moz-box-sizing:    border-box;
  -webkit-box-sizing: border-box;
  box-sizing:         border-box;
}


/* typography */

h1, h2, h3, h4, h5, h6 {
  line-height: 1;
}

h1 {
  font-size: 3em;
  letter-spacing: -2px;
  margin-bottom: 30px;
  text-align: center;
}

h2 {
  font-size: 1.2em;
  letter-spacing: -1px;
  margin-bottom: 30px;
  text-align: center;
  font-weight: normal;
  color: $gray-light;

}

p {
  font-size: 1.1em;
  line-height: 1.7em;
}

/* header */

#logo {
  float: left;
  margin-right: 10px;
  font-size: 1.7em;
  color: white;
  /* text-transform: uppercase; */
  letter-spacing: -1px;
  padding-top: 9px;
  font-weight: bold;
  &:hover {
    color: white;
    text-decoration: none;
  }
}

/* footer */

footer {
  margin-top: 45px;
  padding-top: 5px;
  border-top: 1px solid #eaeaea;
  color: $gray-light;
  a {
    color: $gray;
    &:hover {
      color: $gray-darker;
    }
  }
  small {
    float: left;
  }
  
}


footer ul {
  float: right;
  list-style: none;
}

footer ul li {
  float: left;
  margin-left: 15px;
}

/* Forms */

input, textarea, select, .uneditable-input {
  border: 1px solid #bbb;
  width: 100%;
  margin-bottom: 15px;
  @include box_sizing
}

input {
  height: auto !important;
}

#error_explanation {
  color: red;
  ul {
    color: red;
    margin: 0 0 30px 0;
  }
}

/*
.field_with_errors {
  @extend .has-error;    /*this is breaking 
  /*potential solution? https://jasoncharnes.com/bootstrap-4-rails-fields-with-errors/
  .form_control {
    
    color: $state-danger-text;
  }
}
*/ 

/* Miscellaneous */

.debug_dump {
  clear:       both;
  float:       left;
  width:       100%;
  margin-top:  45px;
  @include box_sizing;
}

app/controllers/users_controller.rb:

class UsersController < ApplicationController
  def new
    @user = User.new
  end
  
  def show
    @user = User.find(params[:id])
  end
  
  def create
    @user = User.new(user_params)   #strong params required by Rails
    #debugger
    if @user.save
      #handle succesful save
    else
      render 'new'
    end
  end
  
  private
  
    def user_params
      params.require(:user).permit(:email, :first_name, :last_name, :phone_number, :admin)
    end
end

编辑 好的,我已经通过在代码中插入测试片来确认这与 HTML 渲染有关。实例变量传递给局部绝对不是问题(尽管我现在已经知道为什么这是糟糕的做法!)。下面的示例完全按照预期输出到命令行,但是当在表单中提交错误数据时,明文“False”不会更改为“True”。似乎这是 Ajax 或类似的东西,提交表单并运行 ruby/rails,但 html 没有刷新?此外 - 我现在已经为出现的错误编写测试并且测试 通过 !这让我很头疼。

app/views/shared/_error_messages.html.erb:

<% puts @user.errors.any? %>
<% if @user.errors.any? %>
  True
  <% puts @user.errors.count %>
  
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>
    </div>
    <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% else %>
  <% puts @user.email %>
  False 
<% end %>

app/views/users/new.html.erb

试试这个

<%= render 'shared/error_messages', user: @user %>

如果它是一个共享部分,也许使实例变量通用而不是 @user。这样它就可以重复使用,以后就不会那么混乱了。

在渲染中使用 locals

render partial: 'shared/error_messages', locals: { user: @user }

并在 shared/error_messages 上将 @user 重命名为 user

已解决!这是 Rails 7 中 Turbo / Hotwire 的问题(而不是 Turbolinks)。在用户控制器中,我必须更改渲染调用以包含状态::unprocessable_entity。该行为现在完美运行。

  def create
    @user = User.new(user_params)   #strong params required by Rails
    #debugger
    if @user.save
      #handle succesful save
    else
      render 'new', status: :unprocessable_entity
    end
  end

感谢所有发表评论的人。即使在部分中使用实例变量不是问题,我也确实阅读并了解了为什么这是不受欢迎的做法,非常值得。

我从这个 Whosebug 评论中找到了答案: Rendering a view after form submission not working correctly in Rails 7