Rails :How to move code from view to partial file - ruby-on-rails

In edit.html.erb
<% if material.look %>
<%= form_for material do |f|%>
<% if material.approval = "1" %>
<%= f.hidden_field :date,value: Date.today %>
<% end %>
<%= f.hidden_field :approval_amount, value: 0 %>
<%= f.hidden_field :approval_amount_percentage, value: 0 %>
<%= f.submit 'yes' %>
<% end %>
<%= form_for material do |f|%>
<%= f.hidden_field :approval_amount, value: 0 %>
<%= f.hidden_field :approval_amount_percentage, value: 0 %>
<%= f.submit 'no' %>
<% end %>
<% end %>
Code in two forms are duplicate, so I want to move them to partial file,
In _material_form.html.erb I code like this
<%= f.hidden_field :approval_amount, value: 0 %>
<%= f.hidden_field :approval_amount_percentage, value: 0 %>
In edit.html.erb, I modifies duplicate code
<% if material.look %>
<%= form_for material do |f|%>
<% if material.approval = "1" %>
<%= f.hidden_field :date,value: Date.today %>
<% end %>
<%= render 'material_form'%>
<%= f.submit 'yes' %>
<% end %>
<%= form_for material do |f|%>
<%= render 'material_form'%>
<%= f.submit 'no' %>
<% end %>
<% end %>
However, it shows an error
undefined local variable or method `f' for
What causes the error and how to fix it ? Thanks.

Your form, assigned to the variable f is out of scope in your partial. To use it, you'll need to pass f in as a local value to your partial:
<%= render 'material_form', f: f%>
The rails documentation on partials is quite helpful; you can also dig into the action renderer documentation if you want to go deeper.

Related

How to insert new line breaks using form_for with collection_check_boxes

I use the following form_for at one point in my code to display a series of topics for users to select from.
<%= form_for #user do |f| %>
<%= f.collection_check_boxes(:topic_ids, Topic.all.sample(50).each, :id, :topic_name) %>
<%= f.submit %>
<% end %>
When it renders on the page, the boxes are all one-after-the-other. How can I separate them so that there is one check box per line?
from reference here
It is possibly to customize the way the elements will be shown by giving a block to the method as sample below from your code above
<%= form_for #user do |f| %>
<%= f.collection_check_boxes :topic_ids, Topic.all.sample(50).each, :id, :topic_name do |b| %>
<%= b.label(class: "check_box") do %>
<%= b.check_box(class: "check_box") %>
<%= b.object.topic_name %></br>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
You may of course render HTML inside the block:
<%= form_for #user do |f| %>
<%= f.collection_check_boxes :topic_ids, Topic.all.sample(50).each, :id, : topic_name do |b| %>
<div class="my-checkbox-wrapper">
<%= b.label(class: "foo") do %>
<%= b.object.topic_name %>
<%= b.check_box(class: "bar") ></br>
<%end%>
<%= f.submit %>
<%end%>
You can have a look at this example
It is very broad question. In short, using CSS.
For example using Bootstrap 4:
<%= form_for #user do |f| %>
<div class="form-check">
<%= f.collection_check_boxes :topic_ids, Topic.all.sample(50).each, :id, :topic_name, class: 'form-check-input' %>
</div>
<%= f.submit %>
<% end %>

undefined local variable or method `f' when using hidden_field tag

I'm following a tutorial, and i get this error when i try to add f.hidden_field tag in my form.
undefined local variable or method 'f'
<h1>Signing up for "<%= #subscription.plan.name %>"</h1>
<%= f.hidden_field :paypal_customer_token %>
<%= f.hidden_field :paypal_payment_token %>
<% if #subscription.paypal_payment_token.present? %>
<H1>Payment has been provided </H1>
<% else %>
<div class="field">
<%= radio_button_tag :pay_with, :paypal %>
<%= label_tag :pay_with_paypal do %>
<%= image_tag "paypal.png" %>
<% end %>
<%= link_to "paypal.png", paypal_checkout_path(:plan_id => #subscription.plan_id) %>
<% end %>
Either that tutorial is broken or you missed the line where they do something like this:
<%= form_for #subscription do |f| %>

Rails - Better way to query conditions on join table

I am playing around with a bucket list and I have the following models:
BucketList > BucketListItem < Item
BucketListItem is the join table between the two.
When I'm displaying all of the items and allowing users to either add them to their own bucket list or mark them as complete, I need to know whether or not that user has the item on their bucket list, and also whether they have marked it as done or not. I've come up with a working solution but it feels like there should be a better way of doing it.
In the controller:
#user_items = current_user.bucket_list.items
#user_bucket_list_items = current_user.bucket_list.bucket_list_items
#completed_user_items = []
current_user.bucket_list.bucket_list_items.where(status: 1).each do |bucket_list_item|
#completed_user_items << bucket_list_item.item
end
In the partial that renders each of the items:
<% if #user_items.include?(item) %>
<p>Added</p>
<% else %>
<%= form_for(BucketListItem.new, remote: true) do |f| %>
<%= f.hidden_field :item_id, value: item.id %>
<%= f.submit "+ Add" %>
<% end %>
<% end %>
<% if #completed_user_items.include?(item) %>
<p>Done</p>
<% elsif #user_items.include?(item) %>
<%= form_for(#user_bucket_list_items.where(item_id: item.id).first, remote: true) do |f| %>
<%= f.hidden_field :status, value: "done" %>
<%= f.submit "Mark as Done" %>
<% end %>
<% else %>
<%= form_for(BucketListItem.new, remote: true) do |f| %>
<%= f.hidden_field :item_id, value: item.id %>
<%= f.hidden_field :status, value: "done" %>
<%= f.submit "Mark as Done" %>
<% end %>
<% end %>
It's particularly the second if statement that feels a little convoluted to me. Am I missing an obvious easier way to do this?
Thanks
Well view wise there is not much scope of optimization, But you can optimize your queries in controller
#In Controller
#bucket_list = current_user.bucket_list
#user_items = #bucket_list.items
# More efficient way of getting item which are not yet completed
#completed_user_items = current_user.items.where(bucket_list_items: { status: 1 })
#In view
<% if #user_items.include?(item) %>
<p>Added</p>
<% else %>
<%= form_for(BucketListItem.new, remote: true) do |f| %>
<%= f.hidden_field :item_id, value: item.id %>
<%= f.submit "+ Add" %>
<% end %>
<% end %>
<% if #completed_user_items.include?(item) %>
<p>Done</p>
#Here I have used #bucket_list
<% elsif #user_items.include?(item) %>
<%= form_for(item.bucket_list_items.where(bucket_list: #bucket_list).first, remote: true) do |f| %>
<%= f.hidden_field :status, value: "done" %>
<%= f.submit "Mark as Done" %>
<% end %>
<% else %>
<%= form_for(BucketListItem.new, remote: true) do |f| %>
<%= f.hidden_field :item_id, value: item.id %>
<%= f.hidden_field :status, value: "done" %>
<%= f.submit "Mark as Done" %>
<% end %>
<% end %>

Couldn't save collection_radio_buttons in array Ruby on Rails

We have a problem to save the values of the radio_buttons of a loop. It doesn't save in an array.
The SavedAnswer model has an has_and_belongs_to_many relation with the MultipleChoiceAnswer model.
This is my code:
<%= form_for #saved_answer do |f| %>
<% #questions.each do |question| %>
<%= collection_radio_buttons(:saved_answer, :multiple_choice_answer_ids , question.multiple_choice_answers, :id, :title) do |c| %>
<%= c.radio_button %>
<%= c.label %>
<% end %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
My output is
Parameters: {"utf8"=>"✓", "authenticity_token"=>"57I9yLZMccvcb3Bn5/pw7kES0c9CUAGs33yCXoS0Urm1Yek/Baz8Hl7fO8Yl/OVZWLKsX7qrwOlqEBoXrGkcxQ==", "saved_answer"=>{ "multiple_choice_answer_ids"=>"1"}, "commit"=>"Submit"}
Thanks in advance!
You have form_for with |f| and collection with |f|.
It's not a good decision, i think. That can cause problems.
If not - write what you receive in params when trying to save.
Just use check boxes for your issue:
<%= form_for #saved_answer do |f| %>
<% #questions.each do |question| %>
<%= check_box_tag "saved_answer[multiple_choice_answer_ids][]", question.id, #saved_answer.multiple_choice_answer_ids.include?(question.id) %>
<%= question.title %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
Refer: http://railscasts.com/episodes/17-habtm-checkboxes?view=asciicast

Using form_for with Awesome Nested Set

I have a Comment model with the acts_as_nested_set enabled, but when I try to do something like this (for nested comments), i receive the error "comment_comments_path not found", presumably because the default pathing doesn't work with Awesome Nested Set. How do I get around this?
<%= form_for([#comment, #comment.children.build]) do |f| %>
<%= f.text_area :content, :placeholder=>'What do you think?'%>
<%= f.submit 'Submit Reply'%>
<% end %>
I also tried this:
<%= form_for(#comment) do |f| %>
<% #comment.children.each do |sub| %>
<%= f.fields_for :children, sub do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>
<% end %>
but it didn't generate a textbox for me to type in.
You're very close, yeah you have to build it first then have fields for, so this:
<% #comment.children.build %>
<%= form_for([#comment]) do |f| %>
<%= f.fields_for :children do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<% end %>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>
This will have a form for all existing children + the new one. If you want only a form for a new child then you'll want this instead:
<%= form_for([#comment]) do |f| %>
<%= f.fields_for #comment.children.build, :children do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<% end %>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>

Resources