Search code examples
ruby-on-railsputlink-to

Rails 4.2.4, link_to not working with put method


I have two links (upvote and downvote) with method put like this

<%= link_to 'upvote', comment_upvote_path(comment), method: :put, remote: true, id: "comment_upvote_link" %>
<%= link_to 'downvote', comment_downvote_path(comment), mthod: :put, remote: true, id: "comment_downvote_link" %>

here is my routes file for these two links

put '/comment/upvote/:id' => "comments#upvote", as: 'comment_upvote'
put '/comment/downvote/:id' => "comments#downvote", as: 'comment_downvote'

and in the comments controller (using acts_as_commentable_with_threading gem for comments)

class CommentsController < ApplicationController

before_action :authenticate_user!

def create
 commentable = commentable_type.constantize.find(commentable_id)
 @comment = Comment.build_from(commentable, current_user.id, body)
 if @comment.save
   make_child_comment
   redirect_to(:back, :notice => 'Comment was successfully added.')
 else
   redirect_to :back
 end
end

def upvote
 @comment = Comment.find(params[:id])
 current_user.up_votes @comment
 respond_to do |format|
   format.html { redirect_to Post.find(@comment.commentable_id) }
   format.js { render 'comments/votes/upvote' }
 end
end

def downvote
 @comment = Comment.find(params[:id])
 current_user.down_votes @comment
 respond_to do |format|
   format.html { redirect_to Post.find(@comment.commentable_id) }
   format.js { render 'comments/votes/downvote' }
 end
end

private

def comment_params
  params.require(:comment).permit(:body, :commentable_id, :commentable_type, :comment_id)
end

def commentable_type
  comment_params[:commentable_type]
end

def commentable_id
  comment_params[:commentable_id]
end

def comment_id
  comment_params[:comment_id]
end

def body
  comment_params[:body]
end

def make_child_comment
  return "" if comment_id.blank?
  parent_comment = Comment.find comment_id
  @comment.move_to_child_of(parent_comment)
end
end

comment model

class Comment < ActiveRecord::Base
default_scope -> { order(created_at: :desc)}
acts_as_nested_set :scope => [:commentable_id, :commentable_type]

validates :body, :presence => true
validates :user, :presence => true

acts_as_votable

belongs_to :commentable, :polymorphic => true

# NOTE: Comments belong to a user
belongs_to :user

def score
 self.get_upvotes.size - self.get_downvotes.size
end

def self.build_from(obj, user_id, comment)
 new \
   :commentable => obj,
   :body        => comment,
   :user_id     => user_id
end

#helper method to check if a comment has children
def has_children?
 self.children.any?
end

# Helper class method to lookup all comments assigned
# to all commentable types for a given user.
scope :find_comments_by_user, lambda { |user|
 where(:user_id => user.id).order('created_at DESC')
}

# Helper class method to look up all comments for
# commentable class name and commentable id.
scope :find_comments_for_commentable, lambda { |commentable_str, commentable_id|
 where(:commentable_type => commentable_str.to_s, :commentable_id => commentable_id).order('created_at DESC')
 }

# Helper class method to look up a commentable object
# given the commentable class name and id
def self.find_commentable(commentable_str, commentable_id)
 commentable_str.constantize.find(commentable_id)
end
end

log for upvote

Started PUT "/comment/upvote/13" for ::1 at 2015-12-27 04:12:12 +0500
Processing by CommentsController#upvote as JS
Parameters: {"id"=>"13"}
[1m[35mUser Load (0.0ms)[0m  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1  ORDER BY `users`.`id` ASC LIMIT 1
[1m[36mComment Load (0.0ms)[0m  [1mSELECT  `comments`.* FROM `comments` WHERE `comments`.`id` = 13  ORDER BY `comments`.`created_at` DESC LIMIT 1[0m
[1m[35m (0.0ms)[0m  SELECT COUNT(*) FROM `votes` WHERE `votes`.`votable_id` = 13 AND `votes`.`votable_type` = 'Comment' AND `votes`.`voter_id` = 1 AND `votes`.`voter_type` = 'User' AND `votes`.`vote_scope` IS NULL
[1m[35m (0.0ms)[0m  SELECT COUNT(*) FROM `votes` WHERE `votes`.`votable_id` = 13 AND `votes`.`votable_type` = 'Comment' AND `votes`.`voter_id` = 1 AND `votes`.`voter_type` = 'User' AND `votes`.`vote_scope` IS NULL
[1m[35m (0.0ms)[0m  BEGIN
[1m[36m (0.0ms)[0m  [1mCOMMIT[0m
[1m[35m (0.0ms)[0m  SELECT COUNT(*) FROM `votes` WHERE `votes`.`votable_id` = 13 AND `votes`.`votable_type` = 'Comment' AND `votes`.`vote_flag` = 1 AND `votes`.`vote_scope` IS NULL
[1m[35m (0.0ms)[0m  SELECT COUNT(*) FROM `votes` WHERE `votes`.`votable_id` = 13 AND `votes`.`votable_type` = 'Comment' AND `votes`.`vote_flag` = 1 AND `votes`.`vote_scope` IS NULL
[1m[36m (0.0ms)[0m  [1mSELECT COUNT(*) FROM `votes` WHERE `votes`.`votable_id` = 13 AND `votes`.`votable_type` = 'Comment' AND `votes`.`vote_flag` = 0 AND `votes`.`vote_scope` IS NULL[0m
Rendered comments/votes/upvote.js.erb (5.0ms)
Completed 200 OK in 25ms (Views: 15.0ms | ActiveRecord: 0.0ms)

log for downvote

Started GET "/comment/downvote/13" for ::1 at 2015-12-27 04:12:34 +0500

ActionController::RoutingError (No route matches [GET] "/comment/downvote/13"):
actionpack (4.2.4) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
web-console (2.2.1) lib/web_console/middleware.rb:39:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.2.4) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.2.4) lib/rails/rack/logger.rb:20:in `block in call'
activesupport (4.2.4) lib/active_support/tagged_logging.rb:68:in `block in tagged'
activesupport (4.2.4) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (4.2.4) lib/active_support/tagged_logging.rb:68:in `tagged'
railties (4.2.4) lib/rails/rack/logger.rb:20:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
rack (1.6.4) lib/rack/runtime.rb:18:in `call'
activesupport (4.2.4) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
rack (1.6.4) lib/rack/lock.rb:17:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/static.rb:116:in `call'
rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
railties (4.2.4) lib/rails/engine.rb:518:in `call'
railties (4.2.4) lib/rails/application.rb:165:in `call'
rack (1.6.4) lib/rack/content_length.rb:15:in `call'
puma (2.15.3) lib/puma/server.rb:541:in `handle_request'
puma (2.15.3) lib/puma/server.rb:388:in `process_client'
puma (2.15.3) lib/puma/server.rb:270:in `block in run'
puma (2.15.3) lib/puma/thread_pool.rb:106:in `call'
puma (2.15.3) lib/puma/thread_pool.rb:106:in `block in spawn_thread'

Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb (5.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb (25.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.2.1/lib/web_console/templates/_markup.html.erb (0.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.2.1/lib/web_console/templates/_inner_console_markup.html.erb within layouts/inlined_string (0.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.2.1/lib/web_console/templates/_prompt_box_markup.html.erb within layouts/inlined_string (0.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.2.1/lib/web_console/templates/style.css.erb within layouts/inlined_string (0.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.2.1/lib/web_console/templates/console.js.erb within layouts/javascript (60.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.2.1/lib/web_console/templates/main.js.erb within layouts/javascript (0.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.2.1/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.2.1/lib/web_console/templates/index.html.erb (130.0ms)

and in browser

<a id="comment_upvote_link" data-remote="true" rel="nofollow" data-method="put" href="/comment/upvote/13">upvoted</a>
<a mthod="put" id="comment_downvote_link" data-remote="true" href="/comment/downvote/13">downvote</a>

The problem is upvote link is working but downvote is not(not even showing any kind of error), but if i change downvote request method to get in routes file like this

get '/comment/downvote/:id' => "comments#downvote", as: 'comment_downvote'

then it will work. I don't know what's the problem here, if downvote is not working then upvote also should not work because they are both identical, i tries debugging it with debugger but is seems for downvote with put method control will not go into downvote action it just don't do anything.

Any help will be appreciated.


Solution

  • You have a typo in the downvote link:

    <%= link_to 'downvote', comment_downvote_path(comment), mthod: :put, remote: true, id: "comment_downvote_link" %>
    

    mthod -> method