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
我对 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