В рельсах Turbo просто хлопает ответом сервера в конце текущей страницы.

Проблема: Турбо просто захлопывает ответ от сервера до конца текущей страницы. Не заменяет страницу, как ожидалось.

Недавно обновился с Rails 6 до 7. Также я переключился с importmap на esbuild.

У меня есть форма, которая отправляет сообщение в метод создания. Контроллер отвечает

  if @stamp.save       
        redirect_to stamps_path, notice: "Input saved"
      else

Странная вещь, которая происходит, заключается в том, что ответ добавляется к нижней части исходного кода сверху. Таким образом, в конце исходного кода добавляется новый заголовок из ответа, например

<...> The whole initial html <...>
</body>
<title>Page title</title> <-- The server response gets appended after </body>
<meta .... the whole page gets repeated again

Не совсем уверен, что вам здесь показать, копался во всех настройках и т. д. Я никогда не видел, чтобы Turbo вел себя так с ответами.

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

ruby "3.1.2"
gem "rails", "~> 7.0.2", ">= 7.0.2.4"
gem "sprockets-rails"
gem "puma", "~> 5.6"
gem "haml-rails", "~> 2.0"
gem "sqlite3", "~> 1.4"
gem 'devise', '~> 4.8'
gem 'devise-i18n', '~> 1.10'
gem "turbo-rails"
gem "jsbundling-rails", "~> 1.0"
gem 'sass-rails'
gem "stimulus-rails"
gem 'rubyXL', '~> 3.3'
gem "jbuilder"
gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
gem 'kaminari', '~> 1' # pagination gem
gem "bootsnap", require: false

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

group :development do
  gem "web-console"
end

group :test do
  gem "capybara"
  gem "selenium-webdriver"
  gem "webdrivers"
end

{
  "private": true,
  "license": "ISC",
  "name": "name",
  "version": "0.1.0",
  "scripts": {
    "release": "npm run build && npm run publish",
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^6.1.2",
    "@fortawesome/free-brands-svg-icons": "^6.2.0",
    "@fortawesome/free-solid-svg-icons": "^6.1.2",
    "@hotwired/stimulus": "^3.1.0",
    "@hotwired/turbo-rails": "^7.2.5",
    "@popperjs/core": "^2.11.5",
    "@rails/activestorage": "^6.0.0",
    "bootstrap": "^5.2.0",
    "esbuild": "^0.17.7"
  }
}

Я пытался воспроизвести другое приложение для рельсов, которое у меня есть, используя Turbo. Изучил все настройки и т. д. Другие страницы могут использовать redirect_to и заменять содержимое, как и ожидалось. Я использую haml, поэтому HTML-структура должна быть в порядке.

Типы данных JavaScript
Типы данных JavaScript
В JavaScript существует несколько типов данных, включая примитивные типы данных и ссылочные типы данных. Вот краткое объяснение различных типов данных...
Как сделать движок для футбольного матча? (простой вариант)
Как сделать движок для футбольного матча? (простой вариант)
Футбол. Для многих людей, живущих на земле, эта игра - больше, чем просто спорт. И эти люди всегда мечтают стать футболистом или менеджером. Но, к...
Знайте свои исключения!
Знайте свои исключения!
В Java исключение - это событие, возникающее во время выполнения программы, которое нарушает нормальный ход выполнения инструкций программы. Когда...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
Введение в раздел &quot;Заголовок&quot; в HTML
Введение в раздел "Заголовок" в HTML
Говорят, что лучшее о человеке можно увидеть только изнутри, и это относится и к веб-страницам HTML! Причина, по которой некоторые веб-страницы не...
1
0
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я могу представить только один способ, которым это могло бы произойти: у вас есть шаблон show.erb. Просто переименуйте его в show.html.erb (или .haml, .slim, не важно).


По умолчанию формы отправляются как TURBO_STREAM, это то, что показывает rails в логах, однако это не вся картина. Форма отправки запроса устанавливает Accept заголовок:

Accept: text/vnd.turbo-stream.html, text/html, application/xhtml+xml
#       ^
# here is where `TURBO_STREAM` comes from

Это ответы Content-Type, которые турбо ожидает получить. Когда вы используете блок respond_to в действиях контроллера, заголовок Accept определяет, какой блок format вызывать:

respond_to do |format|
  if @model.save(model_params)
    # if you have turbo_stream, it will run first
    # format.turbo_stream { render turbo_stream: turbo_stream.replace(model) }
    # if you don't have turbo_stream, next format in `Accept` header is html
    format.html { redirect_to model_url(@model) }
    format.json { render :show, status: :ok, location: @model }
    # if nothing matches, you get `ActionController::UnknownFormat` error.
    # the one you get when trying to render `format.js`, but Turbo 
    # doesn't handle js format, so it doesn't send `Accept: text/javascript`
  else
    format.html { render :edit, status: :unprocessable_entity }
    format.json { render json: @model.errors, status: :unprocessable_entity }
  end
end

Когда вы используете блок respond_to, рельсы автоматически устанавливают некоторые параметры рендеринга, одним из которых является :content_type, который, в свою очередь, устанавливает заголовок ответа Content-Type. Поэтому, если блок format.html запускается, он устанавливает Content-Type: text/html, какой турбо знает, как обрабатывать, перенаправляя или заменяя содержимое страницы.

Важно то, что мы перешли от формата turbo_stream к html. Излишне говорить, что html должен отображать ответ, выглядящий как html, а turbo_stream должен быть тегом <turbo-stream>.

Что происходит, когда вы не используете блок respond_to. Rails попытается отобразить шаблон, соответствующий формату. Например, запрос turbo_stream будет искать show.turbo_stream.erb, затем show.html.erb, а затем show.erb, например:

render :show, formats: [:turbo_stream, :html]

Допустим, он находит show.html.erb, потому что присутствует расширение html, rails установит для ответа Content-Type значение text/html, и все будет работать как положено.

Однако, если он находит show.erb, нет ничего, что указывало бы на то, что он в формате html, мы не использовали блок respond_to, поэтому ответ Content-Type не задан явно, единственный оставшийся вариант — вернуться к первому типу Accept, который является turbo_stream. Теперь вы рендерите html-шаблон, но тип ответа — turbo_stream, а тега <turbo-stream> нет.

Когда turbo видит ответ turbo_stream, он добавляет его к документу, что вы и видите. Поскольку инструкций <turbo-stream> нет, он просто остается нетронутым.


Короче говоря, что-то по пути должно установить правильный тип контента.

Либо используйте блок respond_to, который установит необходимые параметры рендеринга. Или установите параметры рендеринга самостоятельно: content_type: "text/html". Или сообщите рельсам тип контента, используя расширения html.erb и turbo_stream.erb.

Обратите внимание, что при перенаправлении тип содержимого turbo_stream остается, потому что turbo обрабатывает перенаправление на внешнем интерфейсе. Если в действии show нет расширения html.erb и блока respond_to, вы получаете несоответствие типа контента.

О боже, я люблю тебя .. Это было НАИЛУЧШИМ решением и лучшим образованием, которое я мог получить.

JUlinder 16.02.2023 13:09

Другие вопросы по теме