简体   繁体   中英

Rails 5 AJAX refusing to render partial

I created an AJAX function that allows you to click to refresh posts at the top of the stack. Unfortunately, the ajax function is receiving the wrong parameters and returning server error 500. I am simply trying to load the latest posts available (most recent) I can't catch where the error is coming from. What do I need to do to get the newest posts to load on the stack using AJAX GET in index.html.erb?

posts_controller.rb

class PostsController < ApplicationController

before_action :set_post, only: %[show edit update destroy share like]
before_action :authenticate_user!

def index
  following_ids = current_user.following_users.pluck(:id)
  following_ids << current_user.id
  @posts = Post.where(user_id: following_ids).order('created_at DESC').page(params[:page])
  @post = Post.new
end

def load_more
  following_ids = current_user.following_users.pluck(:id)
  following_ids << current_user.id
  @posts = Post.where(user_id: params[:following_ids]).order('created_at DESC').limit(20)
  respond_to do |format|
    format.html
    format.js
  end
end

index.html.erb

<div class="col-md-5">
  <div class="post-feed-bg">
    <div id="post-index-form" class="post-form-bottom-padding">
      <%= render 'posts/form' %>
    </div>

    <!---LOAD MORE POSTS BUTTON-->
      <%= link_to load_more_path(@posts), class: 'bttn-material-circle bttn-danger bttn-md load-more-posts', :remote => true do %>
        <i class="fas fa-sync"></i>
      <% end %>

    <div class="post-textarea-bottom-border"></div>
    <div class="text-center">
      <%= image_tag 'post/loading.gif', style: 'display: none;', class: 'loading-gif' %>
    </div>
    <div class="post-feed-container" id="container_posts">
      <% if @posts.present? %>
        <%= render partial: "posts/posts", locals: {posts: @posts} %>
       <% end %>
    </div>
  </div>
</div>

_posts.html.erb

<% @posts.each do |post| %>
  <div class="post-container" data-id="<%= post.id %>">
    <div class="media" style="padding-bottom: 2em;">
      <%= user_avatar_post(post.user) %>
      <div class="media-body post-user-name">
        <h5><i class="fas fa-user"></i> <%= link_to post.user.user_full_name, user_path(post.user) %></h5>
        <p><%= linkify_hashtags(post.body_text) %> </p>
      </div>
    </div>
    <div class="post-container-charm-bar">
      <ul>
        <li class="votes" id="#post_<%= post.id %>">
          <%= link_to like_post_path(post), style: 'text-decoration: none', class: 'like-btn', method: :put, remote: true do %>
            <p id="thumb-id" class="thumbs-up" style="cursor: pointer;">b</p>
          <% end %>
        </li>
        <li><strong class="likes-count"><%= number_with_delimiter(post.get_likes.size) %></strong></li>
        <li><%= link_to '#', data: {toggle: "modal", target: "#commentmodal"} do %>
            <%= link_to post_path(post, anchor: 'comments') do %>
              <i class="far fa-comments post-charm-bar-icon-color fa-2x"></i>
            <% end %>
          <% end %>
        </li>
        <li><strong><%= post.comment_threads.size %></strong></li>
        <li>
          <%= link_to({controller: 'posts', action: 'share', id: post.id}, method: :post, remote: true, style: 'text-decoration: none;')  do %>
            <i class="far fa-share-square fa-2x "></i>
          <% end %>
        </li>
        <li>
          <%= link_to post, style: 'text-decoration: none;' do %>
            <i class="fas fa-eye fa-2x"></i>
          <% end %>
        </li>
        <li>
          <%= link_to edit_post_path(post), style: 'text-decoration: none;' do %>
            <i class="fas fa-pencil-alt fa-2x post-charm-bar-icon-color"></i>
          <% end %>
        </li>
        <li>
          <% if current_user == post.user %>
            <%= link_to post_path(post), style: 'text-decoration: none;', method: :delete, remote: true do %>
              <i class="fas fa-trash-alt fa-2x"></i>
            <% end %>
          <% end %>
        </li>
      </ul>
    </div>

    <div class="container-fluid">
      <div class="row">
        <div class="col-md-12 post-image">
          <% if post.photo.present? %>
            <%= image_tag post.photo.feed_preview, class: 'd-flex align-self-start mr-3 img-fluid rounded', lazy: true %>
          <% else %>
          <% end %>
        </div>
      </div>
    </div>
  </div>
<% end %>


<script type="text/javascript">
    $(document).ready(function () {
        $("img").lazyload({
            effect: "fadeIn",
            skip_invisible: true,
            threshold: 500
        });
    });
</script>

index.js.erb

// Load new records
$("#container_posts").prepend("<%= escape_javascript(render(@posts)) %>").hide().fadeIn(1000);


//Append new data
$("<%= j render partial: "posts/#{@post.post_type}", locals: {post: @post } %>").appendTo($("#container_posts"));

//Update pagination link
<% if @posts.last_page? %>
$('.pagination').html("All done");
<% else %>
$('.pagination').html("<%= j link_to_next_page(@posts, 'Next Page', :remote => true) %> ");

routes.rb

 resources :posts, on: :collection do
    member do
    ......
    end
  end
  get "/load_more", to: "posts#load_more", as: 'load_more'

load_more_posts.js

$(document).on('turbolinks:load', function () {
    $('a.load-more-posts').click(function (e) {
        // prevent the default click action
        e.preventDefault();

        // hide more load more link
        $('.load-more-posts').hide();

        // show loading gif
        $('.loading-gif').show();
        // get the last id and save it in a variable 'last-id'
        var last_id = $('.post-container').last().attr('data-id');

        // make an ajax call passing along our last career insight id
        $.ajax({
            // make a get request to the server
            type: "GET",
            // get the url from the href attribute of our link
            url: "/posts",
            // send the last id to our rails app
            data: {
              id: last_id,
              user_profile: "", // maybe nil in certain cases
              _: ""
            },
            // the response will be a script
            dataType: "script",
            success: function (data, textStatus, jqXHR) {
                if (jqXHR.status == "204") {
                    $('.loading-gif').hide();
                    $('.load-more-posts').show();
                }

                $('.loading-gif').hide();
                $('.load-more-posts').show();
            },
            error: function (jqXHR, exception) {
            }
        })
    });
});

post parameters

=> #<Post id: 59, body_text: "Fix this!", photo: nil, user_id:
 2, created_at: "2018-11-02 19:13:09", updated_at: "2018-11-02 19:13:09", post_id: nil, post_id: nil, post_counter: 0, cached_votes_total: 0, cached_votes_score: 0, cached_votes_up: 0, cached_votes_do
wn: 0, cached_weighted_score: 0, cached_weighted_total: 0, cached_weighted_avera
ge: 0.0, hash_id: "DQxad5rRVvfb">

server stacktrace

Started GET "/load_more.%23%3CPost::ActiveRecord_Relation:0x0000000016f89718%3E" for 127.0.0.1 at 2018-11-03 00:32:58 -0400
Started GET "/posts?id=41&user_profile=&_=1541219410513" for 127.0.0.1 at 2018-11-03 00:32:58 -0400
Processing by PostsController#load_more as 
Processing by PostsController#index as JS
  Parameters: {"id"=>"41", "user_profile"=>"", "_"=>"1541219410513", "on"=>:collection}
  User Load (3.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 5], ["LIMIT", 1]]
  User Load (2.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 5], ["LIMIT", 1]]
DEPRECATION WARNING: Setting custom parent classes is deprecated and will be removed in future versions. (called from parent_class_name at C:/Ruby24-x64/lib/ruby/gems/2.4.0/bundler/gems/acts_as_follower-c5ac7b9601c4/lib/acts_as_follower/follower_lib.rb:10)
DEPRECATION WARNING: Setting custom parent classes is deprecated and will be removed in future versions. (called from parent_class_name at C:/Ruby24-x64/lib/ruby/gems/2.4.0/bundler/gems/acts_as_follower-c5ac7b9601c4/lib/acts_as_follower/follower_lib.rb:10)
   (2.0ms)  SELECT "users"."id" FROM "users" INNER JOIN "follows" ON "follows"."followable_id" = "users"."id" AND "follows"."followable_type" = $1 WHERE "follows"."blocked" = $2 AND "follows"."follower_id" = $3 AND "follows"."follower_type" = $4 AND "follows"."followable_type" = $5  [["followable_type", "User"], ["blocked", false], ["follower_id", 5], ["follower_type", "User"], ["followable_type", "User"]]
   (58.0ms)  SELECT "users"."id" FROM "users" INNER JOIN "follows" ON "follows"."followable_id" = "users"."id" AND "follows"."followable_type" = $1 WHERE "follows"."blocked" = $2 AND "follows"."follower_id" = $3 AND "follows"."follower_type" = $4 AND "follows"."followable_type" = $5  [["followable_type", "User"], ["blocked", false], ["follower_id", 5], ["follower_type", "User"], ["followable_type", "User"]]
Completed 406 Not Acceptable in 127ms (ActiveRecord: 5.0ms)



ActionController::UnknownFormat (ActionController::UnknownFormat):

SERVER Stacktrace Update 2

Rendered collection of posts/_post.html.erb [25 times] (3464.5ms)
  Rendered posts/_post.html.erb (2329.4ms)
  Rendered posts/index.js.erb (10273.4ms)
Completed 500 Internal Server Error in 109620ms (ActiveRecord: 24197.5ms)



ActionView::Template::Error (undefined method `user_profile' for nil:NilClass):
    1: <div class="post-container" id="post_<%= post.id %>" data-id="<%= post.hash_id %>">
    2:   <div class="media" style="padding-bottom: 2em;">
    3:     <%= user_avatar_post(post.user) %>
    4:     <div class="media-body post-user-name">
    5:       <h5><i class="fas fa-user"></i> <%= link_to  full_name(post.user), user_path(post.user) %></h5>
    6:       <p><%= linkify_hashtags(post.body_text) %> </p>

app/helpers/posts_helper.rb:3:in `user_avatar_post'
app/views/posts/_post.html.erb:3:in `_app_views_posts__post_html_erb__891594994_136890360'
app/views/posts/index.js.erb:6:in `_app_views_posts_index_js_erb__704681650_227473700'
Processing by ExceptionHandler::ExceptionsController#show as JS
  Parameters: {"id"=>"41", "_"=>"1541262709872", "on"=>:collection}
Error during failsafe response: Could not render layout: undefined method `[]' for nil:NilClass
  C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionview-5.2.0/lib/action_view/layouts.rb:418:in `rescue in _default_layout'
  C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionview-5.2.0/lib/action_view/layouts.rb:415:in `_default_layout'
  C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionview-5.2.0/lib/action_view/layouts.rb:392:in `block in _layout_for_option'
  C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionview-5.2.0/lib/action_view/renderer/template_renderer.rb:96:in `resolve_layout'

_post.html.erb partial is not rendering with user and bypassing helper methods in posts_helper.rb

posts_helper.rb

module PostsHelper
  def user_avatar_post(current_user)
    if current_user.user_profile.avatar.feed_thumb.url.nil?
      inline_svg 'user_dashboard/add-user-avatar.svg', size: '12% * 12%', class: 'd-flex align-self-start mr-3 purple-rounded rounded'
    else
      image_tag current_user.user_profile.avatar.feed_thumb.url, class: 'd-flex align-self-start mr-3 img-thumbnail rounded'
    end
  end

   def full_name(user)
     user.first_name + ' ' + user.last_name
   end
end

Updated Post Controller

def load_more
  if params[:last_post_id]
    following_ids = current_user.following_users.pluck(:id)
    following_ids << current_user.id
    @posts = Post.where(user_id: params[:following_ids]).where('id < ?', params[:last_post_id]).order('created_at DESC').limit(20)
  else
    head :no_content
  end
  respond_to do |format|
    format.html
    format.js
  end
end

rotute.erb

get "/load_more/:last_post_id", to: "posts#load_more", as: 'load_more'

index.html.erb

 <!---LOAD MORE POST BUTTON-->
        <div class="float-right" style="z-index: 1000;">
          <%= link_to load_more_path(@posts.last.id), class: 'bttn-material-circle bttn-danger bttn-md load-more-posts', :remote => true do %>
            <i class="fas fa-sync"></i>
          <% end %>
        </div>

I'm using friendly_id to hash ids for posts.

On your logs, you can see the load_more request has a really weird extension:

Started GET "/load_more.%23%3CPost::ActiveRecord_Relation:0x0000000016f89718%3E"

Rails think's that's the format and does not know how to render that format.

Your route is defined like this:

get "/load_more", to: "posts#load_more", as: 'load_more'

but you are using it like this

load_more_path(@posts)

and the route does not expect a parameter and it ends up using it as a format.

You should add something to the route so you know from what post "load more". I'll do something like:

get "/load_more/:last_post_id", to: "posts#load_more", as: 'load_more'

And use it like

load_more_path(@posts.last.id)

And on the controller you'll have access to params[:last_post_id] so you know you need to load more posts after that post id.

following_ids = current_user.following_users.pluck(:id)
following_ids << current_user.id
@posts = Post.where(user_id: params[:following_ids]).where('id < ?', params[:last_post_id]).order('created_at DESC').limit(20)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM