I'm working on ROR project and created the partial form for the comments but i get the error in show.html.rb "undefined method `comments'".I have tried to find what's long but no luck.The highlight of the error is on this image
Image
here is my _form.html.erb
<%= simple_form_for ([#message, #message.comments.build]) do |f| %>
<%= f.input :content , label: "Comments" %>
<%= f.button :submit, :class => "btn-custom" %>
<% end %>
class CommentsController < ApplicationController
def create
#message = Message.find(params[:message_id])
#comment = #message.comments.create(comment_params)
#comment.user_id = current_user.user_id
if #comment.save
redirect_to message_path(#message)
else
render 'new'
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
And this is my show.html.rb
<div class="col-md-10 col-md-offset-1">
<div class="message-show">
<h2><%=#message.title %></h2>
<p class="message-posted-by"><%= time_ago_in_words(#message.created_at) %>
ago </p>
<p class="message-desc"><%= #message.description %></p>
<h3 class="comment-section-header">Discussion:</h3>
<p><%= render #message.comments %></p>
<h3 class="reply-to-msg">Reply</h3>
<%= render 'comments/form' %>
<div class="links btn-group">
<%= link_to "Back", root_path, class: "btn btn-default" %>
<%= link_to "Edit", edit_message_path, class: "btn btn-primary" %>
<%= link_to "Delete",message_path(#message), method: :delete,data: {confirm:"Are you sure?"} , class: "btn btn-danger" %>
</div>
</div>
</div>
Seems like your Message model is missing an association to comments:
# in app/models/message.rb
has_many :comments
Related
comment controller
class CommentsController < ApplicationController
before_action :load_commentable
before_action :checked_logged_in, only: [ :create]
def new
#comment = #commentabl.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
#comment.user_id = current_user.id
#comment.commenter = current_user.username
if #comment.blank? || #comment.save
flash[:success] = "Commented was created"
ActionCable.server.broadcast 'comment_channel',
commenter: current_user.username,
comment: #comment.content
redirect_to #commentable
else
flash[:danger] = render_to_string(:partial => 'shared/error_form_messaging',
:locals => {obj: #comment},
format: :html)
redirect_to #commentable
end
end
private
def comment_params
params.require(:comment).permit(:content, :commenter, :user_id)
end
def load_commentable
resource, id = request.path.split('/')[1,2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def checked_logged_in
unless logged_in?
flash[:danger] = 'please log in to be able to comment'
redirect_to login_path
end
end
end
my form for creating a comment:
<%= form_with model:[commentable, commentable.comments.new], :html => {class: "form-horizontal", role:"form"} , local: true do |form| %>
<div class="form-group">
<div class="control-label col-sm-2">
<%= form.label :content, 'Comment' %>
</div>
<div class="col-sm-8">
<%= form.text_field :content , class: 'form-control', placeholder: "enter your comment here", autofocus: true %>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<%= form.submit 'Comment' , class: ' btn btn-primary' %>
</div>
</div>
<% end %>
the form is called in show.html.erb
<h2 class="text-center">
Title: <%= #article.title %>
</h2>
<div class="well col-xs-8 col-xs-offset-2">
<div id="user-info-showpage" align="center">
Created by: <%= render 'shared/user-info', obj: #article.user %>
</div>
<h4 class="text-center">
<strong>Description:</strong>
</h4>
<hr />
<%= simple_format(#article.description) %>
<% if #article.categories.any? %>
<p>Categories: <%= render #article.categories %></p>
<% end %>
<div class="article-actions">
<% if logged_in? && (current_user == #article.user || current_user.admin?) %>
<%= link_to "Delete", article_path(#article), method: :delete,
data: {confirm: "Are you sure you want to delete the article?"},
class: 'btn btn-xs btn-danger' %>
<%= link_to "Edit", edit_article_path(#article), class: 'btn btn-xs btn-success'%>
<%end%>
<%= link_to "View All Articles", articles_path , class: 'btn btn-xs btn-primary'%>
</div>
</div>
<% if logged_in? %>
<div class="col-xs-8 col-xs-offset-2">
<%#= render partial: 'comments/form', :locals => {commentable: #article} %>
</div>
<%end%>
<div class="col-xs-8 col-xs-offset-2">
<div id="comments"></div>
<%= #article.comments.inspect %>
<% #article.comments.each do |c| %>
<div class="well">
<%= c.content %> by
<%= c.commenter %>
</div>
<%end%>
<div id="comments"></div>
</div>
my result is in view is
Please if more info needed, ask me so I can provide
Note: I am not sure this empty record is owing to commentable.comments to be nil or I miss something
I commented render form in show page and now the empty record is gone, so my issue must be related to form_with
From my understanding, you
Expect:
in your articles#show page to not show the empty by _________ <div> HTML because the comment is still built (still in-memory), and not yet saved (not yet in DB).
Solution 1:
app/views/articles/show.html.erb
...
<div class="col-xs-8 col-xs-offset-2">
<div id="comments"></div>
<% #article.comments.each do |c| %>
<!-- ADD THIS LINE -->
<% if c.persisted? %>
<div class="well">
<%= c.content %> by
<%= c.commenter %>
</div>
<% end %>
<%end%>
<div id="comments"></div>
</div>
...
Solution 2 (better but still is a workaround):
app/views/comments/_form.html.erb
<%= form_with model:[commentable, Comment.new(commentable: commentable)], :html => {class: "form-horizontal", role:"form"} , local: true do |form| %>
Explanation:
The reason the page is displaying an empty by _________ <div> is that because you "built" a new comment before .each is called. Because they are sharing same memory space, the build basically also adds it to the array in-memory. See the following:
# rails console
article = Article.create!
comment1 = Comment.create!(commentable: article)
# from here, comment1 is then saved already in the DB
# now let's see what happens when you use "build" or "new"
# They have differences, it seem: for details: https://stackoverflow.com/questions/1253426/what-is-the-difference-between-build-and-new-on-rails/1253462
# redefine (to simulate your #article = Article.find(params[:id])
article = Article.find(article.id)
comment2 = article.comments.build
puts article.comments.count
# SQL: Select count(*) FROM ...
# => 1
puts article.comments.size
# => 2
# notice how `count` and `size` are different. `count` value is "DB-based" while `size` is "memory-based". This is because `count` is an `ActiveRecord` method while `size` is a delegated `Array` method.
# now let's simulate your actual problem in the view, where you were looping...
article.comments.each do |comment|
puts comment
end
# => <Comment id: 1>
# => <Comment id: nil>
# notice that you got 2 comments:
# one is that which is already persisted in DB
# and the other is the "built" one
# the behaviour above is to be expected because `.each` is a delegated `Array` method
# which is agnostic to where its items come from (DB or not)
This is the reason why in your page, the "built" comment is shown in the page because you are calling
<%= render partial: 'comments/form', :locals => {commentable: #article} %>
... which calls commentable.comments.build
BEFORE the <% "article.comments.each do |c| %>
If this is not clear enough yet, try putting
<%= render partial: 'comments/form', :locals => {commentable: #article} %>
... which calls commentable.comments.build
AFTER the <% "article.comments.each do |c| %> ... <% end %>
... and the by _________ <div> should already not show up.
So I am trying to get the article id to pass into the comments.article_id, I have looked all over - and can't find anything(I am fairly new so I doubt I know what I'm looking for) I have been trying for the last couple of hours to pass the articles id to the comments controller then set the comments.article_id to the article id. Here's my code at the moment:
ArticlesController:
class ArticlesController < ApplicationController
require 'comment'
def new
end
def create
#article = Article.new(article_params)
#article.user_id = current_user.id
if #article.save
flash[:success] = "Post created successfully!"
redirect_to article_path(#article)
else
flash[:danger] = "We could not create you're article!"
render 'new'
end
end
def show
#article = Article.find(params[:id])
#comment = Comment.new
end
private
def article_params
params.require(:article).permit(:title, :description)
end
end
My comments controller:
class CommentsController < ApplicationController
def new
end
def create
#comment = Comment.new(comment_params)
#comment.article_id = Article.find(params[:id])
#comment.user_id = current_user.id
if #comment.save
flash[:success] = "Successfully created comment"
redirect_to article_path(#comment.article)
else
debugger
flash[:danger] = "Failed to create comment"
redirect_to article_path(2)
end
end
private
def comment_params
params.require(:comment).permit(:description)
end
end
and my show.html.erb for articles(because I am doing it all in there)
<h1 align="center">Title: <%= #article.title %></h1>
<div class="well col-xs-8 col-xs-offset-2">
<div class="row">
<div class="col-xs-4 col-xs-offset-4">
<div class="well well-sm">
<div class="user-img">
<p class="created">Created By:</p>
<%= gravatar_for #article.user, size: 150 %>
</div>
<div class="user-title">
<%= link_to #article.user.username, user_path(#article.user) %> <br />
</div>
</div>
</div>
</div>
<h4 class="center description"><strong>Description:</strong></h4>
<hr />
<%= simple_format(#article.description) %>
<div class="article-actions">
<% if logged_in? && current_user == #article.user %>
<%= link_to 'Edit', edit_article_path(#article), class: "btn btn-xs btn-primary" %>
<%= link_to 'Delete this article', article_path(#article), method: :delete,
data: { confirm: "Are you sure you want to delete this article?" },
class: "btn btn-xs btn-danger" %>
<%= link_to 'View all articles', articles_path, class: "btn btn-xs btn-success" %>
<% else %>
<%= link_to 'View all articles', articles_path, class: "btn btn-xs btn-success" %>
<% end %>
</div>
<% #article.comment.each do |f| %>
<div id="commentBorder">
<div class="panel panel-default">
<div class="panel-body">
<p><%= f.description %></p>
</div>
<div class="panel-footer">
<div align="center">
<small>Created by <%= f.user.username %>,<br />
<%= time_ago_in_words(f.created_at) %> ago</small></div>
</div>
</div>
</div>
<% end %>
<%= form_for(#comment, :html => {class: "form", role: "forms"}, :url => article_comments_path(#article)) do |comm| %>
<%= comm.label :description %>
<%= comm.text_field :description %>
<%= comm.submit "Post comment" %>
<% end %>
Solution!
So playing around some more literally five minutes after this, inside my Comments controller, I changed #comment.article_id = Article.find(params[:id])
Into
#comment.article_id = params[:article_id]
This fixed it, I have a theory on how so correct me if I am wrong.
From this picture you can see we already have article_id as a parameter(https://i.gyazo.com/fe49dcebbe75c006e95c7f44a9964865.png)
By using params[:article_id] we reached and got the article_id parameter and assigned it to our #comment.article_id value.
Just to be clear about rails associations, you could also have done :
#comment.article = Article.find(params[:article_id])
This has the advantage of ensuring the article exists before setting it's id value to the comment.article_id
I am new to ruby on rails, and know this is a beginner error. I'm trying to create an application that displays user comments within a post. I have a comment partial pointing to my post#show, and when requesting to display <%= image_tag(comment.user.avatar.small.url, class: "media-object") if comment.user.avatar? %> from _comment.html.erb, I get "undefined method 'user' for nil:NilClass. I've read other questions on stackoverflow and I know this is saying it can't find a user associated with the post within comments and that I need to define user in my controller. I'm assuming it's for the post controller, but I can't seem to wrap my head around the specific syntax to display comments by user in post.
#comments_controller
def create
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:post_id])
#comment = current_user.comments.new(comment_params)
#comment.post = #post
#comment.save
authorize #comment
redirect_to [#topic, #post]
end
#posts_controller
def show
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
end
#post model
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :topic
has_one :summary
has_many :comments
mount_uploader :image, ImageUploader
#comment model
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
#rendering comment partial in post#show
<h1><%= #post.markdown_title %></h1>
<div class="row">
<div class="col-md-8">
<small>
<%= image_tag(#post.image.thumb.url) if #post.image? %></br>
<%= image_tag(#post.user.avatar.tiny.url) if #post.user.avatar? %>
submitted <%= time_ago_in_words(#post.created_at) %> ago by
<%= #post.user.name %>
</small>
<p><%= #post.markdown_body %></p>
</div>
<div class="col-md-4">
<% if policy(#post).edit? %>
<%= link_to "Edit", edit_topic_post_path(#topic, #post), class: 'btn btn-success' %>
<% end %>
<% if policy(#post).destroy? %>
<%= link_to "Delete Post", [#topic, #post], method: :delete, class: 'btn btn-danger', data: { confirm: "Are you sure you want to delete this post?" } %>
<% end %>
</div>
<div class="col-md-8">
<% if policy(Comment.new).create? %>
<%= render partial: 'comments/comment', locals: { comment: #comment } %>
<%= render partial: 'comments/form', locals: {topic: #topic, post: #post} %>
<% else %>
<h3>Sign up to Bloccit to post comments</h3>
<%= link_to "Sign up", new_user_registration_path, class: 'btn btn-primary' %></br></br>
<% end %>
#comment partial
<ul>
<% #post.comments.each do |c| %>
<div class="media">
<div class="media-left">
<%= image_tag(comment.user.avatar.small.url, class: "media-object") if comment.user.avatar? %>
</div>
<div class="media-body">
<small>
<%= comment.user.name %> commented <%= time_ago_in_words(comment.created_at) %> ago
<% if policy(comment).destroy? %>
| <%= link_to "Delete", [#topic, #post, comment], method: :delete %>
<% end %>
</small>
<li>
<p><%= c.body %></p>
</li>
</div>
<% end %>
Also, when I put #post.user = #user in posts_controller the error changes to "undefined method 'avatar' for nil:NilClass. Thanks for your help!
undefined method 'user' for nil:NilClass
The error is because of this line
<%= render partial: 'comments/comment', locals: { comment: #comment } %>
You don't have #comment initialized in show method of posts_controller and you are passing it as locals for comment, so comment.user returns error.
And also I've noticed that in _comment.html.erb you have this line <% #post.comments.each do |c| %>, so you can use c instead of comment.
<%= image_tag(c.user.avatar.small.url, class: "media-object") if c.user.avatar? %>
You are incorrectly referencing the block variable. Either change |c| to |comment| or change the comment references to c.
So like this:
<%= image_tag(c.user.avatar.small.url, class: "media-object") if c.user.avatar? %>
I'm making a basic application and I made it so a user can attach a file to a form post. That all works perfectly fine, but now I'm trying to display a link to the file and it doesn't seem to work.
I'm getting two errors. One if I attach a file and another if I don't attach a file. They both say undefined method 'doc=' for nil:NilClass but are on different lines of code.
If I don't upload a file this is what I get: NoMethodError in Projects#index on this line of code <% if #project.doc %>.
If I do upload a file this is what I get: NoMethodError in ProjectsController#create on this line of code #project.doc = uploaded_io.original_filename
projects_controller.rb
class ProjectsController < ApplicationController
def index
#projects = Project.all
end
def show
end
def new
#projects = Project.new
end
def create #no view
#projects = Project.new(project_params)
uploaded_io = params[:doc]
if uploaded_io.present?
File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'wb') do |file|
file.write(uploaded_io.read)
#project.doc = uploaded_io.original_filename
end
end
if #projects.save
redirect_to projects_path, :notice => "Your project was sent!"
else
render "new"
end
end
def edit
#projects = Project.find(params[:id])
end
def update #no view
#projects = Project.find(params[:id])
if #projects.update_attributes(project_params)
redirect_to projects_path, :notice => "Your project has been updated."
else
render "edit"
end
end
def destroy #no view
#projects = Project.find(params[:id])
#projects.destroy
redirect_to projects_path, :notice => "Your project has been deleted."
end
private
def project_params
params.require(:project).permit(:title, :description)
end
end
index.html.erb
<div class="container">
<div class="page-header">
<h1>Projects<small> Here are all of your projects.</small></h1>
</div>
</div>
<% #projects.each do |project| %>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<%= project.title %>
</div>
</div>
<div class="panel-body">
<p>
<%= project.description %>
</p>
<br>
<%= link_to "Discuss", new_project_discussion_path(project) %> |
<%= link_to "Tasks", new_project_task_path(project) %> |
<%= link_to "Edit", edit_project_path(project) %> |
<%= link_to "Delete", project, :method => :delete %>
<% if #project.doc %>
<p>Document: <%= link_to #project.doc, "/uploads/#{#project.doc}", :target => "_blank" %></p>
<% end %>
</div>
</div>
<%end%>
<br>
<br>
<div class="container">
<p><a class="btn btn-primary btn-lg" href="/projects/new" role="button">Create project</a></p>
</div>
_form.html.erb
<%= form_for(#projects, :html => { :multipart => true}) do |f| %>
<% if #projects.errors.any? %>
<ul>
<% #projects.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<div class="container">
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: "form-control" %>
</div>
<%= label_tag :doc, 'Files (optional)' %>
<%= file_field_tag :doc %>
<br>
<div class="form-group">
<%= f.submit "Submit Project", class: "btn btn-primary" %>
</div>
<% end %>
Updated :
You have many errors, here are a few that I found :
uploaded_io = params[:doc]
Should be
uploaded_io = params[:project][:doc]
Also delete this line
#project.doc = uploaded_io.original_filename
You don't need that.
Finally, in your views, you should have project.doc instead of #project.doc
Im working on a nested attribute form.
these are the two models..
Employee.rb
class Employee < ActiveRecord::Base
has_one :employee_info, :primary_key => :employeeID, foreign_key: :employeeID
accepts_nested_attributes_for :employee_info
end
EmployeeInfo.rb
class EmployeeInfo < ActiveRecord::Base
belongs_to :employee, primary_key: :employeeID, foreign_key: :employeeID
validates_uniqueness_of :employeeID
end
And i have my form in _form.html.rb
<%= form_for #employee, html: {class: "form form-horizontal validate-form", novalidate: "novalidate"} do |f| %>
<% if #employee.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger alert-dismissable">
<a class="close" data-dismiss="alert" href="#">×</a>
<h2><%= pluralize(#employee.errors.count, "error") %> prohibited this shop from being saved:</h2>
<ul>
<% #employee.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
<div class='form-group'>
<%= f.label :employeeID, class: 'col-md-2 control-label' %>
<div class='col-md-5'>
<%= f.text_field :employeeID, {class: 'form-control'} %>
</div>
</div>
<div class='form-group'>
<%= f.label :employee_name, class: 'col-md-2 control-label' %>
<div class='col-md-5'>
<%= f.text_field :employee_name, class: 'form-control' %>
</div>
</div>
<%= f.fields_for :employee_info do |ff| %>
<div class='form-group'>
<%= ff.label :hired, class: 'col-md-2 control-label' %>
<div class='col-md-5'>
<%= ff.text_field :hire_date, class: 'form-control' %>
</div>
</div>
<div class='form-group'>
<%= ff.label :terminated, class: 'col-md-2 control-label' %>
<div class='col-md-5'>
<%= ff.text_field :term_date, class: 'form-control' %>
</div>
</div>
<% end %>
<div class='form-actions form-actions-padding-sm'>
<div class='row'>
<div class='col-md-10 col-md-offset-2'><i class='icon-save custom-icon'></i>
<% if params[:action] == "new" %>
<%= f.submit "Create", class: 'btn btn-primary custom-button' %>
<% else %>
<%= f.submit "Update", class: 'btn btn-primary custom-button' %>
<% end %>
<%= link_to 'Cancel', shops_path, class: 'btn' %>
</div>
</div>
</div>
<% end %>
and the update method in controller
def update
respond_to do |format|
p "------------------------------"
p employee_params
if #employee.update(employee_params)
format.html { redirect_to #employee, notice: 'Employee was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #employee.errors, status: :unprocessable_entity }
end
end
end
where that p employee_params output in console is
{"employeeID"=>"103", "employee_name"=>"James Michule", "employee_info_attributes"=>{"hire_date"=>"1996-03-12 11:30:00 UTC", "term_date"=>"1996-03-12 11:30:00 UTC", "hourly_rate"=>"7.4", "address"=>"108 E. Jay", "phone_number1"=>"", "phone_number2"=>"", "zipcode"=>"65721", "state"=>"MO", "city"=>"Ozark", "id"=>"30"}}
and when i try to update i get an error..
error:
ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError):
app/controllers/employees_controller.rb:56:in `block in update'
app/controllers/employees_controller.rb:53:in `update'
What is wrong.? Please help
Rails 4 has features from the strong_parameters
so you can use
#employee.update_attributes(params[:employee], permit[:employee_attribute]
or you can do in following way
#employee.update_attributes(params[:employee].permit(:employeeID))
Your employees_controller
private
def employee_params
params.require(:employee).permit(:term_date, :hire_date)
end
Add term_date & hire_date in the employee_params method like the code above.
Hope it solves the issue.
P.S. And please read the topic "Rails Strong parameters" before creating the app on rails >= 4