在 Rails 中通过 AJAX 加载更多用户电影

Posted

技术标签:

【中文标题】在 Rails 中通过 AJAX 加载更多用户电影【英文标题】:Load more user movies via AJAX in rails 【发布时间】: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'。

【问题讨论】:

您能粘贴日志吗?或者你可以安装github.com/charliesome/better_errors它会帮助你调试你的rails代码。 我在下面的主帖中添加了截图。 输入 rails 日志,或者直接转到您请求的此链接,您会看到实际错误 更新如下。感谢收看! 您必须在此处添加一些分页并发送递增的页面值,而不是用户 ID 或电影 ID。看看github.com/amatsuda/kaminari 或github.com/mislav/will_paginate。这是一个如何实现它的视频教程 - railscasts.com/episodes/174-pagination-with-ajax?view=asciicast 【参考方案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。

【讨论】:

以上是关于在 Rails 中通过 AJAX 加载更多用户电影的主要内容,如果未能解决你的问题,请参考以下文章

在 Rails 中通过 JS 设计注册#update

在 Laravel 中通过 ajax 加载更雄辩的 hasMany 关系查询?

在 jQueryUI 选项卡中通过 AJAX 加载 Google 可视化

如何在rails中通过tcp发送值?

如何在AngularJS中通过AJAX加载数据后重新初始化数据表?

如何在 ASP.NET MVC 中通过 Ajax 提交表单?