1

I have a model to be fill with a form, consisting of a title and a body of text. Optionally, I want the ability to submit a link as well as a part of this model. If this is filled out, it is submitted, otherwise ignored. The form would have title and body fields at top of page, for instance.

<%= form_for(@micropost, remote: true) do |f| %>
  <div class="field">
    <%= f.text_field :title %>
    <%= f.text_area :content %>
  </div>
  <%= f.submit "Post" %>
<% end %>

Now, I want to add the field for the link, but in a different location on the page (so as to indicate that it is optional).

    <%= f.text_field :link %>

I tried doing this all in one partial,

<%= form_for(@micropost, remote: true) do |f| %>
  <div class="field">
    <%= f.text_field :title %>
    <%= f.text_area :content %>
    <! insert other content here >
    <%= f.text_field :link %>
  </div>
  <%= f.submit "Post" %>
<% end %>

But this would lead to very messy nesting of partials and I'm not sure how to get this to work correctly. Alternatively, I was wondering if it was possible to have one form_for at the top of the page, and another form_for at the bottom of the page that are somehow "synced", so that by pressing the submit button at the top, the value entered in the bottom form_for is collected and submitted as well.

<%= form_for(@micropost, remote: true) do |f| %>
  <div class="field">
    <%= f.text_field :title %>
    <%= f.text_area :content %>
  </div>
  <%= f.submit "Post" %>
<% end %>

<%= form_for(@micropost, remote: true) do |f| %>
   <! somehow sync this with the other form >
   <%= f.text_field :link %>
<% end %>

nicole
  • 71
  • 6

3 Answers3

3

One option is to have an auxiliary text field for link attribute. Copy it's value to hidden variable mapping the link attribute

Assuming you are going to use jQuery,

<%= form_for(@micropost, remote: true) do |f| %>
  <%= f.hidden_field :link %>
  <div class="field">
    <%= f.text_field :title %>
    <%= f.text_area :content %>
  </div>
  <%= f.submit "Post" %>
<% end %>

Somwhere on the same page

<%= text_field_tag 'micropost[link]', '', id: 'aux_link' %>

<script>
  $(function(){
    $('form').on('submit', function(){
      $('#micropost_link').val($('aux_link'));
    });
  });
<script>

This is just an approach. Adjust code as per your form element ids.

One issue with this approach is it will be difficult to validate if link attribute is compulsory.

Amit Patel
  • 15,609
  • 18
  • 68
  • 106
1

I found here that the canonical way to do this is to use the "form" attribute. Give the form an id, from which the field can refer back to the form, even if the field is placed outside of the form. For instance,

<%= form_for(@micropost, remote: true, html: { id: "micropost_form" }) do |f| %>
   <div class="field">
      <%= f.text_field :title %>
      <%= f.text_area :content %>
   </div>
   <%= f.submit "Post" %>
<% end %> 

We can then use fields_for to place the desired field elsewhere, linking back to the original form.

<%= fields_for @micropost do |f| %>
  <%= f.text_field :link, form:"micropost_form" %>
<% end %>
nicole
  • 71
  • 6
0

Just make the form_for be the root of the view

You can just use the form_for like a container div.
Then put the <input> and <button> as you want like making your normal webpage.

Then, because you want to make some inputs optional, you can do that in rails controller.

def create_or_update
  params[:micropost].delete(:link) if params[:micropost][:link].blank?
  # continue the task
end

This trick is useful for all optional fields like password

kevinluo201
  • 1,444
  • 14
  • 18