Rendering problem with double nested forms in Rails 6 + cocoon - ruby-on-rails

I'm using Rails 6 + cocoon gem with vanilla js. I'm creating a website with quizzes, and quizzes, questions to them and answers to questions should be created on one page. Because of that i used double nested forms:
class Test < ApplicationRecord
belongs_to :author, class_name: 'Teacher'
belongs_to :article, optional: true
has_many :questions, dependent: :destroy
accepts_nested_attributes_for :questions, reject_if: :all_blank
end
class Question < ApplicationRecord
belongs_to :test
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, reject_if: :all_blank
validates :title, presence: true
end
class Answer < ApplicationRecord
belongs_to :question
validates :content, presence: true
validate :validate_max_answer_amount, on: :create
scope :correct, -> { where(correct: true) }
private
def validate_max_answer_amount
errors.add :base, :invalid_amount, message: 'Too many answers!' if question.answers.count >= 5
end
end
The problem lies precisely in the display of fields when they are added using cocoon. For example:
Can't post here images, because i have 1 rep, so check here please
Initial form - 1st screenshot
Form after adding answers - 2nd screenshot (expected that new fields would be lower than old one)
Form after adding questions - 3rd screenshot (expected that new fields would be lower than old one & that new fields would contain field for the first answer)
My View files:
tests/_form.html.slim:
=render 'shared/errors', object: #test
=form_with model: [:teacher, #test], local: true do |f|
=f.number_field :author_id, class: 'hidden'
=f.number_field :article_id, class: 'hidden'
.mb-3.add-questions
p
| Add questions:
.mb-3
=f.fields_for :questions do |q|
=render 'teacher/questions/question_fields', f: q
br
br
=link_to_add_association 'Add one more question', f, :questions, partial: 'teacher/questions/question_fields'
=f.submit 'Submit', class: 'btn btn-outline-success btn-lg mb-4'
questions/_question_fields.html.slim:
.mb-3.row
.col-sm-2.col-form-label
=f.label :title, 'Title'
.col-sm-10.col-form-label
=f.text_field :title, class: 'form-control'
=f.fields_for :answers do |a|
=render 'teacher/answers/answer_fields', f: a
=link_to_add_association 'Add one more answer', f, :answers, partial: 'teacher/answers/answer_fields'
answers/_answer_fields.html.slim:
.mb-1.row
.col-sm-1
.col-sm-2.col-form-label
=f.label :content, 'Enter content'
.col-sm-8.col-form-label
=f.text_field :content, class: 'form-control'
.col-sm-1.col-form-label
=f.check_box :correct, {class: 'form-check-input'}, true, false
I tried to remove =render 'teacher/answers/answer_fields' in questions/_question_fields.html.slim, but it didn't help with the problem with the questions. That is, new questions appeared anyway without an answer field.
I haven't figured out how to try to solve the problem with adding fields for answers (so that new fields appear below the old ones), so I hope for your help!

Related

Guidance creating Rails App

I am developing a website which will host different tests on any subject.
I am using nested forms for referencing.
An exam has questions and a question has 4 options and every question has correct answers.
the models are like this:
class Exam < ActiveRecord::Base
has_many :questions
validates :name, presence: true
accepts_nested_attributes_for :questions,
reject_if: proc {|attributes| attributes['content'].blank?},
allow_destroy: true
end
class Question < ActiveRecord::Base
belongs_to :exam
has_many :correct_answers
validates :content, presence: true
has_many :options
accepts_nested_attributes_for :options,
reject_if: proc {|attributes| attributes['content'].blank?},
allow_destroy: true
accepts_nested_attributes_for :correct_answers, reject_if: proc {|attributes| attributes['content'].blank?},
allow_destroy: true
end
class Option < ActiveRecord::Base
belongs_to :question
end
Now i am not able to understand how to create a web form which can submit the results and can compare the selected choice with correct answer, then render the view with correct answer and selected answers.
Please help.
I guess you can use something simple like:
<%= form_for(#exam) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :question %>
<%= f.text_field :question%>
<%= f.submit Submit %>
FYI just read this article if you need any further help with your form
-> https://www.launchacademy.com/codecabulary/learn-rails/writing-forms

form validation with nested models in Rails

I have this problem. I need to validate the attributes of two models in the same form in Rails. One is the parent of the other.
The form is like this:
<%= semantic_form_for #professional do |pro| %>
<%= pro.inputs :id => "information" do %>
<%= pro.input :name, label: t("Artistic Name") %>
<%= pro.semantic_fields_for #user do |user| %>
<%= user.inputs :id => "register" do %>
<%= user.input :email, :placeholder=>"email#example.com" %>
<%= user.input :password, label: t('Password') %>
<%end%>
<% end %>
<% end %>
<% end %>
The models I am using are like this:
User:
class User < ActiveRecord::Base
belongs_to :role, polymorphic: true
validates :email, :password, presence: true
end
Professionals:
class Professional < ActiveRecord::Base
has_one :user, as: :role, dependent: :destroy
accepts_nested_attributes_for :user
validates :date_birthday, :gender, :height, :name, :description, :Weight, :address, :languages,:services, :category, :phonenumber, :fullname, :hair_color, :age, :orientation, presence: true
end
So, what is the problem?
When I clicked in the submit button the professional attributes are marked but not the users attributes.
Like this:
The fields marked in red belongs to the professional model but the fields email and password belongs to the user model aren't marked in red when it should be because they are empty.
What can i do? I need the warning message for the user is attributes too
Thanks in advances.
We've achieved what you need before.
We had to use inverse_of so that the object was a singular piece of data (rather than multiple pieces as is the case by default):
#app/models/user.rb
class User < ActiveRecord::Base
belongs_to :role, polymorphic: true, inverse_of: :user
validates :email, :password, presence: true
end
#app/models/professional.rb
class Professional < ActiveRecord::Base
has_one :user, as: :role, dependent: :destroy, inverse_of: :role
accepts_nested_attributes_for :user
end
This will help.
You also need to make sure you're passing these objects correctly (I see so many people not doing this).
You need to tell Professional to validate the associated User:
class Professional < ActiveRecord::Base
...
validates_associated :user

Attachment doesn't filled in edit form

Rails 4.2.1, Ruby 2.2.1 and PostgreSQL 9.3
I have region and pattern models
class Region < ActiveRecord::Base
has_many :patterns, dependent: :destroy
accepts_nested_attributes_for :patterns, reject_if: :all_blank, allow_destroy: true
end
class Pattern < ActiveRecord::Base
belongs_to :region
has_attached_file :picture
validates_attachment_content_type :picture, content_type: "image/png"
end
And nested form in slim format with cocoon gem
= simple_form_for(#region) do |f|
= f.simple_fields_for :patterns do |pattern|
= render 'pattern_fields', f: pattern
.links
= link_to_add_association 'add pattern', f, :patterns
_pattern_fields.html.slim view
.nested-fields
.form-inline
= f.input :picture, as: :file
= link_to_remove_association f, class: 'btn btn-default btn-xs' do
.glyphicon.glyphicon-remove
I can easily create region with multiple patterns, but when I click edit, file fields are empty.
Is there nice way to properly work with file fields and rails forms with paperclip?

Has_one Association breaking in Edit

I have a nested form using the cocoon gem that gests 5 classes deep. They are all belongs_to and has_many except one that is the 2nd to most nested class with a has_one and belongs_to association. Whenever I edit it, it gets deleted and recreates an instance (not what I want) any ideas?
class FirmwaresController < ApplicationController
def index
#firmwares = Firmware.all
end
def new
#firmware = Firmware.new
end
def edit
#firmware = Firmware.find(params[:id])
end
end
class Setting < ActiveRecord::Base
belongs_to :menu_item
has_many :selections, dependent: :destroy
has_many :dependencies
attr_accessible :kind, :name, :placement, :selections_attributes
accepts_nested_attributes_for :selections, reject_if: :all_blank, allow_destroy: true
validates_presence_of :kind
end
class MenuItem < ActiveRecord::Base
belongs_to :menu
belongs_to :dependency
has_one :setting, dependent: :destroy
attr_accessible :dependency_id, :menu_for, :name, :placement, :setting_attributes
accepts_nested_attributes_for :setting, reject_if: :all_blank, allow_destroy: true
validates_presence_of :name
end
_menu_items.html.haml
.row-fluid
.input-prepend
= f.input :name, label: "Menu Item Name"
.input-append
= f.input :placement, label: "Order in Menu (X.Y)", as: :string
= f.simple_fields_for :setting do |settings_form|
= render 'setting_fields', f: settings_form
%p
= link_to_add_association "Has Setting?", f, :setting, class: "btn btn-primary btn-small add_setting_link"
= link_to_remove_association 'Remove Menu Item', f, class: "btn btn-danger btn-small remove_menu_item"
_setting_fields.html.haml
.row-fluid
.input-prepend
= f.input :kind, label: "Type", collection: setting_kinds, input_html: {class: "setting_type"}
.input-append
= link_to_remove_association 'Remove Setting', f, class: 'btn btn-danger btn-small remove_setting_link'
.setting_selection{style: "display: none;"}
= f.simple_fields_for :selections do |selections_form|
= render 'selection_fields', f: selections_form
%p= link_to_add_association 'Add Selection Option', f, :selections, class: "btn btn-primary btn-small"
I assume the has_one association you're referring to is the has_one :setting in MenuItem. If so, you might try adding update_only: true to your accepts_nested_attributes_for :setting options. From the documentation (emphasis mine):
By default the :update_only option is false and the nested attributes are used to update the existing record only if they include the record's :id value. Otherwise a new record will be instantiated and used to replace the existing one. However if the :update_only option is true, the nested attributes are used to update the record’s attributes always, regardless of whether the :id is present.
This question is old, but this could help some people:
The reason the association was always recreated for me, was that I had forgotten to include :id in the permitted parameters of phone_number_attributes! If you forget to do that, rails wont get the id and will recreate a new record to replace the old one.
def user_params
params.require(:user).permit(
:avatar,
:remove_avatar,
{ id_photo_attributes: [:photo, :remove_photo] },
{ phone_number_attributes: [:id, :phone_number] } # dont forget :id here!
)
end

Rails 3.2 Two Forms, One Hidden

I have two sections in a form, and I have a button that toggles their visibility. Is there a way to restrict the submit button from sending parameters from the hidden one? It's unfortunately creating courses without names or numbers, and it is not selecting an existing course if I use the collection_select.
projects/new.html.haml
= form_for [#user, #project] do |f|
# This part of the form is mostly shown to the user, but is failing to work correctly
= f.collection_select :course_id, #courses, :id, :name, { prompt: true }
# This part of the form is typically hidden, javascript reveals it.
.hidden
= f.fields_for :course do |builder|
= builder.text_field :name, class: 'large', placeholder: 'Ex: Calculus I'
= builder.label :number, 'Number'
= builder.text_field :number, class: 'new_project_course_number', placeholder: 'Ex: MATH-101'
= builder.hidden_field :user_id, value: current_user.id
project.rb
belongs_to :user
belongs_to :course
attr_accessible :course_id, :course_attributes
accepts_nested_attributes_for :course
course.rb
belongs_to :user
has_many :projects
user.rb
has_many :projects
has_many :courses
Please let me know if I am leaving off any vital information accidentally.
I think you might be looking for reject_if param for your nested attribute set.
For example:
accepts_nested_attributes_for : course, :reject_if => proc { |attributes|
attributes['name'].blank?
}
Or something like this. It allows you leave submitted form as is it, but only created nested course object, when name is preset (in your case, there is some placeholder, so you might use another check here)

Resources