Search code examples
ruby-on-railsrailstutorial.org

How to build partial for 2 forms that have different url paths


I have two forms:

<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Save changes", class: "btn btn-primary" %>
    <% end %>

    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="http://gravatar.com/emails" target="_blank">change</a>
    </div>
  </div>
</div>

and

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user, url: signup_path) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

I need to create a partial, which I've done:

<%= form_for(@user) do |f| %>
  <%= render 'shared/error_messages', object: @user %>

  <%= f.label :name %>
  <%= f.text_field :name, class: 'form-control' %>

  <%= f.label :email %>
  <%= f.email_field :email, class: 'form-control' %>

  <%= f.label :password %>
  <%= f.password_field :password, class: 'form-control' %>

  <%= f.label :password_confirmation %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>

  <%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>

But there is a problem, which is that lines <%= form_for(@user) do |f| %> and <%= form_for(@user, url: signup_path) do |f| %> are slightly different - one passes a url to the form helper the other one not.

Section 10.1.1 from Rails tutorial suggests there is a way to do it using the provide method ("My suggestion is to use the variable-passing technique") but I couldn't find it. I've tried passing <% provide(:link, signup_path) and then <%= form_for(@user, url: yield(:link)) do |f| %> but it didn't work. This answer didn't provide the solution that Hartl would be looking for.

Thanks


Solution

  • One way to do it is to use an instance variable to let your partial know whether it should use the default path or signup_path.

    # In your controller's action, define the following instance variable only if you want form_for's url to be signup_path
    def whatever_action
      @replace_form_path = true
    end
    
    # In your view
    form_for(@user, (instance_variable_defined?(:@replace_form_path) ? {url: signup_path} : {})) do
    end