How can I make it so that my info only gets stored if the checkbox is checked
<% #extra.each do |extra| %>
<%= f.fields_for :purchaseds do |builder| %>
<div class="label-field">
<%= builder.label :name, extra.name %>
<p><%= extra.description %></p>
</div>
<div class="text-field">
$<%= extra.price %>
<%= builder.check_box :purchased %>
</div>
#I WOULD LIKE THIS TO ONLY GET SAVED IF THE CHECK BOX FOR PURCHASED IS CHECKED
<%= builder.hidden_field :name, :value => extra.name %>
<%= builder.hidden_field :description, :value => extra.description %>
<%= builder.hidden_field :price, :value => extra.price %>
<% end %>
<% end %>
My client asked to be able to add extra services himself, and then users could be able to choose if they want to purchase them as accessories to their order. So what I did was I made a table called Extra (for extra services) and another table called Purchased. Purchased belongs to Order and is a nested attribute.
Well two ways. I will give you just the high level of it but if you would like me to expand, please let me know!
Option 1
Add a submit button to the form builder and have the checkbox data sent to the controller as well. There, check to see if it's set to true. If so, save the data. If not, don't save it.
Option 2
Add a jQuery function that, when the checkbox is set to true, it fires off an AJAX request to the controller to save the data.
It depends on how you want the user to be able to use this form.
Related
I'm making an app where some activities are listed in a table called Fakultety (polish language, sorry), and participants on in another table called Uczestnicy.
I have a submit form where you can submit yourself to an activity, but I'm stuck on passing values to a DB. Firstly, I don't know how to tell to the database on which activity you want to be assigned to (I tried to change the submit button id to an activity id and then passing it into a database but don't know how to do this id: "#{#fakultet.id}" not working) and later I want to count how many people are assigned to field participants in a database Fakultety, but I don't want to pass all the data, just ID of the users from table called Uczestnicy. How to do it? I mean just to pass the ids to another table, and how to tell the database on which activity I want to be assigned to?
This is my form view:
<h1>Zapisujesz sie na fakultet</h1>
<div class="form-group">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#participant, url: zapisy_path) do |f| %>
<p>Imię:</p>
<%= f.text_field :firstName, class: 'form-control' %>
<p>Nazwisko:</p>
<%= f.text_field :lastName, class: 'form-control' %>
<p>Grupa:</p>
<%= f.text_field :group, class: 'form-control' %>
<%= f.submit "Zapisz się", class: "btn btn-primary" id: "#{#fakultet.id}"%>
<% end %>
</div>
</div>
</div>
Does anybody understand me and can help me?
Rails provides form collection helpers that make it really easy to assign associations:
# I'm going to just do this in english
<%= form_for(#activity) do |f| %>
<%= f.collection_select(:participant_ids, Partipicant.all, :id, :name, prompt: true, multiple: :new) %>
# ...
<% end %>
Then whitelist the attribute as an array:
params.require(:activity).permit(:foo, :bar, participants_ids: [])
Thats all you actually need to assign childen to to a parent resource. This is done as a part of the normal create/update actions of the parent resource.
You don't actually need the form for the child records unless you actually want to be creating the record. In that case you can setup a nested resource or if you want to create/edit multiple nested records at the same time as the parent record you can use nested attributes.
First you should rename your models and tables, to English, it's a really bad pattern to use your language, in English it is easier to understand by other devs.
According to the problem, probably what you are looking for is hidden_field
<%= f.hidden_field :fakultet_id, :value => #fakultet.id %>
and if you want to query Fakultety that have user assigned, you can select Fakultety where participant_id is not nil
Fakultety.where.not(participant_id: nil)
I need a way for my form to not be sent if the user didn't bother to select any radio buttons.
I'd like to to that within the view and the controller, not in the model (the data shouldn't even be sent)
<%= form_tag("/bookings/new", method: "get") do %>
<% #flights.each do |flight| %>
<%= radio_button_tag :flight_id, flight.id %>
<% end %>
<%= submit_tag "book now" %>
<% end %>
edit, to clarify
normally I'd do
<%= f.text_field :name, required: true %>
but, as I have many radio buttons and I only need one for the form to work, I don't know how to implement it
You can set validation in the model to see the presence of checkbox if javascript is disabled. This is a more robust method.
validates :flight_id, :acceptance => true
Docs here - http://guides.rubyonrails.org/active_record_validations.html#acceptance
Edit
function validateCheckBox() {
var x = document.getElementById("flight_id").checked;
if(!x) {alert("Not checked")}
}
<%= submit_tag "book now" , :onclick => "validateCheckBox();" %>
<%= f.text_field :name, required: true %>
This still works perfectly for radio buttons, and it's okay if it ends up on all radio items. The form will still only require one input.
I just tested it on my Rails 6 app.
I am using the cocoon gem to try and achieve adding an object which belongs to another with nested fields. I have a 'user_resolution' which has many 'milestones'. I have set up the associations accordingly in both of these models. For some reason, milestones are failing to be created, however if I add one manually in the database I can successfully update it. I am able to dynamically add the fields and remove them using the cocoon gem but that is all. When I click 'add milestone' it redirects me to the show view of the user resolution and throws the success message saying user resolution has been updated, no errors are thrown but the milestone(s) is/are not created.
user_resolution.rb
has_many :milestones
accepts_nested_attributes_for :milestones, reject_if: :all_blank, allow_destroy: true
milestone.rb
belongs_to :user_resolution
I have set up the nested form within the edit view as for now I only want users to add a milestone to a resolution in the edit view.
user_resolutions/edit.html.erb
<%= form_for(#user_resolution) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<%= f.fields_for :milestones do |milestone| %>
<%= render 'milestone_fields', f: milestone %>
<% end %>
<%= link_to_add_association 'Add Milestone', f, :milestones %>
<%= f.submit "Add Milestone" %>
<% end %>
_milestone_fields.html.erb
<div class="nested-fields">
<div class="field-row">
<%= f.label :name, 'Name' %>
<%= f.text_field :name %>
</div>
<div class="field-row">
<%= f.label :description, 'Name' %>
<%= f.text_area :description %>
</div>
<div class="field-row">
<%= f.label :severity, 'severity' %>
<%= f.check_box :severity %>
</div>
<div class="field-row">
<%= f.label :target_date, 'target_date' %>
<%= f.date_select :target_date %>
</div>
<%= link_to_remove_association 'Remove', f %>
</div>
The permitted parameters within the user resolutions controller also contain the following
milestones_attributes: [:id, :user_resolution_id, :name, :description, :target_date, :severity, :complete, :_destroy]
The milestones themselves have no views, they only have a model and a controller. The controller create action (which i'm unsure is required for nested forms) contains the standard following code
def create
#milestone = Milestone.new(milestone_params)
if #milestone.save
redirect_to user_resolutions_path,
:flash => { :success => "You successfully created a milestone" }
else
redirect_to new_milestone_path,
:flash => { :error => "Oops something went wrong. Try again." }
end
end
I've been as informative as I can but if you need anything else let me know. Thanks guys.
which i'm unsure is required for nested forms
You don't need a create action for milestones - they'll be populated from the user_resolutions#create controller action.
There are several things to look at with this. I'll detail some here. This won't be a specific answer, but may help point you in the right direction.
Firstly, you need to make sure you're receiving the correct params.
Cocoon does a great job building the nested form - you need to make sure it's obliging Rails' nested attribute structure.
To do this, you should right-click > view source.
In the f.fields_for section (it won't be called that in the HTML), you'll be looking for the equivalent to the following:
<input type="text" name="milestones_attributes[0][name]" value="">
The important thing to note is the name...
Each time you use a form, or any Rails view helper for that matter, you're really just building standard HTML. form_for just creates an HTML form, and thus any params contained within it need to adhere to a certain structure for Rails to recognize the params.
The f.fields_for elements will typically be called x_attributes[:id][:param] - this is passed to Rails, which cycles through each [:id] to determine the number of nested params to add.
You need to check the source for the above naming structure. If you see it, that's good. If not, it means you haven't built your form properly.
Secondly, you need to make sure your objects are being built in the controller.
I'm not sure how Cocoon does this, but essentially, each time you use f.fields_for, you have to build the associated object before:
def new
#user_reservation = UserReservation.new
#user_reservation.milestones.build #-> this is what makes f.fields_for work
end
If the first step shows incorrect element naming, it means your associative objects are not being built (which is why they're not being recognized).
To test it, you should build the associative objects in the new method, before sending.
Finally, you'll want to post your params.
These tell you in explicit detail what Rails is doing with the nested attributes, allowing you to determine what's happening with them.
Sorry for the long-winded answer. You'll not have received any answers anyway, so I felt it prudent to give you something.
I'm fairly new to Ruby on Rails and I'm building a customer database for my father's landscaping company as a pet project. I've run into a roadblock with some code.
I've got three tables interacting with each other here: Clients, Invoices and Services (nested under Invoices). In the clients table, there are prices stored for each service performed (e.g., cut, bushes, mulch). If the client doesn't receive that service, the entry is null. I've stored the prices this way because each client is charged a different set amount for a service depending on the size of their property.
When adding a service to an invoice, I want to check the service selected in the drop-down against the price set in the client table, and give an error if its null (if the customer doesn't receive that service). For example, if "Cut" is selected, I'd like to compared that to (I think) #invoice.client.cut
I'm not entirely sure where to start with this. How would you have code like this run when the submit button is clicked?
Thanks in advance for any and all help!
Here's what the form looks like in its current state:
<%= form_for [#invoice, #service] do |f| %>
<div class="control-group">
<%= f.label :name %>
<div class="controls">
<%= f.select(:name, options_for_select([['Cut', 'Cut'], ["Mulch", "Mulch"],['Bushes', 'Bush'], ['Spring clean-up', 'Spring'], ['Fall clean-up', 'Fall'], ['Snow removal', 'Snow']])) %>
</div>
</div>
<div class="control-group">
<%= f.label :category %><br>
<div class="controls">
<%= f.select(:category, options_for_select([["Maintenance", "Maintenance"], ["Seasonal", "Seasonal"]])) %>
</div>
</div>
<div class="field">
<%= f.label :quantity %><br>
<%= f.number_field :quantity %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I would add at data-attribute somewhere in the view that lists the customer's current services, possible on the label for that dropdown. You can then use javascript to verify that the option selected is available to the user without making a call to the database.
<%= f.label :name, 'data-services' => #invoice.client.services %>
Instead of checking the validity of the selected value when the user chooses it, don't even show the value in the dropdown. The user experience is different than you described, but not necessarily worse.
The architecture of querying the different kinds of services a client has should be improved by an extra model, but using the methods you already have:
<%= f.select(
:name,
options_for_select(
[
['Cut', 'Cut'],
['Mulch', 'Mulch'],
['Bushes', 'Bush'],
['Spring clean-up', 'Spring'],
['Fall clean-up', 'Fall'],
['Snow removal', 'Snow']
].select do |a|
#invoice.client.public_send(a.last.downcase)
end
)
) %>
Tried to figure this out for a while without being able to crack the nut.
What I am trying to do is this.
I have a user model, it has_many answers. I would like to restrict the ability for one user to answer the same answer more than once. I've been able to block this in the model, however not in the view.
I would like the submit button to see if the current_user.id is present in the current answer id (the one it's thinking about filling out), if so disable the submit button saying "already applied".
My answers#new
<%= form_for #answer do |f| %>
<%= f.hidden_field :application_id, value: #application.id %>
<% if #application.question_2.length && #application.question_3.length >= 1 %>
<p>Question 1: <%= #application.question_1 %></p>
<%= f.text_area :answer_1 %><br/>
<p>Question 2: <%= #application.question_2 %></p>
<%= f.text_area :answer_2 %><br/>
<p>Question 3: <%= #application.question_3 %></p>
<%= f.text_area :answer_3 %>
<% elsif #application.question_2.length >= 1 %>
<p>Question 1: <%= #application.question_1 %></p>
<%= f.text_area :answer_1 %><br/>
<p>Question 2: <%= #application.question_2 %></p>
<%= f.text_area :answer_2 %><br/>
<% else %>
<p>Question 1: <%= #application.question_1 %></p>
<%= f.text_area :answer_1 %><br/>
<% end %>
<%= f.submit "Submit answers", data: { disable_with: "Please wait..." } %>
<% end %>
I see a couple different pieces of this. When I write similar functionality, I think about the following questions:
What should happen on page load / reload?
Should anything happen without page reload (ie. via AJAX / JS)?
Should the action be disabled server-side, client-side, or both?
First of all, if the user has already submitted an answer by the time the page loads, the template should display the button differently. Usually it makes sense to not display a form at all in that case, but if you want the form with the button disabled, the following code comes to mind (see html example):
<% if #user_has_answered %>
<%= f.submit "Submit answers", disabled: true %>
<% else %>
<%= ... normal button ... %>
<% end %>
If you're concerned about preventing the user from clicking the button twice when they submit the form from the page, some simple Jquery can easily handle that, or you can use disable_with as in your example twice. This has nothing to do with the state of the database; it merely sets up a Javascript listener that disables the button as soon as it's clicked (and changes its text) to prevent the user from accidentally double-submitting when pages load slowly.
You mentioned that you have prevented double answers in the model. How does the controller handle this? If a user somehow manages to fill out the form a second time and submit it (perhaps Javascript is disabled and they had multiple tabs open on the same page? If it's possible, users do it), what do you want to happen to the data they've submitted? Show them a rejection message? Preserve their data on the same page? This functionality should be 80% automatic in Rails, if you want it, as long as you handle the request and rejection in the same way that form validation errors are handled.
I'm happy to be more specific if you share more detail about what you're looking for or having trouble with.
Assuming that Answer belongs_to Application, you could do...
<% if current_user.answers.collect(&:application).include?(#application) %>
<%= f.submit "already applied", disabled: true %>
<% else %>
<%= f.submit "Submit answers", data: { disable_with: "Please wait..." } %>
<% end %>