Display all comments and order them - ruby-on-rails

I want to display all comments (total number) on 'all' page. So, not all comments for a specific Post, but all comments in the entire app. I've tried with Comment.all, but it says it can't find post without an ID...
.../comments/all
routes
resources :posts do
resources :comments do
member do
put "like", to: "comments#upvote"
put "dislike", to: "comments#downvote"
end
end
end
comments_controller
def all
?
end
def index
#post = Post.find(params[:post_id])
#comments = #auto.comments.order("cached_votes_score DESC")
end
def show
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
end
...

You need a not nested route to comments:
routes
resources :posts do
resources :comments do
member do
put "like", to: "comments#upvote"
put "dislike", to: "comments#downvote"
end
end
end
get "comments#all"
comments_controller
def all
#comments=Comment.all
end

The problem is in your PostsController because what you want is not actually directly relevant to a post.
Try adding a collection route for comment
resources :comments do
member do
..
end
collection do
get :all # actually that is index
end
end
or simpler
#config/routes.rb
resources :comments, only: :index
and then a
#app/controllers/comments_controller.rb
def index
Comment.all
end
on your CommentsController will do.

Related

How to set a like button in rails

Hello I have an exercise app where a user should be able to Like some products.
I could find a way to display the product he liked, but I really can't figure how to create and make work the like button.
I am not using any gem, I wan't to understand how to do it from Scratch.
Here are my models:
class User < ApplicationRecord
has_many :likes
has_many :liked_products, through: :likes, source: :product
end
class Product < ApplicationRecord
has_many :likes
end
class Like < ApplicationRecord
belongs_to :user
belongs_to :product
end
In my view product show where I want the like button:
<h1><%= #product.name %></h1>
<%= link_to "Like", product_likes_path(#product), method: :put, remote: true %>
my routes:
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users
resources :products do
resource :likes
end
end
That's my products controller, I think things must come in here but I don't know HOW!
class ProductsController < ApplicationController
before_action :find_product, only: :show
def index
#products = Product.all
end
def show
##product.like => gives an error 404
end
private
def find_product
#product = Product.find(params[:id])
end
end
I had created a likes controller but it seems it is not useful.... So... I gave up there...
class LikesController < ApplicationController
def new
#like = Like.new(like_params)
end
def create
#like = Like.new(like_params)
end
private
def like_params
params.require(:likes).permit(:user_id, :product_id)
end
end
I would really enjoy some light on this please :)
Finally found out how to set the controller
class LikesController < ApplicationController
def create
#user = current_user.id
#product = params[:product_id]
likes = {user_id: #user, product_id: #product}
#like = Like.new(likes)
#like.save!
if #like.save
redirect_to user_path(#user)
else
redirect_to product_path
end
end
end
the buttton
<%= link_to "Like", product_likes_path(#product), method: :post %>
routes
Rails.application.routes.draw do
root to: 'products#index'
devise_for :users
resources :users
resources :users do
resources :products do
resources :likes
end
end
end
You could try something along these lines:
Routes:
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users do
resources :products do
resources :likes
end
end
resources :products do
resource :likes
end
end
Which will give you something like:
... other routes ...
user_product_likes GET /users/:user_id/products/:product_id/likes(.:format) likes#index
POST /users/:user_id/products/:product_id/likes(.:format) likes#create
new_user_product_like GET /users/:user_id/products/:product_id/likes/new(.:format) likes#new
edit_user_product_like GET /users/:user_id/products/:product_id/likes/:id/edit(.:format) likes#edit
user_product_like GET /users/:user_id/products/:product_id/likes/:id(.:format) likes#show
PATCH /users/:user_id/products/:product_id/likes/:id(.:format) likes#update
PUT /users/:user_id/products/:product_id/likes/:id(.:format) likes#update
DELETE /users/:user_id/products/:product_id/likes/:id(.:format) likes#destroy
... other routes ...
Then:
<%= link_to "Like", user_product_likes_path(#user, #product), method: :post, remote: true %>
And in your LikesController:
class LikesController < ApplicationController
def new
#like = Like.new(like_params)
end
def create
#like = Like.new(like_params)
if #like.save
... do something happy
else
... do something sad
end
end
private
def like_params
params.require(:likes).permit(:user_id, :product_id)
end
end
Untested, so buyer beware. You might need to fiddle with your like_params and other stuff.

Adding acts_as_votable voting to posts and comments, routing issue?

I am trying to use acts_as_votable voting system on both posts and comments in my rails app. I am currently generating some obviously improper routes for my comments#upvote and comments#downvote, Here they are below:
upvote_post PUT /posts/:id/upvote(.:format) comments#upvote
downvote_post PUT /posts/:id/downvote(.:format) comments#downvote
But they routes need to be something like /posts/comment/:id/downvote. Here is how I am currently doing my routes
resources :posts do
member do
put "like", to: "posts#upvote"
put "dislike", to: "posts#downvote"
end
resources :comments
member do
put "upvote", to: "comments#upvote"
put "downvote", to: "comments#downvote"
end
end
Also, will I need two votes tables since I want both comments and posts to be votable?
Here is my my comments controller if needed:
class CommentsController < ApplicationController
before_filter :authenticate_user!, :except => [:index, :show]
def index
#post = Post.find(params[:post_id])
#user = User.find(params[:user_id])
#comments = #post.comments.order('created_at desc')
end
def new
#post = Post.find(params[:post_id])
#comment = #post.comments.new(params[:id])
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
#comment.post_id = #post.id
#comment.user_id = current_user.id
if #comment.save
redirect_to post_comments_path(#post)
else
redirect_to new_post_comment_path(post)
end
end
def destroy
end
def upvote
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.upvote_by current_user
redirect_to post_comments_path(#post)
end
def downvote
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.downvote_by current_user
redirect_to post_comments_path(#post)
end
private
def comment_params
params.require(:comment).permit(:body, :post_id, :user_id)
end
end
Thanks for the help
As a rule you probably don't want to nest your routes so deep. And the comment vote doesn't need to know the id of the post, just the comment. You also might find that rather than have a separate method for up and down voting in the controller having the votes go to the VotesController and just handle it there
So, I would do something like this:
resources :posts do
resources :comments, only: [:new, :create, :destroy]
resources :votes, only: [:create, :update, :destroy]
end
resources :comment do
resources :votes, only: [:create, :update, :destroy]
end
That's if you want to have votes be a polymorphic relation on both in which case in your ApplicationsController you'd want a method like:
def find_model
params.each do |name, value|
if name =~ /(.+)_id\z/
return $1.classify.constantize.find(value)
end
end
nil
end
# VotesController
def create
model = find_model
if model
# do stuff
end
end
If you have separate votes tables you can skip this last part.
Had a similar problem fixed it by changing
put "like", to: "posts#upvote"
put "dislike", to: "posts#downvote
to
get "like", to: "posts#upvote"
get "dislike", to: "posts#downvote"
posts_controller
def upvote
#post.upvote_by current_user
redirect_to :back
end
def downvote
#post.downvote_by current_user
redirect_to :back
end
post show page
<%= link_to "like", like_post_path(#post), method: :get %>
<%= link_to "dislike", dislike_post_path(#post), method: :get %>
hope this helps

Unknown Action for Followers on UsersController - Rails Tutorial

I'm trying to implement a Follower system similar to Twitter in my app. I'm implementing the Follower system explained in Michael Hartl's Rails Tutorial:
http://ruby.railstutorial.org/chapters/following-users
I have noticed an issue after completing the example:
Going to /users/(id)/following or /users/(id)/followers displays the following error messages:
Unknown action
The action 'following' could not be found for UsersController
or
Unknown action
The action 'followers' could not be found for UsersController
What puzzles me about these errors is that I did define these actions in the UsersController:
def following
#title = "Following"
#user = User.find(params[:id])
#users = #user.followed_users.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title = "Followers"
#user = User.find(params[:id])
#users = #user.followers.paginate(page: params[:page])
render 'show_follow'
end
Here is my routes.rb file just in case the issue lies there:
AppName::Application.routes.draw do
#get "users/index"
#get "users/show"
authenticated :user do
root :to => 'home#index'
end
root :to => "home#index"
devise_for :users
resources :users do
member do
get :following, :followers
end
end
resources :works
resources :relationships, only: [:create, :destroy]
end
Additional information: I'm using Devise to handle user authentication.
FIXED:
The issue was the placement of the following and followed actions in the Users Controller.
In your config/routes.rb, the member actions must be one per line:
resources :users do
member do
get :following
get :followers
end
end
See also http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
resources :users do
member do
get :following
get :followers
end
end
the above routes work, and provide following_user_path and followers_user_path routes respectively

How to share a controller action for nested routes in Rails?

In Rails, when I need:
/comments
and
/posts/1/comments
How do I best organize CommentsController? E.g. let the routes share the index actions, or work with 2 controllers?
You can work with only one controller.
I would go with a before_filter to check if the post_id param is present:
class CommentsController < ApplicationController
before_filter :find_post, only: [:index]
def index
if #post.present?
## Some stuff
else
## Other stuff
end
end
private
def find_post
#post = Post.find(params[:post_id]) unless params[:post_id].nil?
end
end
And have in your routes (with the constraints of your choice) :
resources :posts do
resources :comments
end
resources :comments
I believe you want /comments only for show and index actions, right? Otherwise the post params will be lost when creating or updating a comment.
In your routes.rb you can have something like:
resources : posts do
resources :comments
end
resources :comments, :only => [:index, :show]
In your form:
form_for([#post, #comment]) do |f|
And in your controller, make sure you find the post before dealing with the comments (for new, edit, create and update, such as:
#post = Post.find(params[:post_id])
#comment = #post...
You can do almost anything you want with rails routes.
routes.rb
match 'posts/:id/comments', :controller => 'posts', :action => 'comments'}
resources :posts do
member do
get "comments"
end
end

One Resource belongs to two parent resources

in routes.rb
resources :restaurants do
collection do
get 'nearby'
end
resources :tickets
end
resources :users do
resources :tickets
end
If my controller, I can differentiate the parent resources
if params[:user_id].present?
#collection = User.find(params[:user_id])
else
#collection = Restaurant.find(params[:restaurant_id])
end
#ticket = #collection.tickets.new
but how can I differentiate, for example, path helper?
Thanks.
See polymorphic_path.

Resources