-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle nil form_with model argument #49943
Handle nil form_with model argument #49943
Conversation
affd40d
to
16eb00d
Compare
@rafaelfranca when we were talking about issues that beginners face at Rails World, this is one of the most common we've seen. Instance variables returning |
16eb00d
to
dce5421
Compare
dce5421
to
706daa6
Compare
a39af63
to
c5ed86e
Compare
78f020c
to
8c5ebdc
Compare
I was under the impression that when I think the PR is great but the functionality would only apply to |
@excid3 I completely agree with the instance variable headaches for beginners. It's one of the reasons we developed decent_exposure. It encapsulates what they're trying to do with an instance variable into a view helper. Since it gets turned into an actual method, Ruby gives way more help with things like a typo. |
@mattpolito - Hey there!
This change still allows that functionality. This is handling when you make a call something like
Thanks! I'm glad you like the PR. I don't know that I agree with you on moving it to |
@cjilbert504 I just mean not passing |
@mattpolito - It definitely is a valid use-case which is why I didn't want to break that existing functionality. Thanks for chiming in on this one! |
The rails/actionview/lib/action_view/helpers/form_helper.rb Lines 602 to 603 in 8c5ebdc
This also makes
|
8c5ebdc
to
12b093d
Compare
rails/rails#49943 `form_with` cannot have `model: nil` anymore. Make sure to set `@session` if no `authenticable` can be found.
rails/rails#49943 `form_with` cannot have `model: nil` anymore. Make sure to set `@session` if no `authenticable` can be found.
This sounds like a breaking change, which we try to guarantee to users that they will see one minor version with a deprecation notice. Could we change this |
@jhawthorn - If that's what you all would like to happen here, I'm happy to do so. If that's the case, I will try to get to it ASAP. Thanks for the feedback/thoughts here! |
Yes. Let's deprecate it. |
Copy that! I think I'll have some time on Monday or Tuesday that I can take care of it if that's cool. |
FYI @cjilbert504 an example of where this would break would be if you have a custom form helper that calls # Renders a Rails form, enhanced with Turbo attributes. Specifically:
# - Connects the form to the Form stimulus controller.
# - Calls Form#submitStart when the form is submitted.
# - Targets the "_top" turbo frame (ie. the full page) if no frame is provided.
#
# Accepts the same arguments as +form_with+: https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
# You can provide Stimulus options using the `stimulus` keyword. See the +stimulus+ method for options.
def turbo_form_with(model: nil, scope: nil, url: nil, format: nil, stimulus: {}, turbo_frame: nil, **options, &block)
form_with(model: model, scope: scope, url: url, format: format, builder: TurboFormBuilder, **form_options, &block)
end The fix is easy, but we should warn before we raise. diff --git a/app/helpers/turbo_view_helper.rb b/app/helpers/turbo_view_helper.rb
index 123b64f6458..c413875ad29 100644
# Accepts the same arguments as +form_with+: https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
# You can provide Stimulus options using the `stimulus` keyword. See the +stimulus+ method for options.
- def turbo_form_with(model: nil, scope: nil, url: nil, format: nil, stimulus: {}, turbo_frame: nil, **options, &block)
+ def turbo_form_with(model: false, scope: nil, url: nil, format: nil, stimulus: {}, turbo_frame: nil, **options, &block)
form_with(model: model, scope: scope, url: url, format: format, builder: TurboFormBuilder, **form_options, &block)
end |
@ghiculescu - Yep, I understand that it would break as of this PR. I'm going to work on deprecating first as soon as I can. Thanks a bunch! |
@jhawthorn @rafaelfranca - Sorry I'm just getting back to wrapping this up (was sick and had power outages due to bad weather). Anyway, I wanted to ask about wrapping this up, would you all like me to make a new branch/PR to undo this and swap to the deprecation warning or just use this same branch and undo and swap to the deprecation warning? |
It would need to be a new branch/PR. |
Perfect, because that’s what I did already 🤣. But wanted to confirm first. Thanks, @rafaelfranca |
@p8 @jhawthorn @rafaelfranca - I opened #50931 to resolve the issue of this PR introducing breaking changes. Let me know if I need to change anything about it and I will happily do so. Thank you all very much! |
Rails main changed `object` to be `false` instead of `nil`, causing the specific check we were doing for `object.nil?` to fail, and the custom errors were not displaying for forms without an object. Our test suite caught that, and the fix is to simply not check specifically for `nil?`, but just whether we have an object or not, which should account for both `nil`/`false` versions. It's a small backwards incompatibility, probably not something worth changing the framework for, but one worth mentioning. Source is likely to be: - rails/rails#49943 - rails/rails#50931
Motivation / Background
First, thank you to everyone here for taking the time to read this description.
I would like to propose a possible change to the
form_with
method which would help provide, in my opinion, better debugging around an issue that can be encountered when passing anil
object to themodel:
argument in theform_with
method.I have come across this issue a few times myself and I know others that have as well. The most recent encounter was from a newer Rails developer that myself and others have been helping along in the process of learning Rails.
The issue actually shows up in two ways, the first is if the form is on an index page, having nil passed to the
:model
argument this will raise anActionController::ParameterMissing
error. The other is in the default scenario of being on the new page and havingnil
passed to the:model
argument. In this scenario, anActionController::RoutingError (No route matches [POST] "/posts/new")
(usingPost
model as an example). This happens because of Rails falling back to building the URL from the current page in this scenario.Going back to the first form of this causing an error, I would like to outline the flow of the issue so that everyone can (hopefully) have a better understanding of this issue.
Junior Dev: I'm having an issue using strong parameters. Has there been a change in rails 7 when using strong parameters?
where the model name is UrlLink. When I try to submit my form, I get the following error:
When I remove require and just use params.permit(:url), I can submit the form.
I'm confused, I setup my form with
form_with(model: url_link)
and have a url input fieldform.url_field :url
.Me: I see that you have a mismatch in instance variable naming between the instance variable declared in the controller action versus what is being passed in as a local to the form partial:
Junior Dev: Thanks, I fixed the mismatch and my form and controller are working now.
With this context, I think it would have been a better debugging experience for the junior if instead of the
ActionController::ParameterMissing
error being raised thus causing the junior to think it was a strong params issue (which it sort of is I admit) I think it would be more helpful to raise anArgumentError
when passing in anil
object to themodel:
argument inform_with
.Detail
This PR changes the default value of the
model:
argument inform_with
tofalse
instead ofnil
and raises anArgumentError
in the event that the argument isnil
.I tried to think reasons/scenarios of why/where
false
wouldn't be a suitable replacement fornil
as the default value for themodel:
argument but I couldn't think of any (I'm not saying there isn't a case though and would love to hear so if there are any).It also changes a local variable that is set in a case statement in the
form_for
method fromnil
tofalse
which is needed to allowform_for
to continue to callform_with
successfully.Additional information
Thank you for taking the time to read this and for any thoughts or feedback about it.
Checklist
Before submitting the PR make sure the following are checked:
[Fix #issue-number]