ruby-on-rails Rails 7 +器械未看到器械的 Flink 消息

dauxcl2d  于 2023-01-14  发布在  Ruby
关注(0)|答案(6)|浏览(187)

我有一个新的rails 7应用程序[rails new devisetest],一个简单的控制器,带有静态页面和添加的device [gem 'device' + rails g device user]。所有默认值。根据device说明添加Flash消息到应用程序。html.erb
Devise错误消息没有显示,但我看到它们在控制台中生成(或者至少,我看到呈现的消息,但它们没有显示,我看到呈现的_links部分,但确实显示)在另一个使用快速scaffold的测试中(将devise视图复制到应用中,但没有修改它们),flash消息显示scaffold,但仍然没有显示devise。
如果我访问http://localhost:3000/users/sign_up并使用太短的密码创建用户,我会在日志中看到此消息

Started POST "/users" for ::1 at 2021-12-24 08:02:10 +0000
Processing by Devise::RegistrationsController#create as TURBO_STREAM
  Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"email"=>"asdf@asdf.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
  TRANSACTION (0.1ms)  begin transaction
  User Exists? (2.7ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "asdf@asdf.com"], ["LIMIT", 1]]
  TRANSACTION (0.2ms)  rollback transaction
  Rendering layout layouts/application.html.erb
  Rendering /home/sroot/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/devise-4.8.1/app/views/devise/registrations/new.html.erb within layouts/application
  Rendered /home/sroot/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/devise-4.8.1/app/views/devise/shared/_error_messages.html.erb (Duration: 0.7ms | Allocations: 582)
  Rendered /home/sroot/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/devise-4.8.1/app/views/devise/shared/_links.html.erb (Duration: 0.2ms | Allocations: 92)
  Rendered /home/sroot/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/devise-4.8.1/app/views/devise/registrations/new.html.erb within layouts/application (Duration: 3.9ms | Allocations: 2199)
  Rendered layout layouts/application.html.erb (Duration: 77.5ms | Allocations: 4429)
Completed 200 OK in 473ms (Views: 78.7ms | ActiveRecord: 3.1ms | Allocations: 15288)

有谁能指出我的错误吗?或者建议我可以遵循的其他步骤来接近我的错误?
谢谢

qc6wkl3g

qc6wkl3g1#

我按照教程视频 https://gorails.com/episodes/devise-hotwire-turbo 以及尝试与本教程在这里:

  • 一个月一次 *

但是flash消息没有显示出来。我在我的device初始化器中添加了:

# config/initializers/devise.rb

class TurboFailureApp < Devise::FailureApp
  def respond
    if request_format == :turbo_stream
      redirect
    else
      super
    end
  end

  def skip_format?
    %w(html turbo_stream */*).include? request_format.to_s
  end
end

config.navigational_formats = ['*/*', :html, :turbo_stream]

config.warden do |manager|
  manager.failure_app = TurboFailureApp
  # manager.intercept_401 = false
  # manager.default_strategies(scope: :user).unshift :some_external_strategy
end

以及创建一个设备控制器:

# app/controllers/users/devise_controller.rb

class Users::DeviseController < ApplicationController
  class Responder < ActionController::Responder
    def to_turbo_stream
      controller.render(options.merge(formats: :html))
    rescue ActionView::MissingTemplate => error
      if get?
        raise error
      elsif has_errors? && default_action
        render rendering_options.merge(formats: :html, status: :unprocessable_entity)
      else
        redirect_to navigation_location
      end
    end
  end

  self.responder = Responder
  respond_to :html, :turbo_stream
end
643ylb08

643ylb082#

我也有同样的问题。这在某种程度上与Rails 7.0和Devise 4.8.1的兼容性有关。我无法注册用户。sqlite3数据库也仍然是空的,所以我认为这不仅仅是flash消息和用户没有被输入的问题。一些人通过在config/initializers/devise.rb中添加以下内容来解决Rails 7 / Devise的各种问题:

config.navigational_formats = ['*/*', :html, :turbo_stream]
cetgtptt

cetgtptt3#

如果你只是想让它“正常工作”,你可以在你的设计表单中添加data: { turbo: false },这样可以防止turbo用它的自动化功能劫持你的表单提交。
感谢john-999点击https://github.com/heartcombo/devise/issues/5446#issuecomment-1083485163
在我的例子中,我的视图/device/sessions/new.html.erb看起来像这样:

<%= form_for(resource, as: resource_name, url: session_path(resource_name), data: { turbo: false }) do |f| %>
      <% resource.errors.full_messages.each do |msg| %>
        <div><%= msg %></div>
      <% end %>

      <div class="mb-3">
        <%= f.label :email, class: "form-label" %>
        <%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control' %>
      </div>

      <div class="mb-3">
        <%= f.label :password, class: "form-label" %>
        <%= f.password_field :password, autocomplete: "current-password", class: 'form-control' %>
      </div>

      <div class="mb-4 mt-4">
        <%= f.submit t('.sign_in'), class: "btn btn-lg btn-primary" %>
      </div>
    <% end %>
t5zmwmid

t5zmwmid4#

我在config/initializers/devi.rb中添加了以下内容:

class TurboFailureApp < Devise::FailureApp
  def respond
    if request_format == :turbo_stream
      redirect
    else
      super
    end
  end

  def skip_format?
    %w(html turbo_stream */*).include? request_format.to_s
  end
end

内部设计。设置|配置|,这:

# ==> Navigation configuration
  # Lists the formats that should be treated as navigational. Formats like
  # :html, should redirect to the sign in page when the user does not have
  # access, but formats like :xml or :json, should return 401.
  #
  # If you have any extra navigational formats, like :iphone or :mobile, you
  # should add them to the navigational formats lists.
  #
  # The "*/*" below is required to match Internet Explorer requests.
  config.navigational_formats = ['*/*', :html, :turbo_stream]

  # ==> Controller configuration
  # Configure the parent class to the devise controllers.
  config.parent_controller = 'TurboController'

  # ==> Warden configuration
  config.warden do |manager|
    manager.failure_app = TurboFailureApp
  end

然后我在app/controllers/turbo_controller.rb中创建了一个控制器,它是这样的:

class TurboController < ApplicationController
  class Responder < ActionController::Responder
    def to_turbo_stream
      controller.render(options.merge(formats: :html))
    rescue ActionView::MissingTemplate => error
      if get?
        raise error
      elsif has_errors? && default_action
        render rendering_options.merge(formats: :html, status: :unprocessable_entity)
      else
        redirect_to navigation_location
      end
    end
  end

  self.responder = Responder
  respond_to :html, :turbo_stream
end
bis0qfac

bis0qfac5#

我认为最好的答案是Alex Flash is not displayed in the same view in Rails
再一次是亚历克斯Rails 7 signup form doesn't show error messages
这在没有设计的情况下也是如此,错误消息数组属于活动记录,并与模型中验证失败的活动记录@用户对象相关联,该对象继承自ApplicationRecord和ActiveRecord,而不是设计。即使您从头创建了用户模型、控制器、视图和所有操作,当模型中验证失败时,错误消息仍然存在。还没有显示在视图中。甚至flash消息也没有显示。而是在你的控制器中如果用户保存失败,那么,在else语句中重定向到requestreferrer,并显示flash错误消息,可能像redirect_to request.referrer, flash: {error: @user.errors.full_messages},在create user方法或update中,但错误消息似乎不会显示您是否正在渲染回新操作,除非服务器响应为422,因此您可以与scaffolds render 'new', status: :unprocessable_entity, flash: {error: @user.errors.full_messages}执行相同操作,这会导致服务器响应为422,这将起作用。如果@user保存在数据库中,这也适用于成功消息。或更新,您可以只显示redirect_to user_url(@user), notice: " user was successfully created / updated."
您会注意到在浏览器控制台中,如果您使用无效字段注册,您将不会收到错误full_messages,并且您会注意到您的浏览器控制台显示:Error: Form responses must redirect to another location,即如果要渲染回新操作,如果对象在创建操作中保存失败。
看起来如果你去application.html.erb并删除<%= javascript_importmap_tags %>,保存文件并尝试用无效字段注册,你会得到所有的@user.errors.full_messages键和值。这不是一个解决方案。
或者最好不用javascript_importmap_tags,你可以在你的form_with中添加data: { turbo: false }。但仍然不是一个可持续的解决方案。
或者像其他人建议的那样,如果你正在使用devise在initializers.rb中注册用户,你可以添加config.navigational_formats = ['*/*', :html, :turbo_stream]

vawmfj5a

vawmfj5a6#

目前,正确的做法是“塞布丽娜的答案”。下面是一些可以做的事情:

把它放在一个框架里

请先执行以下操作:

# config/initializers/devise.rb

config.navigational_formats = ['*/*', :html, :turbo_stream]

现在表单在验证错误时呈现200,它应该是422。如果我们在turbo帧中工作,这将不是一个问题。
复制application.html.erb布局并将其重命名为devise.html.erb

cp app/views/layouts/application.html.erb app/views/layouts/devise.html.erb

将其 Package 在框架中:

<!-- app/views/layouts/devise.html.erb -->

<!DOCTYPE html>
<html>
  <head> <%= render "layouts/head" %> </head>
  <body>
    <main class="container px-5 mx-auto mt-28">

      <!-- turbo action `advance` to update the url     vvvvvvvv     -->
      <%= turbo_frame_tag :login, data: { turbo_action: :advance } do %>

        <% if alert.present? %>
          <p class="p-3 text-red-500 bg-red-50"> <%= alert %> </p>
        <% end %>
        <%= yield %>

      <% end %>

    </main>
  </body>
</html>

这本身并不起作用,因为响应现在没有布局渲染,并且我们正在丢失:login帧。更新您的控制器以修复它:

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  layout -> { devise_controller? ? "devise" : (false if turbo_frame_request?) }
end

更新路由,使每个 POST 路由都有一个 GET 路由:

devise_scope :user do
  get "/users",          to: redirect("/users/sign_up")
  get "/users/password", to: redirect("/users/password/new")
end

或者,不要使用turbo_action: :advance并跳过额外的路由。您可以更新链接框架目标以在框架之外导航:

# app/views/devise/shared/_links.html.erb

<% if controller_name != 'sessions' %>
  <%= link_to "Log in", new_session_path(resource_name), data: { turbo_frame: :_top } %><br />
<% end %>

<% if devise_mapping.registerable? && controller_name != 'registrations' %>
  <%= link_to "Sign up", new_registration_path(resource_name), data: { turbo_frame: :_top } %><br />
<% end %>

# ...

或者只是编辑模板并将这些链接放在框架之外。

DIY打底

第二个想法有点问题,我只是想看看它是否可行。

# still need this bit
config.navigational_formats = ['*/*', :html, :turbo_stream]

问题是 turbo 拒绝呈现200表单响应,而我们实际上收到了该响应。
我的意思是我们已经有了响应,所以还是渲染它吧:

// app/(assets/)?javascript(s)?/devise.js
document.addEventListener("turbo:before-fetch-response", async (event) => {
  event.preventDefault();
  const response = new DOMParser().parseFromString(await event.detail.fetchResponse.responseHTML, "text/html")
  document.body.replaceWith(response.body)
})

// add to devise layout, your favorite javascript (include|pack|import_module) tag
<%= javascript_include_tag "devise" %>

// turbo frame and controller layout override are not needed

登录正常。注册正常。链接导航和url更新。表单提交不更新url,这是完美的(这里不需要支持表单提交后刷新)。

相关问题