0

I'm trying to implement adding upvote and downvotes to an app, submit the controller actions remotely using a button or link_to, and refresh a count section with AJAX.

Somehow upvoting or downvoting always redirects to a path of a member. When I use head :no_content, I can't submit the form aka link_to. Having some respond_to do | f |... also just renders the action URL.

Thus, remote: true is kind of not working, as I have another controller using <%= form_for([entry, entry.review], remote: true, :authenticity_token => true) do |f| %> and it works perfectly.

I have tried implementing here, here, here, and this tutorial and this but nothing seems to work.

I'm using the acts_as_votable. Everything works except the routing functionality with AJAX

# routes.rb
resources :entries do
  member do
    post 'upvote'
    post 'unupvote'
    post 'downvote'
    post 'undownvote'
  end
end
# entries_controller.rb
  def upvote
    @entry.liked_by current_user
  end

  def unupvote
    @entry.unliked_by current_user
  end

  def downvote
    @entry.disliked_by current_user
  end

  def undownvote
    @entry.undisliked_by current_user
  end
# entries/index.html.erb
...
  <%= button_to upvote_entry_path(entry.id), remote: true,
              class: "btn",
              id: "upvote-button-#{ entry.id }" do %>
    <i class="bi bi-hand-thumbs-up" style="color: #ababab;" id="upvote-<%= entry.id  %>"></i>
    <small id="upcount-<%= entry.id %>" >
      <%= render 'entries/upvote', entry: entry %>
    </small>
  <% end %>
...
# entries/_upvote.html.erb
<%= entry.get_upvotes.size %>
# entries/upvote.js.erb
$('#upvote-<%= entry.id %>').className('bi bi-hand-thumbs-up-fill');
$('#upvote-<%= entry.id %>').attr('href', '/entries/<%= entry.id %>/unupvote');
$('#upcount-<%= entry.id %>').html('<%=j render 'entries/upvote', entry: entry %>');

Edit, I have changed my link_to to button_to, changed the routes to post

axelmukwena
  • 779
  • 7
  • 24
  • What kind of error message do you see in your logs? Another thing, I'm surprised to see upvote_entry_path. Should it not be entries_upvote_path? – Jussi Hirvi Feb 21 '21 at 16:11

2 Answers2

1

Not sure if your a tag is inside other elements but you might want to consider using a button_to instead of a link_to.

HJW
  • 342
  • 3
  • 13
  • I did that, and changed my routes to `post`, and I still get routing with `remote: true` – axelmukwena Feb 21 '21 at 13:06
  • Did you also shut off `turbo-links` by adding `data-turbolinks="false"` in the parent element? – HJW Feb 21 '21 at 13:44
  • I just removed the whole `turbo-links` functionality. I've read on lots of forums that it brings a lot of complications [here](https://community.theforeman.org/t/is-it-time-to-remove-turbolinks/7679/2) and other [here](https://www.danielsellergren.com/how-to-remove-turbolinks-from-rails-6) – axelmukwena Feb 21 '21 at 14:00
  • That shouldn't be necessary I think. The last resort I can come up with is to try to strip everything from your page, back to `application.html.erb` if necessary, and try to get one working `link_to` or `button_to` first – HJW Feb 21 '21 at 14:22
0

So far the temporary solution, not probably recommended but still does the job programming practice, is hiding and unhiding certain elements on specific conditions.

Upon user interaction (e.g onClick), unhide and hide elements while updating values that resemble the controller update. Simply simulate a refresh and update the form paths/controller actions they point to.

This will mostly work better with boolean check-box forms, likes or dislikes where variables will only alternate between two instances at max. Hence you don't have to write much javascript to handle pseudo outputs.

But still, I'm sure there's a better method for example WebSockets through Action Cable. That can probably be overkill but the closest to realtime updates. respond_to just doesn't seem to work

axelmukwena
  • 779
  • 7
  • 24