rails: Rails 7.1: incorrect path when submitting form for a singular resource
Steps to reproduce
When submitting a form with an error, Rails 7.1 redirects to incorrect path when the resource is singular. This may be an issue with Turbo (see expected and actual behaviors below).
# frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Activate the gem you are reporting the issue against.
gem "rails", "~> 7.1.0"
gem "sqlite3"
end
require "active_record"
require "minitest/autorun"
require "logger"
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :authors, force: true do |t|
t.string :name
end
end
class Author < ActiveRecord::Base
validates :name,
format: { with: /\A[a-zA-Z0-9-]{0,39}\z/, message: 'can only contain alphanumeric characters and dashes' },
length: { maximum: 39 }
end
require "rack/test"
require "action_controller/railtie"
class TestApp < Rails::Application
config.root = __dir__
config.hosts << "example.org"
config.session_store :cookie_store, key: "cookie_store_key"
config.secret_key_base = "secret_key_base"
config.logger = Logger.new($stdout)
Rails.logger = config.logger
routes.draw do
resource :author, only: %i[edit update]
end
end
class AuthorsController < ActionController::Base
include Rails.application.routes.url_helpers
before_action :set_author, only: %i[edit update]
def edit; end
def update
if @author.update(author_params)
redirect_to edit_author_path
else
render :edit, status: :unprocessable_entity
end
end
private
def set_author
@author = Author.find(1) # Actual application would use session to find author logged in
end
def author_params
params.require(:author).permit(:name)
end
end
class BugTest < Minitest::Test
include Rack::Test::Methods
Author.create!(name: 'name')
def test_author_updated_success
patch '/author', { author: { name: 'validName' } }
assert_equal 'http://example.org/author/edit', last_response.headers['location']
end
def test_author_updated_failure
patch '/author', { author: { name: 'invalid!!!name?' } }
assert_equal 'http://example.org/author/edit', last_response.headers['location']
end
private
def app
Rails.application
end
end
Expected behavior
The request path should be author/edit
.
The console in Rails 7.0.8 showed
Started PATCH "/author" for 127.0.0.1 at 2023-10-12 09:22:13 -0400
Processing by AuthorsController#update as TURBO_STREAM
Actual behavior
The request path is author/#{author.id}”
.
The console in Rails 7.1.0 shows
Started PATCH "/author.1" for 127.0.0.1 at 2023-10-12 09:21:10 -0400
Processing by AuthorsController#update as */*
System configuration
Rails version: 7.1.0
Ruby version: 3.2.2
About this issue
- Original URL
- State: open
- Created 9 months ago
- Comments: 30 (20 by maintainers)
Thank you @eizengan.
I’ve decided to open this back up for the time being given that the nested resources will not work with resolve.
As I noted above we do have it documented for how to use
resource
non-nested. However using nested resources is a popular use case and I think adding support for this will be beneficial to the framework.I tested this locally.
In
routes.rb
bothand
Result in:
My PR #49889 addresses and fixes both use cases, nested or not.
Understood, but there appear to be two competing philosophies here:
polymorphic_path
resolve
when necessary/appropriate, now exposed by enhancements to underlying infrastructureMy comment regarding there being no working path for nested singular resources is aimed at fixes adhering to the latter, not the former
I don’t have the context to say whether that’s the best approach, but to restore parity with pre-7.1 behavior we would also need to make
resolve
work with nested singular resources. Given that this is specifically called out in the docs (the NOTEs on my earlier comment) I suspect that could be a nontrivial enhancementSo I was informed by Rafael that my implementation was not a viable solution. So anyone can feel free to open other PRs to fix this! I’ll try again as well, time permitting.
Thanks for your input. My PR doesn’t use resources. I tested your use case and it works fine in my suggested fix linked in the above PR.
Thank you @jhawthorn! Using
resolve
works on my end.Yes, I thought I clarified that in my comment above after he chimed in?
Great! Thanks for taking the time to look into this.