Nested Elements within Simple Form - ruby-on-rails

I am trying to use Simple Form with my Rails 4 app.
I have models called projects.rb and programs.rb. Each of those 2 models has some common components. I handle these with another model called scope.rb. Each of projects and programs has a scope.
Within scopes, I have models called data.rb and materials.rb.
In my projects view, I ask several threshold questions. One of them is do you want data? (the answers true or false) The answer to that question is stored in my scope model. If the answer is true, then I want to ask further questions about the data (the answers are stored in my data model).
So, the relationships are that each of programs & projects has one scope. Each of data and materials belongs to scope.
For the moment, all of those data model questions are set out in my projects view.
The projects view when everything is set out in the projects view is as follows:
This is the scope question to find out whether further detail is required about data or materials:
<div class="col-md-3 col-md-offset-1">
<%= f.label 'What sort resources are involved in this project?', :class => 'question-project' %>
</div>
<div class="col-md-7">
<div class="response-project" style="margin-left:5%">
<%= f.simple_fields_for :scope do |s_all| %>
<%= s_all.input :if_datum, :as => :boolean, :label => false, inline_label: 'Data' %>
<%= s_all.input :if_material, :as => :boolean, :label => false, inline_label: 'Equipment or materials' %>
<% end %>
</div>
</div>
</div>
If the answer to data is true, then I ask:
<div class="col-md-3 col-md-offset-1">
</div>
<div class="col-md-7">
<%= f.simple_fields_for :scope do |data_s| %>
<%= data_s.simple_fields_for :datum do |d| %>
<%= d.label 'Is this data confidential or commercially sensitive?', :class => 'response-project' %> <br>
<%= d.collection_radio_buttons :confidential, [[true, ' Yes '] ,[false, ' No']], :first, :last, {:item_wrapper_class => 'inline'}, {:class => "radio-inline response-project" } %>
<%= d.input :prim_sec, label: 'What sort of data do you want?', label_html: {class: 'response-project'}, collection: ["Primary", "Secondary", "Both" ], prompt: "Choose one", item_wrapper_class: 'inline' %>
<% end %>
<% end %>
</div>
</div>
</div>
This all works fine, except that i want to use the same forms in my programs model. That's why I'm trying to extract them into partial views in my data model so that I can use them in both the projects and programs models.
When I start with the data/_form view, with this extracted:
<div class="row">
<div class="col-md-3 col-md-offset-1">
</div>
<div class="col-md-7">
<%= f.simple_fields_for :scope do |data_s| %>
<%= data_s.simple_fields_for :datum do |d| %>
<%= d.label 'Is this data confidential or commercially sensitive?', :class => 'response-project' %> <br>
<%= d.collection_radio_buttons :confidential, [[true, ' Yes '] ,[false, ' No']], :first, :last, {:item_wrapper_class => 'inline'}, {:class => "radio-inline response-project" } %>
<%= d.input :prim_sec, label: 'What sort of data do you want?', label_html: {class: 'response-project'}, collection: ["Primary", "Secondary", "Both" ], prompt: "Choose one", item_wrapper_class: 'inline' %>
<% end %>
<% end %>
</div>
</div>
</div>
And replace that code in my project view to render "data/form".
My problem is that when I move the data code to a data/_form to ask the data specific questions, I get the errors set out below. My view, when I try to do this is:
undefined local variable or method `f' for #<#:0x00000107ff3a90>
This is a reference to the line in the data/_form view that says:
<%= f.simple_fields_for :scope do |data_s| %>
Does anyone know what I've done wrong?
Thank you

I assume that you are doing something like this:
<%= simple_form_for project do |f| %>
<%= render 'data/form' %>
<% end %>
When rendering a partial, local variables are not passed down. So if you need to access f within your data/_form partial, you need to provide your partial with a corresponding local variable. Try this:
<%= simple_form_for project do |f| %>
<%= render 'data/form', f: f %>
<% end %>
Or, in a more verbose fashion:
<%= simple_form_for project do |f| %>
<%= render partial: 'data/form', locals: {f: f} %>
<% end %>
HTH!

Related

Prepopulate complex form values in rails edit view

I have an assessment form that renders a list of questions, and accepts answers for each question. The form data is submitted manually via ajax.
I'm having an issue when trying to pre-populate the data in my edit view. Here's how my views look:
edit.html.erb:
<div class="container">
<%= render 'assessment_form', :locals=> {:assessment => #assessment} %>
</div>
_assessment_form.html.erb:
<%= form_for #assessment do |f| %>
<%= f.submit 'Save', :class=> "btn btn-primary", :style=>"width: 100%;" %>
<div class="col-sm-2 col-sm-offset-10">
<h4>Show on Followup?</h4>
</div>
<% #assessment.questions.where(category:"S").each do |question| %>
<%= render 'question_fields', :question=> question, :f=> f %>
<% end %>
<%= f.hidden_field :patient_id, :value=> #assessment.patient.id %>
<%= f.hidden_field :template_id, :value=> #assessment.template_id %>
<% end %>
_question_fields.html.erb:
<p><%= question.content %></p>
<%= f.fields_for :answer do |builder| %>
<div class="row question">
<div class="col-sm-2 pull-right toggle">
<%= builder.check_box :tracking, {:checked=> false, :class=>"trackable", :data => {:'on-text' => "Yes", :'off-text' => "No", :'on-color'=> "success", :question => question.id}}, 0 , 1 %>
</div>
<div class="col-sm-10">
<%= builder.text_area :content, :class=>"form-control question-field", :data => {:question => question.id} %>
</div>
</div>
<% end %>
But none of the answers content are rendering in the view, the form fields are blank.
Here's an example call: Assessment.last.answers.first.content will give me the string "test". That should be showing up in my text_area box but it's not.
Just do, the instance variable #assessment is passed to the partial.
<%= render 'assessment_form' %>

Rails - dynamically build nested object inside nested object partials (Cocoon)

Currently, I'm building a Medium-like blog service which users can add article parts(text, image, youtube...etc) that composite the article body.
Article model has many ArticlePart model and to create nested form dynamically, I'm using cocoon gem.
Here's my current code.
_form.html.erb
<%= link_to_add_association("Add New Article Part", f, :article_parts,{:data => {"association-insertion-node" => "#article" }}) %>
<ul class="sortable">
<div id="article">
<%= f.fields_for :article_parts %>
</div>
</ul>
_article_part_fields.html.erb
<li class="nested-fields">
<h2>Text Part</h2>
<%= f.hidden_field :position %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= link_to_remove_association("Delete part", f) %>
<h2>Insert New Article Part Here</h2>
</li>
Above works fine but what I want to do is to display "link_to_add_association" where "Insert New Article Part Here" blocks in _article_part_fields.html.erb so that users can add new article part anywhere they want to.
I tried to do it as below by passing parent object form to nested object form, but this code causes stack level too deep error.
<li class="nested-fields">
<h2>Text Parts</h2>
<%= f.hidden_field :position, :class => "position" %>
<%= f.label :title %>
<%= f.text_field :title, :class => "fld-name required" %>
<%= link_to_remove_association("Delete part", f) %>
<h2>Insert New Part Here</h2>
<%= link_to_add_association("商品", parent_form, :article_parts,{:render_options => {:locals => {:parent_form => parent_form}}, :data => {"association-insertion-node" => "#article" }}, :class => 'btn btn-ctrl btn-lg') %>
</li>
Any help appreciated to get this working, or suggest another way to achieve this.
Thanks in advance!

Simple_Form nesting expected Array (got String) for param `answer_ids'

I want a user to be able to fill out multiple choice questions on a form. The form consists of Multiple Surveys, each with multiple questions (and each question is multiple choice)
I can't seem to store the multiple survey bit. I want a answer_ids which I can then save on a User has_many Answers Through: :user_answer relationship. But I'm struggling.
I get the following error:
expected Array (got String) for param `answer_ids'
Here's my form:
<%= simple_form_for [current_user], :url => competition_enter_path, :method => :POST do |u| %>
<% #surveys.each do |survey| %>
<%= u.simple_fields_for [survey] do |f| %>
<div class="contnt1">
<%= survey.name %>
<br />
<% survey.questions.each do |qq| %>
<%= f.simple_fields_for qq do |q| %>
<h3><%= qq.question %></h3>
<%= q.association :answers,
label: false,
collection: qq.answers,
as: :"#{qq.question_type.code}",
:label_method => :answer,
required: true
%>
<% end %>
<% end %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= u.submit %>
</div>
<% end %>
I had almost the same problem. I sort of fixed by replacing:
collection: qq.answers,
with:
collection: qq.answers.map{|v| [v.property_for_answer_text, v]}
As far as I can tell, the problem is that the value that the form sees is a string and not an Answer object. And thus it tries to send String where it should be Answer object.

Form not updating values in the database if the class of a framework is used

I m using the ink framework for styling my web application. And for styling form i am using this http://ink.sapo.pt/index.php/forms.
<form class= "ink-form inline">
<%= form_for(#document, :remote => true) do |f| %>
<fieldset>
<div class="control required validation error">
<%= f.label :title, :class => "short" %>
<%= f.text_field :title, :class => "short" %>
</div>
</fieldset>
<% end %>
</form>
In the above form ive put the class= ink-form inline to style the form. Doing this styles my form but it does nt update the values in the database. When i use this code
<%= form_for(#document, :remote => true, :class => "ink-form inline") do |f| %>
then it updates the values in the database but it doesnt style the form. I am not getting where the problem is. Please help.!!
Try this!
<%= form_for(#document, :remote => true, :html => {:class => "ink-form inline"}) do |f| %>
<fieldset>
<div class="control required validation error">
<%= f.label :title, :class => "short" %>
<%= f.text_field :title, :class => "short" %>
</div>
</fieldset>
<% end %>
If you had inspected your earlier code in the browser, you would see two form tags (one within the other). The reason is form_for generates its own form and that is where you would want to provide the options.

Work after user creation

I create a new user with basic fields as user name and password. Then I redirect to another page where the user is allowed to complete his profile. The page looks like this.
Ok, I created the user first. Then I redirected the user to complete his profile. The profile page looks like this
<h1>User successfully created</h1>
<h3>Would you like to complete your profile now?</h3>
<%= render #profile %>
<%= render #address %>
<%= button_to 'Save',{
:controller => "users",
:action => "update",
:id => #user.id,
:profile => #profile,
:address => #address
}, :method => :put %>
The code above executes the update action in the controller. However, I am getting nil for the #profile and #address objects. I guess the button_to is having no effect on the profile and address partials.
The address partial looks as follows
<%= form_for(#address) do |f| %>
<% if #address.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#address.errors.count, "error") %> prohibited this address from being saved:</h2>
<ul>
<% #address.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<fieldset>
<legend>Addresss</legend>
<div class="field">
<%= f.label :street_address %>
<%= f.text_field :street_address, :size => 40 %>
</div>
<div class="field">
<%= f.label :street_address_2 %>
<%= f.text_field :street_address_2, :size => 40 %>
</div>
<div class="field">
<%= f.label :city %>
<%= f.text_field :city, :size => 40 %>
</div>
<div class="field">
<%= f.label :state %>
<%= f.text_field :state, :size => 40 %>
</div>
<div class="field">
<%= f.label :zip_code %>
<%= f.text_field :zip_code, :size => 40 %>
</div>
<% end %>
I would appreciate if anyone would be able to help me on this.
The button_to method only creates a button which an be used to call an controller/ go to another page.
If you want to allow the user to modify fields, you need to use a form. Please read this guide on forms for more information, especially part 2 is of interest for your situation I guess.
Edit: You need a submit button in your form to submit it, not a button_to outside the form. If you want to have both partials submitted at the same time, you need 1 big form and a controller which is able to process the data of both models.

Resources