Rails - Simple Form & Nesting models - ruby-on-rails

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

Related

Rails rendering nested comments use eager loading

I wanted to be able to allow users to add comments to recipes. I also wanted users to be able to comment on those comments. It appears to be working, but maybe there are too many queries going on. I have researched and seen a lot of closely related articles, but none seem to be helping the issue. No matter how I change it up, it doesn't work. I can make as many comments on comments as I want, but as soon as there are multiple comments to a recipe it crashes. It's like I can have one or the other, but not both or it will crash. Here is what I have so far:
comment.rb
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable
end
recipe.rb
class Recipe < ApplicationRecord
has_many :comments, as: :commentable
recipes/show.html.erb
<div class="">
<h5>Comments:</h5>
<div class="comment-form">
<hr />
<h3 class="subtitle is-3">Leave a reply</h3>
<%= render #recipe.comments %>
</div>
<%= simple_form_for([#recipe, #recipe.comments.build]) do |f| %>
<div class="field">
<div class="control">
<%= f.input :content, input_html: { class: 'input' }, wrapper: false, label_html: { class: 'label' } %>
</div>
</div>
<%= f.button :submit, 'Leave a reply', class: "button is-primary" %>
<% end %>
</div>
_comments.html.erb
<div class="box">
<article class="media">
<div class="media-content">
<div class="content">
<p>
<strong><%= comment.content %></strong>
</p>
</div>
</div>
</article>
</div>
<div>
<div class="">
<%= form_for([comment, comment.comments.build]) do |f| %>
<%= f.hidden_field :recipe_id, value: #recipe.id %>
<%= f.text_area :content, placeholder: "Add a Reply" %><br/>
<%= f.submit "Reply" %>
<% end %>
</div>
<div>
<%= render comment.comments %>
</div>
</div>
If I remove <%= render comment.comments %> It works, but obviously will not show me the comments on other comments. If I make only 1 comment on a recipe, I can comment on that comment as many times as I want with no issues. If I add just one more comment on the recipe, it crashes. If I pry in, it works and shows every comment is there until it is done going through each comment, then crashes. I know there are gems for this, but I am learning and really wanted to build from scratch and understand what is going on. Thanks in advance!
I think if you made a self referential relationship on your Comment model it would work. You'd need to add a parent_id or whatever you want to call it. You can keep the polymorphic owner in case you have other models that will be able to have comments.
# Migration
def change
add_column :comments, :parent_id, :integer, foreign_key: true
add_index :comments, :parent_id
end
And then in your Comment model:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
belongs_to :parent, class_name: 'Comment', inverse_of: :replies
has_many :replies, foreign_key: :parent_id, class_name: 'Comment', inverse_of: :parent
end
If you're using Rails 5, you'd need to add optional: true to the belongs_to :parent relationship.

How to use a form from another controller to set a value that has a has_many :through relation in Rails4?

Here's my current situation:
I have a model :companies and a model :users(Devise). A company can have many moderating users through a third model :moderator_connections and vice versa. To select a current moderator, I've added the column current_company (not referenced) to the model :users.
I want to add a dropdown_menu under my main menu throughout the website. By selecting a current company from this menu, the user can switch to that company's content. I tried to do this by rendering a form-partial above the <%= yield %> in my application.html.erb. The form tries to edit the current_company integer (by changing it to the company_id of one of the connected companies) for the current_user, but I think I'm not even close to solving it :(
Here are my relations.
/models/company.rb:
has_many :moderator_connections
has_many :moderators, through: :moderator_connections, class_name: 'User', foreign_key: 'company_id'
/models/user.rb:
has_many :moderator_connections
has_many :moderated_companies, through: :moderator_connections, class_name: 'Company', foreign_key: 'user_id'
/models/moderator_connection.rb:
belongs_to :user
belongs_to :company
/layouts/application.html.erb:
<main>
<div class="container">
<%= render partial: "users/current_company_form" %>
<%= render partial: "shared/message" %>
<%= yield %>
</div>
</main>
/users/_current_company_form.html.erb:
<% if user_signed_in? %>
<%= form_for edit_user_registration_path do |f| %>
<div class="form-group">
<%= f.collection_select :current_company, current_user.moderator_connections(:company_id), :name, :id,{ prompt: "Choose a company" } %>
<%= f.hidden_field :current_company, :value => current_user.moderator_connections(:company_id) %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
It already goes wrong with the rendering of the partial, I receive the following error (depending on the page I'm in): No route matches [POST] "/pages/welcome"
To be honest, I have no idea how to create this (as you can conclude from my foolish attempts). Can anyone help me out?
I'm not totally sure, but I think this should work:
<% if user_signed_in? %>
<%= form_for current_user, url: edit_user_registration_path do |f| %>
<div class="form-group">
<%= f.collection_select(:current_company, current_user.moderated_companies, :id, :name, prompt: "Select a company") %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<% end %>
Let me know if that works, though!
UPDATE
I think you should change to use:
#user.rb
has_many :moderated_companies, through: :moderator_connections, source: :company
#company.rb
has_many :moderators, through: :moderator_connections, source: :user

Showing and editing has_many objects in Rails

I'm trying to do something that I imagine to be very basic, but I'm very new to Rails and am not sure what sure what I'm doing wrong. I've gone through several tutorials and searched for an answer and can't find what the issue is. Would appreciate any help!
I've got Models set up so that Clients have many Projects which have many Milestones:
class Client < ActiveRecord::Base
has_many :projects, :dependent => :destroy
end
class Project < ActiveRecord::Base
belongs_to :client
has_many :milestones, :dependent => :destroy
end
class Milestone < ActiveRecord::Base
belongs_to :project
end
Routes are set up as follows:
resources :clients
resources :milestones
resources :projects do
resources :milestones
end
In projects/show.html.erb, I want to display each milestone associated with a project and also provide a form that adds new milestones on that same page. When I submit the form, it adds a new milestone (a new LI within UL.card-list), but none of the values show up. Here is the code for projects/show.html.erb:
<h2><%= #project.name %> Milestones</h2>
<ul class="card-list">
<% #project.milestones.each do |m| %>
<li>
<div class="card-header">
<%= m.date %>
</div>
<div class="card-body">
<h3 class="name"><%= m.name %></h3>
<p class="description"><%= m.description %></p>
</div>
</li>
<% end %>
<li>
<div class="card-header">
New Milestone
</div>
<div class="card-body">
<%= form_for [#project,Milestone.new] do |f| %>
<%= f.hidden_field(:project_id, value: #project.id) %>
<div class="field">
<%= f.label :milestone %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :date %>
<%= f.date_field :date %>
</div>
<div class="actions">
<%= f.submit "Add Milestone" %>
</div>
<% end %>
</div>
</li>
</ul>
Here are the parameters that are coming through the form:
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"3D12GTH+IhwMMQDKsj2l+KXe7OBxmub3eejb3pbpWao=",
"milestone"=>{
"project_id"=>"1",
"name"=>"Test Milestone",
"description"=>"test descrip",
"date"=>"2015-06-26"
},
"commit"=>"Add Milestone",
"project_id"=>"1"
}
Milestones controller:
def create
#project = Project.find(params[:project_id])
#milestone = #project.milestones.create!(params[milestone_params])
redirect_to #project
end
private
def milestone_params
params.require(:milestone).permit(:name, :description, :completed, :date, :project_id)
end
Please let me know if there's any other info I can provide that would help. Thanks!
Since you need to support both (POST /milestones and POST /projects/:project_id/milestones) the project_id to the form:
<%= form_for [#project,Milestone.new] do |f| %>
...
<%= f.hidden_field(:project_id, value: #project_id) %>
...
<%- end -%>
Or if your resource is always nested than project_id available in the params in your controller so you can just pass it:
class MilestonesContoller < ApplicationController
def create
#milestone = Milestone.new(milestone_params)
# this part was originally omitted for brevity.
if #milestone.save
redirect_to #milestone.project
else
render :new
end
end
# don't trust params from the scary interwebs
def milestone_params
params.require(:milestone)
.permit(:project_id, :name, :description, :date)
end
end
NOTE that you actually need to integrate this code with the other actions in your controller. It is just a minimal example to show the relevant concepts. Not something which is meant as a complete copy-paste-done solution.
You can also reduce your routes file down to:
resources :clients
resources :milestones
resources :projects do
resources :milestones
end
Use the options for resources if you need to customize the routes.

Rails 4 -Nested Models and Simple Form partial

I am trying to make an app in Rails 4.
I have a projects, project questions and a project answers model.
my models
class Project
has_many :project_questions, dependent: :destroy#, through: :projects
accepts_nested_attributes_for :project_questions
end
class ProjectQuestions
belongs_to :project#, counter_cache: true
has_many :project_answers, dependent: :destroy
belongs_to :user
accepts_nested_attributes_for :project_answers
end
class ProjectAnswer
belongs_to :project_question#, counter_cache: true
belongs_to :user
end
routes.rb
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.
projects/show
<%= 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 |f| %>
<div class="categorytitle">
<%= f.title %>
</div>
<div class="generaltext">
<%= f.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>
When I try this, I get an error that says:
undefined local variable or method `f' for #<#:0x0000010a11ce60>
I thought I was defining f at the beginning of the opening line of the _pqps form.
I'm really struggling to get a grip with coding. Can anyone see what I've done wrong?
You use f.simple_fields_for in pqps, but f is not defined anywhere.
You have to define it using simple_form_for somewhere. I don't know exactly where – it depends on your own needs, but if, say, the whole form is inside _pqps:
<div class="containerfluid">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<%= simple_form_for #project do |f| %>
<% f.simple_fields_for :project_questions, #project.project_questions.build do |f| %>
# ...
<% end %>
<% end %>
</div>
</div>
</div>
If form "starts" outside "_pqps" partial, then you have to pass f as a local parameter:
<%= render 'project_questions/pqps', f: f %>
projects_controller
def show
#project_questions = #project.project_questions.build
end
View
<%= simple_form_for #project_questions do |f| %>
<%= f.input :title%>
<%= f.input :content %>
<%= f.button :submit %>
<% end %>

Rails, Simple Form, Nested Forms

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.)

Resources