Why does the "submit" button display before the <form>? - ruby-on-rails

This is kind of surprising. Even though it looks to me like my submit tag is supposed to occur within the form, it displays before the form. The html source looks ok to me, but the resultant display and DOM is wrong. Not sure what would have shuffled it. The submit button is displayed BEFORE the form.
Can you see something?
view file:
<%= content_tag :table do %>
<%= content_tag :thead do %>
<% 5.times do |q| %>
<%= content_tag :th, "1" %>
<% end %>
<% end %>
<%= content_tag :tbody do %>
<%= form_tag program_participant_round_survey_path(
program_id: #program.id, participant_id: #participant.id, round_id: #current_round.id), :method => 'put' do %>
<%= render partial: 'value', collection: #values %>
<%= submit_tag "Save" %>
<% end %>
<% end %>
<% end %>
key part of the html:
...
<tr>
<td>
Scaling Up vs. Scaling Out
</td>
<td>
<input id="values__q0" name="values[]" type="radio" value="q0" />
</td> <td>
<input id="values__q1" name="values[]" type="radio" value="q1" />
</td> <td>
<input id="values__q2" name="values[]" type="radio" value="q2" />
</td> <td>
<input id="values__q3" name="values[]" type="radio" value="q3" />
</td></tr>
<input name="commit" type="submit" value="Save" />
</form></tbody></table>
</div>
</div>
</body>
</html>
Here's what the page looks like in the browser:
And here's what it looks like as DOM:

That's how a browser handles elements inside tables that don't belong there - it assumes they're a caption and moves them before the table.
You have a <input type="submit"> inside a table but not inside a <tr> in the generated code.
If you wrap the <input> in <tr><td>, it will no longer move before the table. Note that using tables for layout is not recommended.

I don't know the exact reason for what's happening, but I would personally do it like this instead:
<%= form_tag program_participant_round_survey_path(
program_id: #program.id, participant_id: #participant.id, round_id: #current_round.id), :method => 'put' do %>
<%= content_tag :table do %>
<%= content_tag :thead do %>
<% 5.times do |q| %>
<%= content_tag :th, "1" %>
<% end %>
<% end %>
<%= content_tag :tbody do %>
<%= render partial: 'value', collection: #values %>
<% end %>
<% end %>
<%= submit_tag "Save" %>
<% end %>

Related

How to render/fetch a template remotely through StimulusJS?

So following is the bit of code that I'd like to add in the HTML after a particular event occurs:
<div class='comment-form' data-controller='comment'>
<form action='' data-action='comment#createComment'>
<div class='comment-form__title'>Add your reply:</div>
<textarea class='comment-form__textarea' placeholder='Type in your reply' data-comment-target='commentText'></textarea>
<input type="submit" value="Submit" class='btn-secondary' >
</form>
</div>
As of now, the only way I could find, is the following:
post.insertAdjacentHTML(`<div class='comment-form' data-controller='comment'>
<form action='' data-action='comment#createComment'><div class='comment-form__title'>Add your reply:</div><textarea class='comment-form__textarea' placeholder='Type in your reply' data-comment-target='commentText'></textarea><input type="submit" value="Submit" class='btn-secondary'></form></div>`)
I'm looking for a way where this template is rendered through the server code(read: Rails), instead of me hardcoding it in the JS.
P.S:
As of writing this, Discourse for StimulusJS is down, and I could find a link for a question similar to what I'm asking here: https://discourse.stimulusjs.org/t/fetching-a-partial-on-click/1297, and on Stackoverflow, I couldn't find a relevant question to this.
If you looking to render the comment form continuously. You can use the loop like this:
<div class='post-comments-section'>
<% post.comments.each do |comment| %>
<div class="post-comments">
<p>
<b><%= comment.user.name %>:</b> <%= comment.content %>
</p>
<span> <%= comment.created_at.strftime("%Y/%m/%d") %> </span>
</div>
<% end %>
<%= form_for(post.comments.new, url: post_comments_path(post)) do |form| %>
<%= form.text_field :content, id: :comment_content, class: 'form-control', placeholder: 'Add new Comment' %>
<%= form.submit 'Comment', class: 'btn btn-secondary' %>
<% end %>
</div>
And, If you are looking to add something specific. You can add the partial from the controller with a condition.
def create
if comment.create
render partial: "posts/comment"
end
end

Get values of select tags without a form from the view to the controller in rails

I have a view that contains a series of select tags. I wanted to get the values of the selected values on all the select tags from the view to my controller.
Please see code below:
<% dialog_tag :id => "imonggo_xero_dialog" do %>
<h3><%= #title %></h3>
<h5>Accounts Mapping</h5>
<hr>
<center>
<table id="listing">
<tr>
<th>Imonggo</th>
<th>Xero Account</th>
</tr>
<tr class="<%= cycle "odd", "even" %>">
<td>Total Sales</td>
<td><%= select_tag 'sales', options_for_select(#revenues) %></td>
</t>
<tr class="<%= cycle "odd", "even" %>">
<td>Cash</td>
<td><%= select_tag :cash, options_for_select(#current_accounts)%></td>
</t>
<tr class="<%= cycle "odd", "even" %>">
<td>Credit Card / EFTPOS</td>
<td><%= select_tag :ccard, options_for_select(#current_accounts)%</td>
</table>
</center>
<br>
<p class="indent_top">
<%= button_to 'Save', "/#{#locale}/save_settings"%>
</p>
<% end %>
I want that after clicking the "Save" button, I will pass as parameters the values of the selected items on all the select tags in my view.
The key to your problem is properly specifying the controller and action that handles your data in the form_tag. The following is a code sample that passes two values to a controller via the params hash.
I think that some problems you might have encountered will be down to your use of a button_to tag. Note that I am using a submit_tag to handle the form.
<%= form_tag "/my_controller/my_method" do %>
<div>
<%= label_tag "Foo" %>
</div>
<div>
<%= select_tag("foo", options_for_select(#foos_list, :selected => #selected_foo)) %>
</div>
<div>
<%= label_tag "Bar" %>
</div>
<div>
<%= select_tag("bar", options_for_select(#bars_list, :selected => #selected_bar)) %>
</div>
<div>
<%= submit_tag "Save", :name => 'save' %>
<%= submit_tag "Defaults", :name => 'defaults' %>
</div>
<% end %>
----- my_controller -----
...
def my_method
# if statement to distinguish between a save attempt and
# resetting the form to default values
if params[:save]
puts params[:foo]
puts params[:bar]
end
end
...
When you submit your form, the selected values in every select tag inside your form is passed in the form of a params array to the controller to be manipulated like this:
params[:sales]
params[:cash]
params[:ccard]

Can't get shared filters in home view to work in spree demo

In the spree demo (latest version), I tried to use shared/filters instead of shared/taxonomies in views/spree/home/index.html.erb:
<% content_for :sidebar do %>
<div data-hook="homepage_sidebar_navigation">
<%#= render :partial => 'spree/shared/taxonomies' %>
<%= render :partial => 'spree/shared/filters' %>
</div>
<% end %>
I get the filters (All Taxons), but when I pick some, like Bags and T-Shirts and click on search, the filter doesn't work.
I didn't change anything in shared/filters:
<% filters = #taxon ? #taxon.applicable_filters : [Spree::Core::ProductFilters.all_taxons] %>
<% unless filters.empty? %>
<%= form_tag '', :method => :get, :id => 'sidebar_products_search' do %>
<%= hidden_field_tag 'per_page', params[:per_page] %>
<% filters.each do |filter| %>
<% labels = filter[:labels] || filter[:conds].map {|m,c| [m,m]} %>
<% next if labels.empty? %>
<div class="navigation" data-hook="navigation">
<h6 class="filter-title"> <%= filter[:name] %> </h6>
<ul class="filter_choices">
<% labels.each do |nm,val| %>
<% label = "#{filter[:name]}_#{nm}".gsub(/\s+/,'_') %>
<li class="nowrap">
<input type="checkbox"
id="<%= label %>"
name="search[<%= filter[:scope].to_s %>][]"
value="<%= val %>"
<%= params[:search] && params[:search][filter[:scope]] && params[:search][filter[:scope]].include?(val.to_s) ? "checked" : "" %> />
<label class="nowrap" for="<%= label %>"> <%= nm %> </label>
</li>
<% end %>
</ul>
</div>
<% end %>
<%= submit_tag Spree.t(:search), :name => nil %>
<% end %>
<% end %>
Any ideas why?

Rails anyway to add an if statement to a loop

In my rails application I have a set of attachments that display, with a main image being one of them. However, I would like to loop through all of them except the main attachment. My view code right now is:
<% if #asset.attachments.size > 0 %>
<table>
<tr>
<% #asset.attachments.each_with_index do |attachment, i| %>
<% if i%5 == 0 %>
</tr><tr>
<%end%>
<td style="width: 150px;" valign="bottom" align="center">
<%= image_tag(attachment.attachment.url(:thumb)) if attachment.is_image? %>
<%= image_tag("/images/Excel.png") if attachment.is_excel? %>
<%= image_tag("/images/Word.png") if attachment.is_word?%>
<br />
<%= link_to attachment.name.to_s,attachment.attachment.to_s %>
</td>
<%end%>
</tr>
</table>
<%end%>
but, I would like to add something like if !main_image to this line of code:
<% #asset.attachments.each_with_index do |attachment, i| %>
I don't know if that is possible though.
This answer is in continuation to answer on this question
Add another method to your model, which return you the attachments which are not main image.
scope :not_main_image, where(:main_image => false)
On a side note, you might want to move all this logic into a helper method:
<%= image_tag(attachment.attachment.url(:thumb)) if attachment.is_image? %>
<%= image_tag("/images/Excel.png") if attachment.is_excel? %>
<%= image_tag("/images/Word.png") if attachment.is_word?%>
<br />
<%= link_to attachment.name.to_s,attachment.attachment.to_s>
Say you create a helper method like:
def link_to_attachment attachment
html = ""
html += image_tag(attachment.attachment.url(:thumb)) if attachment.is_image?
html += image_tag("/images/Excel.png") if attachment.is_excel?
html += image_tag("/images/Word.png") if attachment.is_word?
html += "<br />"
html += link_to(attachment.name.to_s, attachment.attachment.to_s)
html.html_safe
end
Then in you view you can replace it with:
<td style="width: 150px;" valign="bottom" align="center">
<%= link_to_attachment attachment %>
</td>
<% #asset.attachments.each_with_index do |attachment, i| %>
&lt% next if attachment.main_image %>
It depends on how you define the main attachment
<% #asset.attachments.each_index do |attachment, i| %>
<% unless attachment.main? %>
...
<% end %>
<% end %>
OR
<% #asset.attachments.each_index do |attachment, i| %>
<% if attachment.main? %>
<% next %>
<% else %>
...
<% end %>
<% end %>
OR put this in your controller
#attachments = #asset.attachments.where(:main => false)
after that, iterate over #attachments instead of #asset.attachments

html5 in rails3 views

I have a view with some embedded ruby in it... i want to insert a cell <td></td> into it, but when i do that it gives several error messages? This is because i concatenate a text field and a submit button into the embedded ruby.
This is my code:
<table>
<% for answer in #question.answers %>
<tr>
<!-- this displays all the possible answers -->
<td>
<%= answer.text %>
</td>
<% if current_user.can_vote_on? (#question) %> <!-- if a current user has not yet voted.. -->
<td> <%= form_tag('/vote', :method => "post") do
hidden_field_tag('vote[answer_id]', answer.id) +
submit_tag("Vote")
end %> <!-- vote button.. -->
<% end %>
</td>
</tr>
<% end %>
<% if current_user.can_vote_on? (#question) %> <!-- this shows a answer text field -->
<tr>
<td>
<%= form_tag('/vote/new_answer', :method => "post") do
hidden_field_tag('answer[question_id]', #question.id) +
hidden_field_tag('answer[user_id]', current_user.id) +
text_field_tag('answer[text]') + <!-- in here i want an extra </td><td> tag -->
submit_tag('Vote')
end %>
</td>
</tr>
<% end %>
My question is: how can i exit the embedded ruby and at the same time staying in the concatenated string...? I want to add the </td> and the <td> after the text_field_tag('answer[text]')
I tried this:
<td>
<%= form_tag('/vote/new_answer', :method => "post") do %>
<%= hidden_field_tag('answer[question_id]', #question.id) %>
<%= hidden_field_tag('answer[user_id]', current_user.id) %>
<%= text_field_tag('answer[text]') %>
</td>
<td>
<%= submit_tag('Vote') %>
<% end %>
</td>
And it works!
Thijs
Simple answer: It's not possible.
I suggest you try a different approach such as using divs inside your td elements. If I were you I wouldn't concatinate the strings together.
<%= form_tag('/vote/new_answer', :method => "post") do %>
<%= hidden_field_tag(answer[question_id], #question.id %>
... so on ...
<div class="position_it_somewhere_with_this_class"><%= submit_tag("vote") %></div>
<% end %>
You don't concatenate tags!
Also you don't use divs in table rows. put the classes in your tds
...
<%= form_tag('/vote/new_answer', :method => "post") do %>
<%= hidden_field_tag('answer[question_id]', #question.id) %>
<%= hidden_field_tag('answer[user_id]', current_user.id) %>
<%= text_field_tag('answer[text]') %>
<%= submit_tag('Vote') %>
<% end %>
</td>
</tr>
..

Resources