Ruby on rails getting article_id inside comments controller - ruby-on-rails

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

Related

form_with produces first record as nil

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.

undefined method `comments'

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

How to send email notifications if client is second on a list in Ruby on Rails?

I am kinda new to Ruby on Rails and StackOverflow. I have a rails app where people can sign their names to a list. But I want to send an email notification to whoever is second in the list. How can I make this happen? Do I need an if statement? and how would I make rails know who is second?
Here is my list controller:
class ListsController < ApplicationController
before_action :find_list, only: [:show, :edit, :update, :destroy]
def index
#list = List.all.order("created_at asc")
end
def new
#list = List.new
end
def create
#list = List.new list_params
if #list.save
redirect_to root_path, notice: "#{#list.name}, You have been added to the List!"
else
render 'new', notice: "Oh No! Not Saved!"
end
end
def show
end
def edit
end
def update
if #list.update list_params
redirect_to #list, notice: "#{#list.name}, has been updated!"
else
render 'edit'
end
end
def destroy
#list.destroy
redirect_to root_path, notice: "#{#list.name}, has been deleted!"
end
private
def list_params
params.require(:list).permit(:name, :barber_id)
end
def find_list
#list = List.find(params[:id])
end
end
This is my form
<%= form_for #list do |f| %>
<% if #list.errors.any?%>
<h2><%= pluralize(#list.errors.count, "error") %> prevented this list from saving:</h2>
<ul>
<% #list.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<%end%>
</ul>
<%end%>
<div class="form-group ">
<%= f.label :name %>
<%= f.text_field :name, {class: 'form-control'} %>
</div>
<div class="form-group">
<%= f.label "Choose a Barber" %>
<!-- :include_blank => true
insert this to have the option of leaving it blank
-->
<div class="classic-select">
<%= f.collection_select :barber_id, Barber.all, :id, :name %>
</div>
</div>
<br>
<button type="submit" class="btn-add-to-list">Submit</button>
<%end%>
Here is my index.html.erb
<div class="container">
<div class="row">
<div class="col-md-10 list center-block">
<% #list.each do |list| %>
<div class="col-md-6 names panel-default panel">
<h1><%= link_to list.name, list %></h1>
<p><strong>Barber:</strong> <%= list.barber.name %></p>
<hr>
</div>
<%end%>
<div class="col-md-2 center-block">
<%= link_to "Add Me to the List", new_list_path, class: "btn-add btn"%>
</div>
</div>
</div>
</div>
Yo can get the second on your index with:
#list = List.all.order("created_at asc")
#second_on_list = #list.second
Or
#list = List.all.order("created_at asc")
#second_on_list = #list[1]

Rails: Two different NoMethodError's when trying to display files

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

Showing delete link for creator of comment

I got my app working so that the user can only delete their own comments but now im trying to add a link to the site but i only want the creator of the comment to be able to see the link.
I tried doing
<% if current_user %>
but when i do that it shows up on all comments and not just the user. I can do
<% if current_user.admin %>
and that restricts only the admin to be able to see the delete links. I've also tried
<% if #comment.user_id == current_user.id %>
that doesent work either. How can i do it so that the comment creator can only see the comments?
heres my view
_comments.html.erb
<div class="container">
<% #comments.each do |comment| %>
<div class="comment">
<div class="gravatar_border">
<%= gravatar_for comment.user, size: '49' %>
</div>
<div class="user_info_comments">
<b><%= comment.user.name %></b>
<%= comment.created_at.strftime("%b. %d %Y") %>
</div>
<div class="user_comments">
<%= simple_format comment.content %>
<%= pluralize comment.reputation_value_for(:votes).to_i, "vote" %>
<%= link_to "", vote_comment_path(comment, type: 'up'), method: "post", class: ' icon-thumbs-up' %>
<%= link_to "", vote_comment_path(comment, type: 'down'), method: "post", class: ' icon-thumbs-down' %>
<% if #comment.user_id == current_user.id %>
<%= link_to 'delete', comment, method: :delete, confirm: 'you sure?' %>
<% end %>
</div>
</div>
<% end %>
<br />
</div>
heres my controller
comments_controller.rb
def destroy
#comment = Comment.find(params[:id])
if #comment.user_id == current_user.id
#comment.destroy
flash[:notice] = "comment deleted!"
else
flash[:error] = "not allowed"
end
redirect_to :back
end
heres a link to the site http://www.batman-fansite.com
Change #comment to comment in your view.
<% if comment.user_id == current_user.id %>
#comment is defined in your destroy action, but when you setup a block like this in your view
<% #comments.each do |comment| %>
#comment has no value, only comment does.
<% if comment.user_id == current_user.id %>
and should work)

Resources