Rails, Simple Form, Nested Forms - ruby-on-rails

class Project
has_many :project_questions, dependent: :destroy#, through: :projects
accepts_nested_attributes_for :project_questions
end
I am trying to make an app with rails 4 and Simple Form.
I have models called projects, project_questions and project_answers.
The associations between them are:
Projects:
has_many :project_questions, dependent: :destroy#, through: :projects
accepts_nested_attributes_for :project_questions
Project questions:
belongs_to :project#, counter_cache: true
has_many :project_answers, dependent: :destroy
belongs_to :user
accepts_nested_attributes_for :project_answers
belongs_to :user
Project answers:
belongs_to :project_question#, counter_cache: true
belongs_to :user
User:
has_many :project_questions
has_many :project_answers
class ProjectQuestions
belongs_to :project#, counter_cache: true
has_many :project_answers, dependent: :destroy
belongs_to :user
accepts_nested_attributes_for :project_answers
end
ProjectAnswer:
belongs_to :project_question#, counter_cache: true
belongs_to :user
My objective is to have a partial on my projects show page which displays the questions and their answers relating to the project and to have a link to another form where you can ask a question or answer one. I am struggling.
In my controllers I have:
Projects:
def project_params
params.require(:project).permit(project_question_attributes: [:title, :content, :user_id, :project_id,project_answer_attributes: [:answer, :project_question_id]],
Project_question:
def new
#project_question = ProjectQuestion.new
#project_id = params[:project_id]
#project_question.project_answers[0] = ProjectAnswer.new
end
Project_answer:
def new
#project_answer = ProjectAnswer.new
end
def project_question_params
params[:project_question].permit(:id, :title, :content, :project_id, :user_id,project_answer_atttibutes: [:id, :answer, :project_question_id, :user_id])
end
Then in my views I have:
Project#show:
<% if current_user.id == #project.creator_id %>
<%= link_to 'Ask a question', new_project_project_question_path(:project_id => #project.id) %>
<% end %>
<%= render 'project_questions/pqps' %>
Project_question#pqps (a partial):
<div class="containerfluid">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="categorytitle">
<%= #project_question.try(:title) %>
</div>
<div class="generaltext">
<%= #project_question.try(:content) %>
</div>
<span class="editproject">
<% if current_user.id == #project.creator_id %>
<% end %>
</span>
</div>
</div>
</div>
My project_questions form partial is:
<div class="containerfluid">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<% f.simple_fields_for :project_questions do |f| %>
<%= f.input :project_id, as: :hidden, input_html: {value: #project_question_id} %>
<%= f.input :title, label: 'Question:', :label_html => {:class => 'categorytitle'}, placeholder: 'Type your question here', :input_html => {:style => 'width: 100%', class: 'categorytitle'} %>
<%= f.input :content, label: 'Is there any context or other information?', :label_html => {:class => 'categorytitle'}, placeholder: 'Context might help to answer your question', :input_html => {:style => 'width: 100%', rows: 5, class: 'generalprojecttext'} %>
<%= f.button :submit %>
<% end %>
</div>
</div>
</div>
Project_answer#pa (a partial):
(not yet written - still trying to get the questions to work)
My routes are:
resources :projects do
resources :project_questions do
resources :project_answers
end
end
When I try this, I get an error in my project_questions form that says:undefined local variable or methodf' for #<#:0x000001013d8298>`
I can't see where it is talking about f outside the form block. I have tried adding another line to the form for simple_fields for project and then nesting the project questions form inside of it, but that doesn't change anything.
Can anyone see what I've done wrong?
Thank you

You should change this line <% f.simple_fields_for :project_questions do |f|
%> to this <%= simple_form_for :project_questions do |f| %> in order to make it work.

The plataformatec simple_form wiki has a pretty good instructional page on using nested forms.
(Just as a side note, I find that it's often easier to diagnose problems without using partials. Once everything is working, you can clean-up by refactoring into partials.)
I believe you need to pass a local variable to your partial, so it knows what the first "f" refers to.
<%= render 'project_questions/pqps', locals: {f: f} %>
(You also may choose to use a different local variable in the partial for project_questions, just so you're always clear what is being referenced in error messages.)

Related

Rails - Simple Form & Nesting models

I have three models in my Rails 4 app.
I have a projects, project questions and a project answers model.
Projects
has_many :project_questions, dependent: :destroy#, through: :projects
accepts_nested_attributes_for :project_questions
Project questions has these associations:
belongs_to :project#, counter_cache: true
has_many :project_answers, dependent: :destroy
belongs_to :user
accepts_nested_attributes_for :project_answers
Project answers associations are:
belongs_to :project_question#, counter_cache: true
belongs_to :user
My routes.rb has:
resources :projects do
# patch '/toggle-draft', to 'projects#toggle_draft', as: 'toggle_draft'
resources :project_questions do
resources :project_answers
end
end
In my projects_controller, I have permitted params for project questions and answers as follows:
project_question_attributes: [:title, :content, :user_id, :project_id,
project_answer_attributes: [:answer, :project_question_id]],
These params are also permitted in the Project questions and project answers controllers.
In my projects view, I want to render a partial that I have made in my project_questions view folder.
In projects show page, I have:
<%= link_to 'Ask a question', new_project_question_path %> <% end %>
<%= render 'project_questions/pqps' %>
In my project_questions partial which is called _pqps, I have;
<div class="containerfluid">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<% f.simple_fields_for :project_questions, #project.project_questions.build do |q| %>
<div class="categorytitle">
<%= q.title %>
</div>
<div class="generaltext">
<%= q.content %>
</div>
<%= render 'project_answers/show' %>
<span class="editproject"> <% if current_user.id == #project.creator_id %>
<%= link_to 'Answer this question', new_project_answer_path %>
<% end %>
</span>
<% end %>
</div>
</div>
</div>
However, when I try this, I get an error that says:
undefined local variable or method `new_project_question_path'
Can anyone see what i've done wrong?
Thank you

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 %>

Rails 3.1+ nested form model not rendering properly

I have a basketball app, where a Roster has many Players, and a Player belongs to a Roster.
Roster.rb
class Roster < ActiveRecord::Base
has_many :players
accepts_nested_attributes_for :players
attr_accessible :class_year, :jersey_number, :player_id, :team_id
end
Player.rb
class Player < ActiveRecord::Base
has_many :gamelogs
belongs_to :rosters
validates_presence_of :first_name, :last_name
attr_accessible :first_name, :last_name, :active
end
And my view that is only rendering first part of the form, but NOT the nested one
<div class="well">
<h2>New Player</h2>
<%= simple_form_for #new_player, :html => { :class => 'form-horizontal' } do |f| %>
<%=f.simple_fields_for :players do |x|%>
<%= x.input :first_name %>
<%= x.input :last_name %>
<%end%>
<%=f.input :class_year %>
<%=f.input :jersey_number %>
<%=f.input :team_id, :as => :hidden, :input_html => {:value => params[:id]}%>
<div class="well">
<%= f.button :submit, :class => 'btn-primary icon-plus-sign btn-success', :value => "Add To Team" %>
</div>
<%end%>
</div>
Image of it not working:
http://i.stack.imgur.com/Uoirp.png
I am using Simple_Form 2.0 and Twitter Boot Strap. Is there something I am not seeing? I feel like this should be simple, but I can't seem to figure out why it is not rendering. Thanks in advance.
You need an equal sign on your fields_for block:
<%= f.simple_fields_for :players do |x| %>
Edit:
All of this is assuming that #new_player == Roster.new
I had to do this with Formtastic, so it may be similar with Simple Form.
Looking at the source, it gives you an option to pass the nested object down to the nested form:
def simple_fields_for(record_name, record_object = nil, options = {}, &block)
So try doing something like this:
<%= f.simple_fields_for :players, #new_player.players.build do |x| %>

Resources