【问题标题】:Load more user movies via AJAX in rails在 Rails 中通过 AJAX 加载更多用户电影
【发布时间】:2016-06-28 09:14:58
【问题描述】:

我有一个搜索电影应用程序 (Rails 4),在“my_movies”页面中,我尝试在页面加载时显示 2 部用户电影,然后在单击“加载更多”链接后显示其他 2 部。

现在我得到 500(内部服务器错误)这个代码。我认为我的控制器有问题。我做错了什么?

models/user.rb

class User < ActiveRecord::Base
  has_many :movies, dependent: :destroy
end

models/movie.rb

class Movie < ActiveRecord::Base
  belongs_to :user
end

controllers/users_controller.rb

class UsersController < ApplicationController
  before_action :authenticate_user!
  after_action :verify_authorized

  def my_movies
    authorize :user, :my_movies?
    if params[:id]
      @user_movies = current_user.movies.where('id < ?', params[:id]).limit(2)
    else
      @user_movies = current_user.movies.limit(2)
    end
    respond_to do |format|
      format.html
      format.js
    end
  end
end

views/users/my_movies.html.slim

.row
  .small-12.columns.block.movies_container
    = render 'users/user_movies'

.row
  .small-12.columns.block.load_more_container
    = image_tag 'spinner.svg', style: 'display: none;', class: 'loading_icon'
    = link_to 'Load More', my_movies_user_path, class: 'load_more'

views/users/_user_movies.html.slim

- @user_movies.each do |movie|
  h2.user_movie data-id='#{movie.id}'
    = link_to movie.title, movie_path(movie)

views/users/_user_movies.js.slim

| $('.movies_container').append('
= escape_javascript(render(partial: 'users/user_movies'))
| ');

js/user.coffee

# when the page is ready for manipulation
$(document).ready ->
# when the load more link is clicked
  $('a.load_more').click (e) ->
# prevent the default click action
    e.preventDefault()
    # hide load more link
    $('.load_more').hide()
    # show the loading icon
    $('.loading_icon').show()
    # get the last id and save it in a variable 'last-id'
    last_id = $('.user_movie').last().attr('data-id')
    # make an ajax call passing along our last users movie id
    $.ajax
      type: 'GET'
      url: $(this).attr('href')
      data: id: last_id
      dataType: 'script'
      success: ->
        # hide the loading icon
        $('.loading_icon').hide()
        # show our load more link
        $('.load_more').show()
        return
    return
  return

错误截图:

UPD:重新启动 Rails AJAX 后工作正常,但我得到了两倍的电影(显示相同),而不是从数据库中获取另外 2 个。

错误从这里 (2) 开始,也可能从这里 (1) 开始,因为我发送的是用户 ID,而不是他的最后一个电影 ID。

这是 XHR 启动时的控制台日志:

如何解决?

P.S.你可以找到这个应用here in GitHub,功能分支'Loading more'。

【问题讨论】:

标签: javascript ruby-on-rails ruby ajax coffeescript


【解决方案1】:

首先,我尝试使用 will_paginate gem 和无限滚动来处理它,但是在 Chrome 和 Firefox 中滚动检测遇到了麻烦(我使用 this railscasts 技术)。 所以我决定尝试new 想法(使用kaminari gem),它工作得很好(见下面的代码)除了我想像第一个例子一样通过滚动加载电影作为一个长列表或单击“加载更多”按钮,没关系。现在我只有一个按钮,女巫可以在不使用原始分页的情况下通过页面滑动我的电影。也许有人知道如何将它转换为长列表,就像我最初想要的那样?

感谢Dmitriy Nevzorov,他在cmets中为原帖提出了正确的方法。

模型与原帖中的相同

controllers/users_controller.rb

class UsersController < ApplicationController
  before_action :authenticate_user!
  after_action :verify_authorized

  def my_movies
    authorize :user, :my_movies?
    @user_movies = current_user.movies.order('created_at DESC').page(params[:page]).per(5)
  end
end

views/users/my_movies.html.slim

  .row
    .small-12.columns.block.movies_container
       = render 'users/user_movies'

  - unless @user_movies.current_page == @user_movies.total_pages
    .row
       .small-12.columns.block
          p.view_more
            = link_to('View More', url_for(page: @user_movies.current_page + 1))

views/users/my_movies.js.slim

| $('.movies_container').append('#{j render(partial: 'users/user_movies')}');
- if @user_movies.current_page == @user_movies.total_pages
  | $('.view-more').remove();
- else
  | $('.view-more a').attr('href', '#{url_for(page: @user_movies.current_page + 1)}');

views/users/_user_movies.html.slim

- @user_movies.each do |movie|
  h2
    = link_to movie.title, movie_path(movie)

js/my_movies.coffee

$ ->
  content = $('.movies_container') # where to load new content
  viewMore = $('.view_more')       # tag containing the "View More" link

  isLoadingNextPage = false  # keep from loading two pages at once
  lastLoadAt = null          # when you loaded the last page
  minTimeBetweenPages = 5000 # milliseconds to wait between loading pages
  loadNextPageAt = 1000      # pixels above the bottom

  waitedLongEnoughBetweenPages = ->
    return lastLoadAt == null || new Date() - lastLoadAt > minTimeBetweenPages

  approachingBottomOfPage = ->
    return document.documentElement.clientHeight +
        $(document).scrollTop() < document.body.offsetHeight - loadNextPageAt

  nextPage = ->
    url = viewMore.find('a').attr('href')

    return if isLoadingNextPage || !url

    viewMore.addClass('loading')
    isLoadingNextPage = true
    lastLoadAt = new Date()

    $.ajax({
      url: url,
      method: 'GET',
      dataType: 'script',
      success: ->
        viewMore.removeClass('loading')
        isLoadingNextPage = false
        lastLoadAt = new Date()
    })

  # watch the scrollbar
  $(window).scroll ->
    if approachingBottomOfPage() && waitedLongEnoughBetweenPages()
      nextPage()

  # failsafe in case the user gets to the bottom
  # without infinite scrolling taking affect.
  viewMore.find('a').click (e) ->
    nextPage()
    e.preventDefault()

P.S.更新的项目位于 GitHub 中的 here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    相关资源
    最近更新 更多