[Feature Request] - pass context through yield/content_for

Lets say for example if I wanted to create a form partial/layout where views can add additional inputs:

<%= form_with(model: thing) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_input :name %>
  </div> 
  <%= yield %>
<% end %>

What I would like to be able to do is pass the variable f to the block just like we can do with the yield keyword:

def foo(bar, &block)
   yield bar
end

Which would let me do:

<%= render partial: 'form' do |f| %>
  <div class="field">
     <%= f.number_input :woozyness %>
  </div>
<% end %>

Does this make sense as a feature request? Am I missing some obvious reason why this wouldn’t work? How would it best be implemented - as a locals: option or as splat arguments following the name of the yield?

I have done this plenty of times, using a JavaScript function to add the additional item. I used to try to do what I think you’re describing here, and I found I could pass in the f variable in the locals collection. That works fine, even if it is a little tortured-looking.

Now that I have made my client swear off of using IE, I can use the template tag instead, this works all in one layer, and I don’t need to worry about rendering a partial in an Ajax callback.

        <div data-controller="nested-form" class="nested-form">
          <template data-target='nested-form.template'>
            <%= form.fields_for :sources, @title.sources.build, child_index: 'TEMPLATE_RECORD' do |sources| %>
            <%= render 'sources/form', form: sources %>
            <%- end -%>
          </template>

          <%= form.fields_for :sources do |sources| %>
          <%= render 'sources/form', form: sources %>
          <%- end -%>

          <div data-target="nested-form.add_item" class="form-group">
            <%= link_to "Add Source", "#", class: 'btn btn-outline-secondary', data: { action: "nested-form#add_association" } %>
          </div>
        </div>

The NestedFormController could not be simpler (apologies for the jQuery):

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = ["add_item", "template"]
  
  connect(){
    $(this.element).find('.position').each(function(idx, elm){
      $(elm).val(idx + 1);
    });
  }

  add_association(event) {
    event.preventDefault();
    var content = this.templateTarget.innerHTML.replace(/TEMPLATE_RECORD/g, new Date().valueOf());
    this.add_itemTarget.insertAdjacentHTML('beforebegin', content);
    $(this.element).find('.position').each(function(idx, elm){
      $(elm).val(idx + 1);
    });

  }

  remove_association(event) {
    event.preventDefault();
    let item = event.target.closest(".nested-fields");
    item.querySelector("input[name*='_destroy']").value = 1;
    item.style.display = 'none';
  }
}

Hope this helps!

Walter