I've followed the Go Rails tutorial below to set up comments with polymorphic associations: https://gorails.com/episodes/comments-with-polymorphic-associations
However, I have a nested situation with two models (movies/parts). It is working with 'movies' but I cannot get it working with child model 'parts'.
Models
class Comment < ApplicationRecord
belongs_to :user
belongs_to :commentable, polymorphic: true
end
class Movie < ApplicationRecord
has_many :parts, dependent: :destroy
has_many :comments, as: :commentable
end
class Part < ApplicationRecord
belongs_to :movie
has_many :comments, as: :commentable
end
config/routes.rb
resources :movies do
resources :comments, module: :movies
resources :parts do
resources :comments, module: :parts
end
end
app/views/movies/show.html.erb
<%= render partial: "comments/comments", locals: {commentable: #movie} %>
<%= render partial: "comments/form", locals: {commentable: #movie} %>
app/views/comments/_comments.html.erb
<h1>Comments</h1>
<% commentable.comments.each do |comment| %>
<div class="well">
<%= comment.summary %> by <i><%= comment.user.email %></i><br><br>
</div>
<% end %>
app/views/comments/_form.html.erb
<%= form_for [commentable, Comment.new] do |form| %>
<% if commentable.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(commentable.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% commentable.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= form.text_area :summary, class: "form-control", placeholder: "Add a comment" %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Everything above with 'movies' is working well. The problem is with 'parts'.
app/views/parts/show.html.erb
<%= render partial: "comments/comments", locals: {commentable: #part} %>
<%= render partial: "comments/form", locals: {commentable: #part} %>
Error with 'parts'
NoMethodError in Parts#show
undefined method `part_comments_path' for #ActionView::Base:0x0000000003d3b0
Highlighted line of error:
<%= form_for [commentable, Comment.new] do |form| %>
I think I have to pass the movie object with the part object into 'commentable' -- since it is nested -- but don't know how to do it with this set up. Any suggestions are greatly appreciated.
I believe route in the partial meant replacing any references to part_comments_path with movie_part_comments_path.
Related
I am new to RoR (using rails 5) and have problems with a has_many through: association.
I want to create Categories with different labels for different Languages.
Here is my model:
class Language < ApplicationRecord
has_many :category_infos
has_many :categories, through: :category_infos
end
class Category < ApplicationRecord
has_many :category_infos
has_many :languages, through: :category_infos
accepts_nested_attributes_for :category_infos
end
class CategoryInfo < ApplicationRecord
belongs_to :language
belongs_to :category
accepts_nested_attributes_for :language
end
The controller:
class CategoriesController < ApplicationController
def new
#category = Category.new
#languages = Language.all
#languages.each do |language|
#category.category_infos.new(language:language)
end
end
def create
#category = Category.new(category_params)
if #category.save
redirect_to #category
else
render 'new'
end
end
private
def category_params
params.require(:category).permit(:name, category_infos_attributes:[:label, language_attributes: [:id, :language]])
end
end
The form:
<%= form_with model: #category, local: true do |form| %>
<% if #category.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#category.errors.count, "error") %>:
</h2>
<ul>
<% #category.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<br/>
<% end %>
<p>
<%= form.label :name %>
<%= form.text_field :name %>
</p>
<p>
Labels:
</p>
<table>
<% #category.category_infos.each do |category_info| %>
<tr>
<td>
<%= category_info.language.name %>
</td>
<td>
<%= form.fields_for :category_infos, category_info do |category_info_form| %>
<%= category_info_form.fields_for :language, category_info.language do |language_form| %>
<%= language_form.hidden_field :id, value: category_info.language.id %>
<%= language_form.hidden_field :name, value: category_info.language.name %>
<% end %>
<%= category_info_form.text_field :label %>
<% end %>
</td>
</tr>
<% end %>
</table>
<p>
<%= form.submit %>
</p>
<% end %>
When I create a new category, I get this error :
Couldn't find Language with ID=1 for CategoryInfo with ID=
on Line :
#category = Category.new(category_params)
However I already have registered several languages in database (1 = English, 2 = French etc...)
How do I need to write the form so that I can create a Category and its CategoryInfos in English, French etc... at the same time?
Thanks in advance for your answers
You're making a classic newbie misstake and using fields_for when you just want to create an association by passing an id.
<%= form_with model: #category, local: true do |f| %>
# ...
<%= f.fields_for :category_infos do |cif| %>
<%= cif.collection_select(:language_id, Language.all, :name, :id) %>
<%= cif.text_field :label %>
<% end %>
<% end %>
While you could also pass the attributes to let a users create languages at the same time its very much an anti-pattern as it adds a crazy amount of responsibilities to a single controller. It will also create an authorization problem if the user is allowed to create categories but not languages.
Use ajax to send requests to a seperate languages controller instead if you need the feature.
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 %>
I would like to set a comment form on a post in the "group message show" view.But I have an error message like,
NoMethodError at /group_messages/64
undefined method `group_message_group_message_comments_path' for #<#:0x007f9c0afa0b38>
Could you give me some advice?
☆show.html.erb(group_messages)
<h2>Add a comment</h2>
<%= form_for([#group_message, #group_message_comment]) do |f| %>
<% if #group_message_comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#group_message_comment.errors.count, "error") %> prohibited this group_message_comment from being saved:</h2>
<ul>
<% #group_message_comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %><%# do%>
</ul>
</div><!-- error_explanation-->
<% end %><%# if any?%>
<div class="field">
<%= f.label :member_id %><br />
<%= f.number_field :member_id %>
</div>
<div class="field">
<%= f.label :gmessage_id %><br />
<%= f.number_field :group_message_id %>
</div>
<div class="field">
<%= f.label :group_id %><br />
<%= f.number_field :group_id %>
</div>
<div class="field">
<%= f.label :content %><br />
<%= f.text_field :content %>
</div>
<div class="actions" >
<%= f.submit "Comment"%>
</div>
<% end %><%# form_for>
☆group_messages_controller
def show
if !checklogin? then return end
#group_message = GroupMessage.find(params[:id])
#isme = me? #group_message
#group_message_comment = GroupMessageComment.new
#group_message_comment = GroupMessage.find(params[:id]).group_message_comments.build
respond_to do |format|
format.html # show.html.erb
format.json { render json: #group_message }
end
end
☆GroupMessage model
class GroupMessage < ActiveRecord::Base
attr_accessible :content, :member_id, :group_id
belongs_to :member
belongs_to :group
has_many :group_message_comments
end
☆GroupMessageComment model
class GroupMessageComment < ActiveRecord::Base
attr_accessible :content, :gmessage_id, :group_id, :member_id
belongs_to :member
belongs_to :group_message
end
☆routes.rb
MiniSNS::Application.routes.draw do
resources :group_message_comments
root :to => 'members#login'
match '/groups/join'
resources :group_messages
resources :groups do
resources :group_messages
end
match '/members/new'
resources :index
resources :groups
post 'groups/:id' => 'group#show'
post '/groups/new'
post '/index/index'
match '/members/login'
match '/members/logout'
match '/members/friend'
match 'members/show'
post 'messages/comment'
resources :comments
resources :messages
resources :friends
resources :members
That error message is due to the following line of code:
<%= form_for([#group_message, #group_message_comment]) do |f| %>
This is because you haven't set the correct routing for your models. Can you post your routes.rb too so that I can have a look?
I think you need nested routes, something like:
resources :group_messages do
resources :group_message_comment
end
I am following railscasts 196 episode and i try exactly what he has, but i am having the following error
ActiveModel::MassAssignmentSecurity::Error in SurveysController#create
Can't mass-assign protected attributes: questions_attributes
Rails.root: /home/jean/rail/surveysays
Here my code so far
Survey Form
<%= form_for(#survey) do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<%= f.fields_for :questions do |bf|%>
<%= bf.label :content, "Question" %><br />
<%= bf.text_area :content, :rows=> 3 %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Survey Relationship
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions
attr_accessible :name
end
Question Relationship
class Question < ActiveRecord::Base
belongs_to :survey
attr_accessible :content, :survey_id
end
New Controller
def new
#survey = Survey.new
3.times {#survey.questions.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #survey }
end
end
change your class to this
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions
attr_accessible :name, :questions_attributes
end
look for topic "Using with attr_accessible" here for more information
I saw similar examples here. But it just doesn't work for me.
I want to create/submit an activity for post. There are several days under a post. And an activity is under a specific date. See models below.
Models:
class Post < ActiveRecord::Base
has_many :dayinposts
has_many :activitys, :through => :dayinposts
end
class Dayinpost < ActiveRecord::Base
belongs_to :post
has_many :activitys
end
class Activity < ActiveRecord::Base
belongs_to :dayinpost
end
Routes:
resources :posts do
resources :dayinposts do
resources :activitys
end
end
rake routes
post_dayinpost_activitys GET /posts/:post_id/dayinposts/:dayinpost_id/activitys(.:format) activitys#index
POST /posts/:post_id/dayinposts/:dayinpost_id/activitys(.:format) activitys#create
show.html.erb
<% #post.dayinposts.each do |dayinpost| %>
<% dayinpost.activitys.each do |activity| %>
<p>
<b>Action:</b>
<%= activity.action %>
</p>
<% end %>
<%= form_for([#post, dayinpost, dayinpost.activitys.build]) do |f| %>
<div class="field">
<%= f.label :action %><br />
<%= f.text_field :action %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<% end %>
error
undefined method `post_dayinpost_activities_path' for #<#<Class:0x40cb6d8>:0x40c9890>
But I have saw it in the rake routes...
thanks in advance!
The correct pluralization for "activity" is "activities".
In your config/routes.rb you have "activitys", which is wrong.