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
Related
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!
Using simple_form to build a nested form for a WorkoutSet model with the following fields:
intro_video
get_ready
outro_video
WorkoutStep (another nested model)
I want to be able to select an intro_video out of a select
As WorkoutSet is inside Workout, the forms look like this:
WorkoutSet.rb
class WorkoutSet < ActiveRecord::Base
has_and_belongs_to_many :workout_steps, :join_table => :sets_steps, dependent: :destroy
has_and_belongs_to_many :workouts, :join_table => :workout_sessions
accepts_nested_attributes_for :workout_steps, allow_destroy: true
has_one :intro_video_usage, class_name: 'VideoUsage::Intro', as: :parent, dependent: :destroy
has_one :intro_video, through: :intro_video_usage, source: :video
accepts_nested_attributes_for :intro_video
has_one :get_ready_video_usage, class_name: 'VideoUsage::GetReady', as: :parent, dependent: :destroy
has_one :get_ready_video, through: :get_ready_video_usage, source: :video
has_one :congrats_video_usage, class_name: 'VideoUsage::Congratulations', as: :parent, dependent: :destroy
has_one :congrats_video, through: :congrats_video_usage, source: :video
end
_form.html.haml
%h2 Sets
.sets.some{ :style => "margin-left: 25px" }
= f.simple_fields_for :workout_sets do |set|
= render 'workout_set_fields', f: set
.links
.button-row
= link_to_add_association 'add set', f, :workout_sets
_workout_set_fields.html.haml
.nested-fields
%h2 New set - #{link_to_remove_association 'Delete', f}
= f.label :title
= f.text_field :title
= f.input :intro_video, :collection => Video.all, :label_method => :title, :value_method => :id, :include_blank => false
%br
%br
#sets.some{ :style => "margin-left: 25px" }
= f.simple_fields_for :workout_steps do |step|
= render 'workout_step_fields', f: step
.links
.button-row
= link_to_add_association 'add step', f, :workout_steps
The select is rendered and the values looks fine until I save the model whitelisting the following parameters:
params.require(:workout).permit(:title, :pro, :image, warmup_attributes: [:id, :_destroy, {main_video_ids: []}], workout_sets_attributes: [:id, :_destroy, :title, :intro_video, workout_steps_attributes: [:id, :_destroy, {main_video_ids: []}] ])
Also, I notice that in the line f.input :intro_video the parameter being sent is intro_video, instead of intro_video_attributes
Thanks in advance.
I can't seem to successfully create new resources from a nested form that has polymorphic associations.
It seems the problem lies in validations with polymorphic 'belongs_to' relationships. For example:
class DealerUser < User
belongs_to :dealer, polymorphic: true, foreign_key: :loginable_id, foreign_type: :loginable_type
validates :dealer, presence: true
end
I am attempting to create a new resource called Dealer.
class Dealer < ActiveRecord::Base
has_many :dealer_locations, dependent: :destroy
has_one :dealer_user, as: :loginable, dependent: :destroy
accepts_nested_attributes_for :dealer_locations, allow_destroy: true
accepts_nested_attributes_for :dealer_user, allow_destroy: true
validates :name, presence: true, length: { maximum: 255 }, uniqueness: { case_sensitive: false }
validates_associated :dealer_locations
end
My form code:
<%= form_for(#dealer) do |d| %>
<%= render 'shared/error_messages', object: d.object %>
<br>
<div class="form-group">
<%= d.label :name %>
<%= d.text_field :name, class:"form-input-field" %>
</div>
<h4>Login Credentials</h4><br>
<%= d.fields_for :dealer_user do |du| %>
<div class="form-group">
<%= du.label :email %>
<%= du.text_field :email, class:"form-input-field" %>
</div>
<div class="form-group">
<%= du.label :password %>
<%= du.password_field :password, class:"form-input-field" %>
</div>
<% end %>
<%= d.submit class: "btn btn-large btn-primary" %>
<% end %>
Controller:
class DealersController < ApplicationController
def new
#dealer = Dealer.new
#dealer.build_dealer_user
end
def create
#dealer = Dealer.new(dealer_params)
puts #dealer.inspect
puts #dealer.dealer_user.inspect
if #dealer.save
redirect_to(#dealer, :notice => 'Dealer was successfully created.')
end
def dealer_params
params.require(:dealer).permit(:name, dealer_user_attributes: [:email, :password, :id])
end
end
When I submit the form, I am getting DealerUser.dealer can't be blank error.
#<Dealer id: nil, name: "NAME", created_at: nil, updated_at: nil>
#<DealerUser id: nil, type: "DealerUser", email: "fake#email.com", loginable_id: nil, loginable_type: "Dealer",...
It looks like the associations are working, since you can see type fields are set.
Update 3/11/16: params
{"utf8"=>"✓", "authenticity_token"=>"...",
"dealer"=>{"name"=>"ZZ WATER",
"dealer_user_attributes"=>{"email"=>"...", "password"=>"[FILTERED]"},
"dealer_locations_attributes"=>{"0"=>{"phone"=>"...", "contact_email"=>"...",
"address_attributes"=>{"line_1"=>"line1", "line_2"=>"", "city"=>"city", "country_code"=>"US", "state_code"=>"CA", "zip_code"=>"00000"}}}}, "commit"=>"Create Dealer"}
Is this an order of operations issue? DealerUser needs an ID to pass validation, but the Dealer ID wont get set until it's saved to the DB, which isn't happening since it's not passing validation. Can someone offer me some guidance.
Also, this is a simplified version of what I'm working on, there are nested locations and addresses too. I'm also only a couple months into using ruby on rails. Thank you.
I created a fresh similar project. And I also got the same error. In my attempt to fix this problem, I stumbled upon inverse_of, and it now worked.
Now try
class DealerUser < User
# ..
belongs_to :dealer, polymorphic: true, foreign_key: :loginable_id, foreign_type: :loginable_type, inverse_of: :dealer_user
# ..
end
class Dealer < ActiveRecord::Base
# ..
has_one :dealer_user, as: :loginable, dependent: :destroy, inverse_of: :dealer
# ..
end
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?
My models:
class Topic < ActiveRecord::Base
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :topic
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, reject_if: :all_blank, allow_destroy: true
end
class Answer < ActiveRecord::Base
belongs_to :question
end
My controller questions_controller:
class QuestionsController < ApplicationController
expose(:topic) { Topic.find(params[:topic_id]) }
expose(:question, attributes: :question_params)
expose(:questions) { topic.questions }
def create
if topic.questions.create(question_params)
redirect_to topic
else
render 'new'
end
end
private
def question_params
params.require(:question).permit(
:title,
:instructions,
answers_attributes: [:id, :answer, :correct, :question_id, :_destroy]
)
end
end
/questions/_form:
= simple_form_for [:topic, question] do |f|
= f.input :title, label: "Question:", placeholder: "Your question here."
= f.input :instructions, label: "Instructions:", placeholder: "If this question requires special instructions, put them here."
%br
%h3
Answers
#answers
= f.simple_fields_for :answers do |answer|
= render 'answer_fields', f: answer
.links
= link_to_add_association 'add answer', f, :answers
= f.submit class: "button small radius expand success"
/questions/answer_fields:
.nested_fields
= f.input :answer
= f.input :correct, as: :boolean
= link_to_remove_association "remove task", f
routes.rb:
Rails.application.routes.draw do
resources :topics do
resources :questions
end
root to: 'topics#index'
end
I'm using cocoon to manage my nested forms.
When I go to /topics/.:id and press the 'Add New Question' button, it takes me to the /topics/.:id/questions/new path, and when I press the 'add answer' button, cocoon renders 3 new spaces for answers. Also, the items are not being deleted if I press the 'remove answer' link.
Why is the view rendering 3 answer fields?
Why is the 'remove answer' link not working?