Deeply Nested Form Data not going into database, no errors - ruby-on-rails

I'm building a multi-nested form in rails 3. I'm using the formtastic_cocoon gem, but I don't think that has much bearing on this issue.
I've got users, users have tasks, tasks have steps.
The nesting is users>tasks>steps.
I can dynamically add and remove the task fields to the user, and the step fields from the tasks.
However, when I submit the form, the user gets tasks, but the task>steps don't get saved to the database.
Rails isn't returning any errors, just nothing happens.
My models are
Class User < ActiveRecord::Base
acts_as_authentic
has_many :tasks
accepts_nested_attributes_for :tasks, :reject_if=> proc {|attributes| attributes[:entry].blank?}, :allow_destroy => true
end
Class Task < ActiveRecord::Base
attr_accessible :entry
belongs_to :user
has_many :steps
accepts_nested_attributes_for :steps, :reject_if=> proc {|attributes| attributes[:title].blank?}, :allow_destroy => true
end
Class Step < ActiveRecord::Base
attr_accesible :title
belongs_to :task
end
In my form.html.erb I have
<%= semantic_form_for #user %>
<%= form.inputs :username, :password %>
<div>
<% form.semantic_form_fields_for :tasks do |builder| %>
<%= render 'task_fields', :f=>builder %>
<% end %>
<%= link_to_add_association 'add task', form, :tasks %>
</div>
The _task_fields.html.erb looks like this
<div class="nested-fields">
<%= link_to_remove_association "remove task", f %>
<%= f.inputs :entry %>
<div>
<% f.semantic_form_fields_form :steps do |builder| %>
<%= render 'step_fields' :f => builder %>
<% end %>
<%= link_to_add_association 'add step', f, :steps %>
</div>
</div>
lastly, the _step_fields.html.erb page is
<div class="nested-fields">
<%= link_to_remove_association "remove step", f %>
<%= f.inputs :title %>
</div>

Do you see this in the log?:
WARNING: Can't mass-assign protected attributes: steps_attributes
If so, add this to the Task model:
attr_accessible :steps_attributes

Related

Rails has_many :through create association and associated model on parent "show" view

I have three models in my rails 5 application... What I want to do is to be able to create a note on the person's "show" view, then the note should automatically link to that person and any other person I choose to attach the note to.
Here's where I got up to
Note
class Note < ApplicationRecord
has_many :person_notes
has_many :people, through: :person_notes
accepts_nested_attributes_for :person_notes
end
Person Note (Join table)
class PersonNote < ApplicationRecord
belongs_to :person
belongs_to :note
end
Person
class Person < ApplicationRecord
has_many :person_notes
has_many :notes, through: :person_notes
accepts_nested_attributes_for :person_notes
accepts_nested_attributes_for :notes
end
In my "show" section of my "people" controller I have the following:
def show
#notep = Note.new()
#person.notes << #notep
end
This is creating a join of a new note to my person record every time I open the page (obviously i only want the join to happen on the note I have created.)
I have rendered this in a modal as a partial in my "show" view (there is an "end" and a submit button but it's in between 3 divs and I know they weren't the cause of the issue so i didn't include them.:
<%= simple_form_for(#notep, remote: true) do |f| %>
<%= f.error_notification %>
<%= f.input :subject %>
<%= f.input :note %>
<%= f.input :date, html5: true %>
<div class="input-field">
<%= f.check_box :isalert, :id => "alert" %>
<%= f.label :isalert, :for => "alert" %>
</div>
<div class="input-field">
<%= f.check_box :archived, :id => "archived" %>
<%= f.label :archived, :for => "archived" %>
</div>
<div class="input-field">
<%= f.check_box :deleted, :id => "deleted" %>
<%= f.label :deleted, :for => "deleted" %>
</div>
<%= f.input :datecreated, html5: true %>
<%= f.input :user_id %>
<%= f.simple_fields_for :person_notes do |builder| %>
<%= builder.association :person, label_method: :lstfstfullname %>
<%= builder.input :deleted %>
<%= builder.input :datecreated, html5: true %>
<%= builder.input :user_id %>
<% end %>
You can probably tell I'm a total newb, but I'd appreciate any help I can get.
Thanks,
Leah
If I'm understanding this correctly, you'll want a separate Notes controller and create action to handle note creation. Then in your People show view, you can add a form and input field that submits to NotesController#create.

How to remove has_many through association from Parent model by unchecking checkbox?

I'm really new to RoR and programming in general, and have read through a mind-numbing number of stackoverflow/railsforum/railscasts...etc. already and just can't seem to find a solution. My problem is nearly identical to this post and this post--both of which have unfortunately not been answered.
I have 3 models: Project, Task, and Assignments. I have a collection of checkboxes of existing Tasks (using simple_form and cocoon) that the user can select from, to add to a Project. Adding Tasks through checking their boxes works, but I cannot uncheck boxes and remove the association (Assignment). When I try to save my changes, I'm met with this error:
ActiveRecord::RecordNotFound in ProjectsController#update error:
Couldn't find Task with ID=28 for Project with ID=39.
def raise_nested_attributes_record_not_found!(association_name, record_id)
My guess is that AR is looking for a Task that has already been disassociated from the Project, but that's just a hunch. If that's the case, I'd still have no clue where and how to fix this problem.
Project.rb
class Project < ActiveRecord::Base
has_many :assignments, dependent: :delete_all
has_many :tasks, :through => :assignments
accepts_nested_attributes_for :tasks, reject_if: :all_blank
accepts_nested_attributes_for :assignments, :allow_destroy => true
Task.rb
class Task < ActiveRecord::Base
has_many :assignments
has_many :projects, :through => :assignments
accepts_nested_attributes_for :assignments
Assignment.rb
class Assignment < ActiveRecord::Base
belongs_to :project
belongs_to :task
accepts_nested_attributes_for :project, :reject_if => :all_blank
Project controller#update
def update
#project = Project.find(params[:id])
params[:project][:task_ids] ||= []
if #project.update_attributes(project_params)
flash[:success] = "Your project has been updated!"
redirect_to #project
else
render 'edit'
end
end
private
def project_params
params.require(:project).permit(:job_code, :task_ids => [],
tasks_attributes:
[:id, :item, :description, :requirement, :complexity,
:est_time, :actual_time, :_destroy],
assignments_attributes: [:id, :_destroy, :task_id])
end
I would greatly appreciate any help/insight/hand-holding to solve this problem! Way too much time has been spent trying to figure it out on my own, considering my limited knowledge of rails.
Thanks!
EDIT: form code included
Project edit.html.erb
<% provide(:title, "Edit project") %>
<h1>Update your project status</h1>
<div class="row">
<%= minimal_form_for #project, html: { class: "form-inline"} do |f| %>
<% if #project.errors.any? %>
<%= render 'shared/error_messages', object: f.object %>
<% end %>
<h4>Choose an existing task</h4>
<%= f.association :tasks, :collection => Task.all.to_a, :label_method => :item,
:as => :check_boxes,
:wrapper => :vertical_radio_and_checkboxes,
:checked => params[:task_id] %>
<%= render 'form', f: f %>
<%= f.submit "Save changes", class: "btn btn-primary" %>
<% end %>
</div>
Project _form.html.erb
<h3>Tasks</h3>
<div id="tasks">
<%= f.simple_fields_for :tasks do |task| %>
<%= render "projects/task_fields", :f => task %>
<% end %>
<div class="links">
<%= link_to_add_association "Add task", f, :tasks, class: 'btn btn-primary' %>
</div>
</div>
Project _task_fields.html.erb
<div class="nested-fields">
<%= f.input :item %>
<%= f.input :description %>
<%= f.input :complexity, collection: Task.complexities.keys, :selected => '' %>
<%= f.input :est_time %>
<%= f.input :actual_time %>
<%= link_to_remove_association "Remove task", f, class: 'btn btn-primary' %>
</div>
You need to add a check_box named :_destroy to signal you want it deleted.
Check the guide on this matter: http://guides.rubyonrails.org/form_helpers.html#nested-forms

Cocoon - Wrong number of arguments (1 for 0) for look-up or create :belongs_to

Following the Cocoon wiki for implementing The look-up or create :belongs_to I'm receiving the error: wrong number of arguments (1 for 0). I'm not exactly sure what its referring to being that I'm following the tutorial verbatim aside from using slim as my precompiler. Here's what my code looks like:
Models
class Project < ActiveRecord::Base
belongs_to :user
has_many :tasks
accepts_nested_attributes_for :tasks, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :user, :reject_if => :all_blank
end
class User < ActiveRecord::Base
has_many :projects
end
Projects Form
<%= simple_form_for #project do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<h3>Tasks</h3>
<div id="tasks">
<%= f.simple_fields_for :tasks do |task| %>
<%= render 'task_fields', :f => task %>
<% end %>
<div class="links">
<%= link_to_add_association 'add task', f, :tasks %>
</div>
</div>
<div id="user">
<div id="user_from_list">
<%= f.association :user, collection: User.all(:order => 'name'), :prompt => 'Choose an existing user' %>
</div>
<%= link_to_add_association 'add a new person as owner', f, :user %>
</div>
<%= f.submit %>
<% end %>
Projects Controller
...
def project_params
params.require(:project).permit(:name, :description, tasks_attributes: [:id, :description, :done, :_destroy], user_attributes: [:id, :name])
end
Backtrace
app/views/projects/_form.html.erb:16:in `block in _app_views_projects__form_html_erb___3132123068035883478_70337216288160'
app/views/projects/_form.html.erb:1:in `_app_views_projects__form_html_erb___3132123068035883478_70337216288160'
app/views/projects/new.html.erb:3:in `_app_views_projects_new_html_erb__2418839848133678570_70337176808940'
ActiveRecord#all has been changed in rails 4 - this is now doing what scoped used to do. It does not expect any extra params. Instead of User.all(order: 'name') do:
User.order(:name)

Creating a form based on a :has_many through relationship

I am new to ruby and I am trying to put together a form that will allow you to add items to an order. The form will need to take a quantity for each item in the order.
class Order < ActiveRecord::Base
belongs_to :restaurant
has_many :selections
has_many :items, :through =>:selections;
end
class Selection < ActiveRecord::Base
belongs_to :order
belongs_to :item
end
class Item < ActiveRecord::Base
belongs_to :menu
has_many :selections
has_many :orders, :through => :selections
end
class Restaurant < ActiveRecord::Base
has_many :orders
has_many :menus
has_many :items, :through => :menus
end
class Menu < ActiveRecord::Base
belongs_to :restaurant
has_many :items
end
order controller
# GET /orders/new
def new
#order = Order.new
#restaurant.items.all.each do |item|
#order.selections.build
end
end
orders/_form.html.erb :
The form is supposed to list out the available items and allow you to enter the quantity for an item.
<%= form_for [#restaurant,#order], :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :current_table, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :current_table, :class => 'text_field' %>
</div>
</div>
<% f.fields_for :selections do |ff| %>
<div class="control-group">
<%= ff.label :quantity, :class => 'control-label' %>
<div class="controls">
<%= ff.text_field :quantity, :class => 'text_field' %>
</div>
</div>
<% end%>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
course_orders_path, :class => 'btn' %>
</div>
<% end %>
When I try to render the page I get the following error:
undefined method `quantity' for
<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Selection:0x007ffa0287cd60>
I realize this is probably because I haven't initialized any selections but I'm not entirely sure how/where I should do that. When the form is submitted I want to create an order with a selection for each of the non-empty quantities.
So my first question is how do I construct my form so that I can take a quantity for each item that I know about?
Do I need to initialize anything in the order controller to make this work?
Can you give me any advice or point me to a tutorial that shows me how to set up the create method of the order controller?
EDIT:
I added some code to the Order controller and the form, so when I render the page I no longer get an error, but none of my 'selection' fields rendered. I confirmed with some logging and the debugger that I correctly 'build' 4 selections so I would expect those form elements show up.
Any ideas would be appreciated.
Are you missing a
accepts_nested_attributes_for :nested_class
somewhere?
Also, I had to do something like
<%= form_for [#restaurant,#order] do |f| %>
...
<%= f.fields_for :selections, #order.selections do |ff| %>
...
<% end %>
...
<% end %>

Creating a nested object/modal from an existing nested object/modal in Ruby on Rails

I am using deeply nested model in my project (using simple_form and cocoon). Everything works fine as long as all nested objects are new.
My problem is, that I want to create a nested object from an existing (nested) object.
Here is my model
class Application < ActiveRecord::Base
belongs_to :submitter
has_one :composition
accepts_nested_attributes_for :submitter, :composition
end
class Submitter < ActiveRecord::Base
has_one :spouse
has_many :children
has_many :receipts
has_many :applications
accepts_nested_attributes_for :spouse, :children, :receipts, :applications
end
class Child < ActiveRecord::Base
belongs_to :submitter
has_many :receipts
end
The working process looks like this:
new Application --> new Submitter --> new Child
All can be created using one form.
Additionally, I also want to implement the following process:
new Application --> existing Submitter --> new Child
The existing object should be chosen by a dropdown list box.
Here is the (simplified, working) code of the view:
new.html.erb
<%= simple_form_for(#application) do |f| %>
<%= f.simple_fields_for :submitter do |submitter| %>
<%= render "submitter_fields", :f => submitter %>
<% end %>
<% end %>
_submitter_fields.html.erb
<%= f.input :firstname %>
<%= f.input :lastname %>
<%= render "child", :f => f %>
_child.html.erb
<div id="childs">
<%= f.simple_fields_for :children do |child| %>
<%= render "child_fields", :f => child %>
<% end %>
<div class="links">
<%= link_to_add_association 'Add child', f, :children %>
</div>
</div>
_child_fields.html.erb
<div class="nested-fields">
<%= f.input :firstname %>
<%= f.input :lastname %>
<%= link_to_remove_association "Remove child", f %>
</div>
Now I want to add a dropdown list which is populated with all existing Submitters. For example:
<%= f.assosciation :submitter %>
And here starts my problem: To build the form for adding a new child to the selected submitter, I need to assign this object to the form builder. I have no idea how to do this.
Can somebody give me a hint how to implement this? Or is this scenario simply not possible?
Thanks in advance!
Christian
simple_fields_for takes a second argument the object: https://github.com/plataformatec/simple_form/blob/master/lib/simple_form/action_view_extensions/form_helper.rb#L33 maybe if you pass your existing submitter it will work.

Resources