Rails form updating itself as it's filled out? - ruby-on-rails

I'm trying to make a dynamic form, where the names of some forms at the bottom are based off the values of some forms at the top. For example...
At the top of the page there would be two dropdown menus. At the bottom of the page, there would be two radiobuttons. The name of the first radiobutton would have the name of the first dropdown menu choice, and the second radiobutton would have the name of the second dropdown menu choice.
This is what I have so far:
<%= simple_form_for(#game) do |f| %>
<%= f.error_notification %>
<center>
<div class="form-inputs">
<%= choices = options_for_select( Team.all.map { |team| team[:name] } ) %>
<p>Team 1:</p>
<%= f.select :first_team_name, choices %>
<p>Team 2:</p>
<%= f.select :second_team_name, choices %>
<p>Who you think will win</p>
<%= f.text_field :user_guess %>
</br>
<%= f.submit "Simulate!", class: "btn btn-large btn-primary"%>
</div>
</center>
<% end %>
The text field would be replaced by those radiobuttons instead of a text field.
How do I access the value of the dropdown menus before submitting the form?

For a more comprehensive answer, I'd recommend watching the railscasts episode on this topic, but you'd need a pro (read: paid) subscription.
Since you're not doing anything super complex, you could do it quick & dirty with some javascript:
$(function(){
$('select').change(function(){
html = ''
$('select').each(function(){
html += $(this).val() + '<input type="checkbox" name="game[user_guess]" val="' + $(this).val() +'"/>'
})
$('div.user_guess').html(html)
})
})
If you're pasting the code directly in, you'll need to add a div in your view as well:
<p>Who you think will win</p>
<div class="user_guess"></div>
Don't feel good building HTML with javascript? You can make the change() handler make an ajax call that will load server-generated HTML, which can be made with proper form helpers and such. But for such a simple task it seems like overkill.
(Also, be aware that if the team names can be user defined, this javascript may open you to script injection attacks, so sanitize as needed.)
note that if you want the form to change upon user interaction without the user actually having to submit the form before it changes (rebuilding the page and reloading the view), you have to use javascript. I think. There might be funky things you can do with CSS but that would be really obnoxious to implement.

Related

How to have multiple, separate, instances of Trix / ActionText rich text areas on the same page?

I have a list of commentable models in my Rails view, represented by cards that each have their own comment form. The forms are identical (from the same partial), and have a rich_text_area for the commentable's body (defined as has_rich_text :body on the model, per the docs). It is close to the following (simplified) example:
<% #assignables.each do |assignables| %>
<!-- omitted code displaying the assignable object -->
<!-- ADD COMMENT FORM -->
<%= form_with model: Comment.new do |form| %>
<div class="">
<%= form.hidden_field :commentable_id, value: assignable.id %>
<%= form.hidden_field :commentable_type, value: assignable.class.name %>
<%= form.rich_text_area :body, data: { controller: "mentions" } %>
<%= form.submit "Submit", class: "button button-primary" %>
</div>
<% end %>
<% end %>
Only the first form on the page (in DOM order) actually submits a body parameter. Network requests from any other form shows a blank comment[body] parameter. Additionally, if I add text to the 2nd form's input, then go back and submit the first form without touching it, the submission includes the input I entered into the 2nd form.
From this, I understand I need to override some attribute which is supposed to be unique. I've scoured the Rails docs and the Trix docs, but I haven't found anything which indicates how to make Rails do this override such that Trix accepts it.
What attribute do I override, and how?
Turns out, the answer is simple: override the id attribute of the rich text area to include a unique value like a primary key, and Rails handles the rest.
E.g.:
<%= form.rich_text_area :body, data: { controller: "mentions" },
id: "commentable_#{commentable.id}_comment" %>
Translates to:
<form …>
<input id="commentable_1_comment" value="Editor content goes here" type="hidden" name="content">
<trix-editor input="commentable_1_comment"></trix-editor>
</form>
Now every instance of the text area has a unique ID (rather than the generic new_comment) and the hidden inputs all submit their values correctly.
For reference: The Trix documentation show what the HTML is supposed to look like at the after ERB is done with it, but the Rails rich_text_area docs don't indicate anything about attributes you might want to override.

Making a dropdown and getting the value in Rails

I have a many-to-many relation between my User model and my Project model for the purpose of assigning projects to users. I'm now trying to impement the feature for actual assignment using a dropdown containing the projects on the edit user page. My code looks like this, but I can't seem to figure out how send the selected value back to the controller once the button is clicked:
<div class="input-group my-2">
<%= collection_select('user', 'project', Project.all, :id, :name, include_blank: true) %>
<div class="input-group-append">
<%= link_to '<div class="btn btn-outline-primary">Toggle access to selected project</div>'.html_safe, toggle_project_access_user_url %>
</div>
</div>
I've tried using the suggestions for JS I've found, but I think I'm missing some knowlegde on how to implement the functionality completely with those.
Working with Javascript in Rails covers this.
Use form_with to set up a form with data-remote=true. Then proceed as normal.
form_with url: toggle_project_access_user_url, method: :patch do |f|
f.collection_select(:project_id, Project.all, :id, :name, include_blank: true)
f.submit("Toggle access to selected project")
end
This will send a POST to toggle_project_access_user_url with a hidden _method input indicating it's a PATCH. Use a hook on ajax:success to update the page.

Is it okay to read date from database in the view template in Ruby on Rails?

I am revisiting the basics of MVC and Ruby on Rails. I am looking at my code and found that I have used this select tag in my Edit User Profile view.
<div class="row">
<div class="panel panel-primary">
<div class="panel-heading">
<%= f.label :country_id, "From*" %>
</div>
<div class="panel-body">
<%= f.select :country_id, Country.order(:name).collect {|p| [ p.name, p.id ] }, {}, { :class => 'form-control' } %>
</div>
</div>
</div>
I am accessing the Country table in the view. I am pretty sure this should not be done but somehow it works. Why does it work? What is the correct way to do it?
Thanks.
There's no reason why what you have won't work. Remember, a view template is an "embedded ruby" file. It has Ruby embedded in an HTML template. When the view is "rendered" by the controller, all of the code inside it gets executed and whatever output is generated by its Ruby code becomes part of the HTMl document. In this case, the output generated by the Ruby code is a bunch of HTML tags and Country names and IDs.
To avoid having this logic in the view, you would put it in the controller and save it to an instance variable (i.e. something like #select_vals) and then reference that variable in the view template.
It works because Rails provides a lot of 'magic' under the hood; this functionality, at a guess, is probably part of the ActionView library (I haven't checked).
One of the fundamental principles of the MVC model is that you don't do this in the view. This logic should be done in the controller.
The correct way ->
in Controller method:
#country_vals = Country.order(:name).pluck(:name, :id)
No need to use collect().
In your view:
<%= f.select :country_id, #country_vals, {}, { :class => 'form-control' } %>

form_for was put inside fields_for

I'm having a problem with form_for and fields_for.
So, my problem is:
I had a form_for, and inside this form_for, I use a fields_for. Inside this fields_for, I use a form_tag (i used ajax for this form_tag).
But when I view the generated HTML, it didn't display form_tag, it only display form_for. And I didn't understand why.
Please explain for me, why it didn't display form_tag.
Here is my form_for:
<div class="row">
<%= form_for #real_estate, url: admin_real_estate_update_path do |f| %>
<%= f.fields_for(:client) do |client| %>
<%= text_field :real_estate, :assessment_start_at, value: #real_estate.assessment_start_at %>
<%= render partial: "admin/real_estate/form/assessment", locals: {real_estate_id: #real_estate.id} %>
<% end %>
<%= f.submit "Submut", class: "btn btn-primary"%>
<% end %>
</div>
Here is my form_for which i put inside fields_for:
<%= form_tag admin_search_assessment_path(real_estate_id), method: :post, remote: true do %>
<%= text_field_tag :company_name, params[:company_name] %>
<%= submit_tag "Submit" %>
<% end %>
And i tried to add <form></form> follow as:
<div class="row">
<%= form_for #real_estate, url: admin_real_estate_update_path do |f| %>
<form></form>
<%= f.fields_for(:client) do |client| %>
<%= text_field :real_estate, :assessment_start_at, value: #real_estate.assessment_start_at %>
<%= render partial: "admin/real_estate/form/assessment", locals: {real_estate_id: #real_estate.id} %>
<% end %>
<%= f.submit "Submut", class: "btn btn-primary"%>
<% end %>
</div>
And form_tag was display, but form_for didn't display.
Update:
So, i used $("form_2").submit(function() {....}); to solve this problem.
Actually, i still want to use form-nested.
Inside this fields_for, I use a form_tag (i used ajax for this form_tag)
N'est pas possible, mon ami.
--
Here's how it works...
form_for and form_tag both generate pure HTML forms:
<form action="/action" method="POST">
</form>
Many people get confused about how Rails works - it's really quite simple. Rails employs "helper" methods to generate pure HTML which your browser can read.
Browsers only understand HTML/CSS at the moment. Thus, whenever you send a request to Rails - it has to return that data, otherwise a "web page" simply wouldn't be able to be processed.
Thus, when you ask whether you can nest forms, you have to abide by how the forms work in pure HTML (spec):
Note you are not allowed to nest FORM elements!
HTML fill-out forms can be used for questionaires, hotel reservations,
order forms, data entry and a wide variety of other applications. The
form is specified as part of an HTML document. The user fills in the
form and then submits it. The user agent then sends the form's
contents as designated by the FORM element. Typically, this is to an
HTTP server, but you can also email form contents for asynchronous
processing.
In short, it means that everything within a <form> tag is counted as a form by HTTP. This means that if you have another <form> tag, it's going to cause an error, preventing either from working.
You know this already (otherwise you wouldn't have mentioned ajax).
Your main problem is the use of <form></form> inside your current <form> object. This will confuse HTML profusely, and thus I would recommend replicating the submission of a form, without the <form> object itself:
#app/views/admin/real_estate/form/assessment.html.erb
<%= text_field_tag "[company_name]", params[:company_name], id: real_estate_id %>
<%= button_tag "Submit", type: "button" , data: { id: real_estate_id } %>
#app/assets/javascripts/application.js
$(document).on("click", "button", function(e){
e.preventDefault();
var real_estate_id = $(this).data("id");
$.ajax({
url: "path/to/real/estate/form/assessment/" + $(this).data("id")),
data: {company_name: $("input[type=text]#" + real_estate_id).val()}
success: function(data) {
//do something on success
},
error: function(data) {
//do something on error
}
});
});
This code will still output what you need.
The difference will be two-fold:
The user will experience the same functionality (the input will still be present)
The embedded form will be passed to the main "form" submit, but will not be passed through your strong params method (making it
invisible to your controller)
In effect, you're replicating the functionality of an HTML form through Ajax. Whilst I still wouldn't do it this way, it will give you the functionality you require.

how to submit a form and send fields that are not in the form tag

I am trying to get a form like this:
Name form:
<% form_tag do %>
<p>
<label for="name">Name:</label>
<%= text_field_tag :search%> <%= submit_tag "Go"%>
</p>
<% end %>
Phone Number
<% form_tag do %>
<p>
<label for="ph">Phone Number:</label>
<%= text_field_tag :phone%> <%= submit_tag "Go"%>
</p>
<% end %>
What should I do with Seta and Setb values? Do I need to combine them with form tags? if so, then which ?
Functionality of the form will be that user selects either Seta or Setb and enter something in Name or Phone number and click corresponding Go button.
There isn't a way to submit data for a form which is outside of a form. But, I can think of two solutions:
Have the whole thing in one big form and figure out what the user wanted to do in the handler code. This would be pretty simple (just find a blank box) to do.
Alternatively, you could have clicking "seta" or "setb" invoke a Javascript function which edits a hidden field in both forms. This might be closer to what you actually want, although it is a little more error prone (especially if people have Javascript turned off or their browser doesn't support it).

Resources