ruby-on-rails Rails重定向错误:Uncaught(in promise)错误:响应(200)不包含预期的〈turbo-frame id=“tweet_1”并且将被忽略...

dnph8jn4  于 2023-04-22  发布在  Ruby
关注(0)|答案(1)|浏览(142)

在我正在构建的应用程序中,当用户点击“回复”部分时,他们将被重定向到“显示”页面,看起来像这样:

<%= link_to tweet_path(tweet_presenter.tweet), class: "text-decoration-none text-black replies" do %>
  <%= image_tag "speech.png", size: "20x20", class: "me-1" %>
  <span>Replies<span>
 <% end %>

...并形成视图部分(_tweet.html.erb)的一部分,该视图部分包含在turbo_frame中,该turbo_frame打开为:<%= turbo_frame_tag dom_id(tweet_presenter.tweet) do %>
然而,重定向并没有发生。相反,我得到了以下错误消息:
Uncaught (in promise) Error: the response (200) did not contain the expected <turbo-frame id=“tweet_1” and will be ignored…
我已经通过运行rails routes检查了link_to tweet_path(tweet_presenter.tweet)路径是否正确,并获得以下结果:
tweet GET /tweets/:id(.:format) tweets#show
控制台的输出显示正在访问正确的tweet_id,尽管错误消息是:

Started GET "/tweets/1" for ::1 at 2023-04-10 15:53:46 -0700
Processing by TweetsController#show as HTML
  Parameters: {"id"=>"1"}
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/application_controller.rb:2:in `block in <class:ApplicationController>'
  Tweet Load (0.3ms)  SELECT "tweets".* FROM "tweets" WHERE "tweets"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/tweets_controller.rb:5:in `show'
  Rendering layout /Users/doracobian/.rvm/gems/ruby-3.1.1/gems/turbo-rails-1.4.0/app/views/layouts/turbo_rails/frame.html.erb
  Rendering tweets/show.html.erb within layouts/turbo_rails/frame
  Rendered tweets/show.html.erb within layouts/turbo_rails/frame (Duration: 44.9ms | Allocations: 762)
  Rendered layout /Users/doracobian/.rvm/gems/ruby-3.1.1/gems/turbo-rails-1.4.0/app/views/layouts/turbo_rails/frame.html.erb (Duration: 46.0ms | Allocations: 853)
Completed 200 OK in 52ms (Views: 46.8ms | ActiveRecord: 0.5ms | Allocations: 2490)

...查看开发人员工具中的“元素”,我再次看到turbo-frame#tweet_1,与错误消息告诉我的内容相矛盾。
怎么回事?我一直在绕圈子想弄明白。
对于那些不辞辛劳地研究我这个困惑的人来说,下面是routes.rb的相关部分:

resources :tweets, only: [:show, :create] do
    resources :likes, only: [:create, :destroy]
    resources :bookmarks, only: [:create, :destroy]
    resources :retweets, only: [:create, :destroy]
  end

... tweets_controller.rb的“show”部分:

def show
    @tweet = Tweet.find(params[:id])
  end

非常感谢任何关于这方面的投入。

bqucvtff

bqucvtff1#

帧总是会在那里,不管你得到什么作为响应。如果有一个帧与相同的id在响应中比它将被更新,如果不是,你会得到帧丢失错误。要查看你实际上得到的响应,你必须看看网络选项卡:
https://stackoverflow.com/a/75916578/207090
如果你在索引页上有这个,请先说明一下:

<!-- app/views/tweets/index.html.erb -->

<turbo-frame id="new_tweet">
  <a href="/tweets/new">New tweet</a>
</turbo-frame>

然后,您需要在请求或重定向到的页面上使用相同的框架:

<!-- app/views/tweets/new.html.erb -->

<turbo-frame id="new_tweet">
  <form  action="/tweets"  method="post">
    <textarea name="tweet[content]"></textarea>
    <input type="submit" name="commit" value="Create Tweet">
  </form>
</turbo-frame>

据我所知,你的turbo帧是在_tweet.html.erb部分,我没有看到部分被渲染从你的show页面。
这是我的tweetster克隆。在一个框架中从索引页面创建新的tweet,然后用turbo流插入新创建的tweet。回复和回复上的回复也是一样的,它永远有效。
也有这么多的方法来设置这个,这只是一个想到的。

# db/migrate/20230413231722_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[7.0]
  def change
    create_table :tweets do |t|
      t.text :content
      t.references :tweet
    end
  end
end

# app/models/tweet.rb
class Tweet < ApplicationRecord
  validates :content, presence: true
  has_many :replies, class_name: "Tweet", dependent: :destroy
  belongs_to :tweet, optional: true
  def reply?
    tweet_id.present?
  end
end

# config/routes.rb
resources :tweets do
  get :reply, on: :member
end

你几乎可以忽略这个控制器,我只在create中添加了reply action和turbo_stream format,因为在tweet创建之后,我们就完成了框架,我们必须从它中进行大的逃脱:

# app/controllers/tweets_controller.rb

class TweetsController < ApplicationController
  def index # GET /tweets
    @tweets = Tweet.where(tweet_id: nil) # ignore replies
  end

  def new  = tweet # GET /tweets/new
  # show and edit are not used
  def show = tweet # GET /tweets/1
  def edit = tweet # GET /tweets/1/edit

  def reply # GET /tweets/1/reply
    render partial: "form", locals: {tweet: tweet.replies.new}
  end

  def create # POST /tweets
    respond_to do |f|
      if tweet(tweet_params).save
        # NOTE: render `create.turbo_stream.erb` where we'll handle some
        #       things regarding turbo_frame
        f.turbo_stream
        f.html { redirect_to tweet_url(tweet), notice: "Saved." }
      else
        f.html { render tweet.new_record? ? :new : :edit, status: 422 }
      end
    end
  end
  alias_method :update, :create # PATCH/PUT /tweets/1

  def destroy # DELETE /tweets/1
    tweet.destroy
    respond_to do |f|
      f.turbo_stream { render turbo_stream: turbo_stream.remove(tweet) }
      f.html { redirect_to tweets_url, notice: "Destroyed." }
    end
  end

  private

  def tweet attributes = {}
    @tweet ||= begin
      model = params[:id] ? Tweet.find(params[:id]) : Tweet.new
      model.attributes = attributes
      model
    end
  end

  def tweet_params = params.require(:tweet).permit!
end
# app/views/tweets/index.html.erb
<%= link_to "New tweet", new_tweet_path, data: {turbo_frame: :new_tweet} %>
<%= turbo_frame_tag :new_tweet %>
<%= tag.div id: :tweets, class: "grid gap-4 mt-4" do %>
  <%= render @tweets.order(id: :desc) %>
<% end %>

# app/views/tweets/new.html.erb
<%= render "form", tweet: @tweet %>

# app/views/tweets/_form.html.erb
<%# NOTE: figure out correct turbo frame id for replies and tweets %>
<% frame_id = tweet.reply? ? dom_id(tweet.tweet, :new_reply) : dom_id(tweet) %>
<%= turbo_frame_tag frame_id do %>
  <%= form_with model: tweet, class: {"ml-8": tweet.reply?} do |f| %>
    <%= tag.div safe_join(f.object.errors.full_messages, tag.br), class: "text-red-500" if f.object.errors.any? %>
    <%= f.hidden_field :tweet_id %>
    <%= f.text_area :content, placeholder: (tweet.reply? ? "reply..." : "new tweet..."), class: "rounded-xl w-full" %>
    <%= f.button "Save", class: "font-bold" %>
  <% end %>
<% end %>

# app/views/tweets/_tweet.html.erb
<%= tag.div id: dom_id(tweet), class: ["grid gap-4", {"ml-8": tweet.reply?}] do %>
  <%= tag.div class: "flex justify-between rounded-xl shadow border p-4" do %>
    <%= tweet.content %>
    <%= tag.div class: "flex gap-2" do %>
      <%= link_to "reply", reply_tweet_path(tweet), data: {turbo_frame: dom_id(tweet, :new_reply)} %>
      <%= button_to "delete", tweet_path(tweet), method: :delete, class: "hover:text-red-500" %>
    <% end %>
  <% end %>
  <%= turbo_frame_tag dom_id(tweet, :new_reply), class: "contents" %>
  <%= tag.div id: dom_id(tweet, :replies) do %>
    <%= render tweet.replies %>
  <% end %>
<% end %>

# i'm only using tag.div for syntax highlight for SO (erb + html tags don't mix well)

这可能是你需要在框架之外做事情的主要部分,也许用不同的框架替换框架,也许在某个地方附加一个闪光灯警报,等等:

# app/views/tweets/create.turbo_stream.erb

<%# there is probably a way to make it the same for tweets and replies %>
<% if @tweet.reply? %>
  <% parent_tweet = @tweet.tweet %>
  <%= turbo_stream.update dom_id(parent_tweet, :new_reply) %>
  <%= turbo_stream.append dom_id(parent_tweet, :replies), @tweet %>
<% else %>
  <#% this v is for tweets and same ^ for replies %>

  <%# NOTE: this `update` will remove content from turbo_frame %>
  <%#       but you can add whatever updates you need here     %>
  <%= turbo_stream.update :new_tweet %>

  <%# NOTE: this will add new tweet to `<div id="tweets">` %>
  <%= turbo_stream.prepend :tweets, @tweet %>
<% end %>

如果你想“只是”重定向出框架:
https://stackoverflow.com/a/75750578/207090

相关问题