How to obtain count of comments - ruby-on-rails

This is my Articles index.html.erb so far
<table>
<tr>
<th>Title</th>
<th>Text</th>
<th colspan="3"></th>
<th>Total Number of Comments Per Article</th>
</tr>
<% #articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
<td>Placeholder</td>
</tr>
<% end %>
</table>
<p>Total Number of Articles in database: <%= #count_of_articles %></p>
<h4>All Comments Written So Far</h>
<% #comments.each do |c| %>
<p><b><%= c.commenter %></b></p>
<p><%= c.body %></p>
<% end %>
<%= link_to 'New Article', new_article_path %>
This is my Article's index action
def index
#articles = Article.all
#count_of_articles = #articles.count
#comments = Comment.all
end
I am trying to figure out how to place the number of comments that each article has in the <td>Placeholder</td>
How do I do that?
EDIT
class Comment < ActiveRecord::Base
belongs_to :article
end
class Article < ActiveRecord::Base
has_many :comments, dependent: :destroy
validates :title, presence: true, length: { minimum: 5 }
end

by doing article.comments.count in the view you're basically running a sql query for each article in your db. Why not gather all records in your controller, and ask for the count in your view?, something like:
in the controller:
#comments_by_article = Comment.all.group_by(&:article_id)
and, in your view:
<td><%= #comments_by_article[article.id] && #comments_by_article[article.id].count || 0 %></td>
that way, rails will cache #comments_by_article in your controller, and you'll hitting the database once.

It is simply count:
<table>
<tr>
<th>Title</th>
<th>Text</th>
<th colspan="3"></th>
<th>Total Number of Comments Per Article</th>
</tr>
<% #articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
<td><%= article.comments.count %></td>
</tr>
<% end %>
</table>
article.comments is an ActiveRecord::Relation which extends the ActiveRecord::Calculations class containing the count method. The relation was defined in your model by you. Internally, ActiveRecord will call a COUNT SQL query to determine the number of comments that matches your article.

You can get the count with
article.comments.count

Related

Error when delete comment Ruby on Rails

When I delete comment I see
undefined method 'each' for nil:NilClass
Also, the user cannot delete his account if has posted... It makes the error.
This is code
<p id="notice"><%= notice %></p>
<h1>Comments</h1>
<table>
<thead>
<tr>
<th>Link</th>
<th>Body</th>
<th>User</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #comments.each do |comment| %>
<tr>
<td><%= comment.link_id %></td>
<td><%= comment.body %></td>
<td><%= comment.user %></td>
<td><%= link_to 'Show', comment %></td>
<td><%= link_to 'Edit', edit_comment_path(comment) %></td>
<td><%= link_to 'Destroy', comment, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Comment', new_comment_path %>
Your are not checking if any comments are present before looping through them. So if there are no comments you are calling each on nil.
This should fix it
<tbody>
<% if #comments.any? %> <----- Add in this line and the end below
<% #comments.each do |comment| %>
<tr>
<td><%= comment.link_id %></td>
<td><%= comment.body %></td>
<td><%= comment.user %></td>
<td><%= link_to 'Show', comment %></td>
<td><%= link_to 'Edit', edit_comment_path(comment) %></td>
<td><%= link_to 'Destroy', comment, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
<% end %> <---- here
</tbody>

submit_tag with check_box_tag returning error

I'm having some trouble with check_box_tag and my method enable (a product can be disabled) in Ruby on Rails.
I created some checkbox so the user select the products that he wants to set enable = true.
Keeps returning the error "Couldn't find Product with 'id'=enable"
My method enable:
def enable
Product.update_all(["enable=?", true], :id => params[:selected_products])
redirect_to root_url
end
My routes.rb:
Rails.application.routes.draw do
get 'product_export/new'
get 'product_imports/new'
resources :users
resources :product_imports
resources :products do
collection do
post :import
post :export
post :enable
end
end
root to: 'products#index'
end
and finally my view with the table e the check_box_tag:
<%= form_tag enable_products_path, :method => :put do %>
<%= submit_tag "Enable products" %>
<table class="table table-striped table-responsive" id="productsTable">
<thead class="thead-inverse">
<tr>
<th/>
<th>Code</th>
<th>Enable</th>
<th>Bar code</th>
<th>Unit cost</th>
<th>Description</th>
<th>Family</th>
<th>Final</th>
<th>Measure</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #products.each do |product| %>
<tr>
<td><%= check_box_tag 'selected_products[]', product.id %></td>
<td><%= link_to (product.code), edit_product_path(product) %></td>
<td><%= product.enable %></td>
<td><%= product.bar_code %></td>
<td><%= product.unit_cost %></td>
<td><%= product.description %></td>
<td><%= product.family %></td>
<td><%= product.final %></td>
<td><%= product.measure %></td>
<td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
Thanks for the help!
Use where to find selected products and when to update them:
Product.where(id: params[:selected_products]).update_all(enable: true)

What is error with cancan in view

I am using cancan to authorize the user in controller,And in views i am using Can?to check if the user is authorize to see that function
index.html.erb
<p id="notice"><%= notice %></p>
<h1>Listing Noticeboards</h1>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>society</th>
<th>Notice heading</th>
<th>Notice text</th>
<th>Active</th>
<th>Isdelete</th>
<th>Expire</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #noticeboards = #noticeboards.where(Isdelete: 0).find_each %>
<% #noticeboards.each do |noticeboard| %>
<tr>
<td><%= Society.find_by(id: noticeboard.id_society, Isdelete: 0).name %></td>
<td><%= noticeboard.notice_heading %></td>
<td><%= noticeboard.notice_text %></td>
<td><%= noticeboard.active %></td>
<td><%= noticeboard.IsDelete %></td>
<td><%= noticeboard.Expire %></td>
<td><%= link_to 'Show', noticeboard %></td>
<% if can? :update, noticeboard %>
<td><%= link_to 'Edit', edit_noticeboard_path(noticeboard) %> <% end %></td>
<% if can? :delete , noticeboard %>
<td>
<%= link_to 'Destroy', noticeboard, method: :delete, data: { confirm: 'Are you sure?' } %></td> <% end %>
</tr>
<% end %>
</tbody>
</table>
<br>
<% if can? :create, #noticeboard %>
<%= link_to 'New Noticeboard', new_noticeboard_path %>
<% end %>
In this if i change :delete to anything else, say :Hello, its still checking can, and if i am not using anything, it gives error saying "wrong number of arguments" what is the error, why its not taking :delete function?

How do I connect a comment table to another table?

A pretty basic RoR question that I can't seem to find an answer to online:
I have two independent tables that were created with a scaffold.
lunches and comments. Relationships were not established during the scaffolding. I can redo the comments scaffold if needed.
I need to be able to take in and then display the related comments to every lunch in the lunch index view. Can someone tell me how to do that?
I edited the models\comment.rb to:
class Comment < ActiveRecord::Base
belongs_to :lunch
end
I edited the models\lunch.rb to:
class Lunch < ActiveRecord::Base
has_many :comments, dependent: :destroy
end
In the lunches view I have a loop that lists all the lunches columns:
<tbody>
<% #lunches.each do |lunch| %>
<tr class="<%= cycle('list_line_odd', 'list_line_even')%>">
<td><%= lunch.company %></td>
<td><%= lunch.person %></td>
<td><%= lunch.email_submit_lunch %></td>
<td><%= lunch.company_contact %></td>
<td class="list_description"><%= truncate(strip_tags(lunch.description), length: 40) %></td>
<td><%= lunch.date %></td>
<td><%= lunch.price %></td>
<td class="list_actions"><%= link_to 'Show', lunch %></td>
<td class="list_actions"><%= link_to 'Edit', edit_lunch_path(lunch), data: { confirm: 'Are you sure?' } %></td>
<td class="list_actions"><%= link_to 'Destroy', lunch, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
** Edit: I have redone the comments table to contain the lunch_id foreign key. How would I pass this foreign key (lunch_id) from the lunch view into the comment creation process?
You should use comments relation on lunch model.
If you established it correctly, then you can try something like:
<tbody>
<% #lunches.each do |lunch| %>
<tr class="<%= cycle('list_line_odd', 'list_line_even')%>">
<td><%= lunch.company %></td>
<td><%= lunch.person %></td>
<td><%= lunch.email_submit_lunch %></td>
<td><%= lunch.company_contact %></td>
<td class="list_description"><%= truncate(strip_tags(lunch.description), length: 40) %></td>
<td><%= lunch.date %></td>
<td><%= lunch.price %></td>
<td>
<%- lunch.comments.each do |comment| %>
<p><%= comment.body %></p>
<% end %>
</td>
<td class="list_actions"><%= link_to 'Show', lunch %></td>
<td class="list_actions"><%= link_to 'Edit', edit_lunch_path(lunch), data: { confirm: 'Are you sure?' } %></td>
<td class="list_actions"><%= link_to 'Destroy', lunch, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
UPD:
class CommentsController < ApplicationController
def create
lunch = Lunch.find(params[:lunch_id])
lunch.comments.create!(comment_params)
end
private
def comment_params
params[:comment].permit(:body)
end
end
In such case, when you post form to create comment, you should add lunch_id to form params, like:
lunch_path(lunch_id: lunch.id)
This is the main idea. But implementation can depend of your business logic. For example where do you locate new comment form and other conditions.
You didn't mention it in the description, but you will need to add the column lunch_id to the comments table (if you haven't already) for the relationship to work.
By defining that Lunch has_many :comments Rails will create a instance method for Lunch called comments that will return the associated comments.
In your view you can do something like this to display the comments.
<tbody>
<% #lunches.each do |lunch| %>
<tr class="<%= cycle('list_line_odd', 'list_line_even')%>">
<td><%= lunch.company %></td>
<td><%= lunch.person %></td>
<td><%= lunch.email_submit_lunch %></td>
<td><%= lunch.company_contact %></td>
<td class="list_description"><%= truncate(strip_tags(lunch.description), length: 40) %></td>
<td><%= lunch.date %></td>
<td><%= lunch.price %></td>
<ul>
<% lunch.comments.each do |comment| %>
<li><%= comment %></li>
<% end %>
</ul>
<td class="list_actions"><%= link_to 'Show', lunch %></td>
<td class="list_actions"><%= link_to 'Edit', edit_lunch_path(lunch), data: { confirm: 'Are you sure?' } %></td>
<td class="list_actions"><%= link_to 'Destroy', lunch, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
You will definitely need to establish a FK for lunches in the comments table. Adjust your migration to include:
create_table "comments" do |t|
t.string :body
t.integer :lunch_id
end
Then to display the comments, just loop through the comments on each lunch in your index view:
<td>
<% lunch.comments.each do |comment| %>
<p><%= comment.body %></p>
<% end %>
</td>
From what I understand you created both model scaffolds independently. This means that your db tables are not connected.
To actually make an association you have to add a column to comments table "lunch_id" (which would tell Rails to which lunch does the comment belong).
You can do this by running
rails g migration AddLunchIdToComment
after that open the newly created migration file and add the line
add_column, :comments, :lunch_id, :integer
inside the change function.
after that do rake db:migrate
Now you can access lunch related comments with lunch.comments method inside your view loop. This should make your code work (don't forget to restart the server).

Simple range search in Rails

I'm new to ROR and I'm trying to implement a simple search which should allow a user to search for hikes that match a certain range of difficulty. The form is properly displayed and I do not get any error messages, the problem is that no search results are dispayed.
I've been trying to solve this for a whole day now, so any help is extremely appreciated!
Index.html.erb
<%= form_tag wanderungens_path, :method => 'get' do %>
<p>
<%= number_field_tag ':search[dauer_von]', #search.dauer_von %>
<%= number_field_tag ':search[dauer_bis]', #search.dauer_bis %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
Wanderungens_controller.rb
def index
#search = WanderungenSearch.new(params[:search])
#wanderungens = #search.scope
end
wanderungen_search.rb
class WanderungenSearch
attr_reader :dauer_von, :dauer_bis
def initialize(params)
params ||= {}
#dauer_von = params[:dauer_von]
#dauer_bis = params[:dauer_bis]
end
def scope
Wanderungen.where('zeitdauer BETWEEN ? AND ?', #dauer_von, #dauer_bis)
end
I followed this tutorial: https://www.youtube.com/watch?v=Ri1YNjl1_hA
I'm on Rails 4.0.0 and Ruby 2.0.0
Update: This is the code where #Wanderungens is displayed:
<table>
<thead>
<tr>
<th>Description</th>
<th>User</th>
<th>Schwierigkeitsgrad</th>
<th>Zeitdauer</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% #wanderungens.each do |wanderungen| %>
<tr>
<td><%= wanderungen.description %></td>
<td><%= wanderungen.user.email if wanderungen.user %></td>
<td><%= wanderungen.schwierigkeitsgrad.description if wanderungen.schwierigkeitsgrad %></td>
<td><%= wanderungen.zeitdauer if wanderungen.zeitdauer %></td>
<td><%= link_to 'Show', wanderungen %></td>
<td><%= link_to 'Edit', edit_wanderungen_path(wanderungen) %></td>
<td><%= link_to 'Destroy', wanderungen, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
If I search from 1 to 2, the following request is generated:
http://localhost:3000/wanderungens?utf8=%E2%9C%93&%3Asearch[dauer_von]=1&%3Asearch[dauer_bis]=2

Resources