Ruby on Rails will_paginate массив

Мне было интересно, может ли кто-нибудь объяснить, как использовать will_paginate в массиве объектов?

Например, на моем сайте у меня есть раздел мнения, в котором пользователи могут оценивать мнения. Вот метод, который я написал, чтобы собрать пользователей, которые оценили мнение:

def agree_list
  list = OpinionRating.find_all_by_opinion_id(params[:id])
  @agree_list = []
  list.each do |r|
    user = Profile.find(r.profile_id)
    @agree_list << user
  end
end

Спасибо

Ответ 1

will_paginate 3.0 предназначен для использования нового ActiveRecord::Relation в Rails 3, поэтому он определяет paginate только для отношений по умолчанию. Он все еще может работать с массивом, но вам нужно указать рельсы, чтобы потребовать эту часть.

В файле в config/initializers (я использовал will_paginate_array_fix.rb) добавьте этот

require 'will_paginate/array'

Затем вы можете использовать на массивах

my_array.paginate(:page => x, :per_page => y)

Ответ 2

Вы можете использовать Array#from для имитации разбивки на страницы, но настоящая проблема заключается в том, что вы вообще не должны использовать Array.

Это то, что сделано Ассоциации ActiveRecord. Вы должны внимательно прочитать это руководство, есть много полезных вещей, которые вам понадобятся, если вы разрабатываете приложения Rails.

Позвольте мне показать вам лучший способ сделать то же самое:

class Profile < ActiveRecord::Base
  has_many :opinion_ratings
  has_many :opinions, :through => :opinion_ratings
end

class Opinion < ActiveRecord::Base
  has_many :opinion_ratings
end

class OpinionRating < ActiveRecord::Base
  belongs_to :opinion
  belongs_to :profile
end

Важно, чтобы ваша схема базы данных соответствовала соответствующим соглашениям об именах, или все это сломается. Убедитесь, что вы создаете свои таблицы с Миграция базы данных вместо этого вручную.

Эти ассоциации создадут помощников на ваших моделях, чтобы сделать поиск намного проще. Вместо того, чтобы повторять список отзывов OpinionRatings и собирать пользователей вручную, вы можете сделать Rails для этого с помощью named_scope или scope в зависимости от того, используете ли вы Rails 2.3 или 3.0. Поскольку вы не указали, я приведу оба примера. Добавьте это в свой класс OpinionRating:

2.3

named_scope :for, lambda {|id| 
  {
    :joins => :opinion,
    :conditions => {
      :opinion => { :id => id }
    }
  }
}

named_scope :agreed, :conditions => { :agree => true }
named_scope :with_profiles, :includes => :profile

3.0

scope :agreed, where(:agree => true)

def self.for(id)
  joins(:opinion).where(:opinion => { :id => id })
end

В любом случае вы можете вызвать for(id) в модели OpinionRatings и передать ему идентификатор:

2.3

@ratings = OpinionRating.agreed.for(params[:id]).with_profiles
@profiles = @ratings.collect(&:profile)

3.0

@ratings = OpinionRating.agreed.for(params[:id]).includes(:profile)
@profiles = @ratings.collect(&:profile)

Результатом всего этого является то, что теперь вы можете легко разбивать страницы:

@ratings = @ratings.paginate(:page => params[:page])

Обновление для Rails 4.x: более или менее одинаковое:

scope :agreed, ->{ where agreed: true }

def self.for(id)
  joins(:opinion).where(opinion: { id: id })
end 

Хотя для новых Rails мое предпочтение kaminari для разбивки на страницы:

@ratings = @ratings.page(params[:page])

Ответ 3

Драгоценный камень will_paginate будет разбивать на страницы как запросы, так и массивы ActiveRecord.

list = OpinionRating.where(:opinion_id => params[:id]).includes(:profile).paginate(:page => params[:page])
@agree_list = list.map(&:profile)

Ответ 4

Если вы не хотите использовать конфигурационный файл или возникают проблемы с ним, вы также можете просто обеспечить возврат ActiveRecord:: Relation вместо массива. Например, измените список_согласования как список идентификаторов пользователей, а затем введите IN для этих идентификаторов, чтобы вернуть Relation.

def agree_list
  list = OpinionRating.find_all_by_opinion_id(params[:id])
  @agree_id_list = []
  list.each do |r|
    user = Profile.find(r.profile_id)
    @agree_id_list << user.id
  end
  @agree_list = User.where(:id => @agree_id_list) 
end

Это неэффективно с точки зрения базы данных, но это вариант для любого, у кого есть проблемы с конфигурационным файлом will_paginate.

Ответ 5

Я воспользовался ассоциациями рельсов и придумал новый метод:

def agree_list
  o = Opinion.find(params[:id])
  @agree_list = o.opinion_ratings(:conditions => {:agree => true}, :order => 'created_at DESC').paginate :page => params[:page]
rescue ActiveRecord::RecordNotFound
  redirect_to(profile_opinion_path(session[:user]))
end

На мой взгляд, я просмотрел такой профиль:

<% @agree_list.each do |rating| %>
  <% user = Profile.find(rating.profile_id) %>
<% end %>

Пожалуйста, опубликуйте, если есть лучший способ сделать это. Я попытался использовать помощник named_scope в модели OpinionRating без везения. Вот пример того, что я пробовал, но не работает:

named_scope :with_profile, lambda {|id| { :joins => [:profile], :conditions => ['profile_id = ?', id] } }

Это похоже на использование метода find.

Спасибо за помощь.

Ответ 6

Я использую рельсы 3 ruby ​​1.9.2. Кроме того, я просто запускаю приложение, поэтому никаких CSS или стилей не было.

Установить will_paginate:

gem install will_paginate

Добавить в Gemfile и запустить пакет.

контроллер

class DashboardController < ApplicationController
    include StructHelper

    def show
        @myData =structHelperGet.paginate(:page => params[:page])
    end

end

модуль StructHelper запрашивает службу, а не базу данных. structHelperGet() возвращает массив записей.

Не уверен, что более сложное решение будет заключаться в подделке модели или в том, чтобы захватывать данные так часто и воссоздавать таблицу sqlite время от времени и иметь реальную модель для запроса. Просто создайте мое первое приложение для рельсов.

Просмотр

<div id="Data">
                <%= will_paginate @myData%>
                    <table>
                    <thead>
                    <tr>
                    <th>col 1</th>
                    <th>Col 2</th>
                    <th>Col 3</th>
                    <th>Col 4</th>
                    </tr>
                    </thead>
                    </tbody>
                    <% @myData.each do |app| %>
                        <tr>
                           <td><%=app[:col1]%> </td>
                           <td><%=app[:col2]%> </td>
                           <td><%=app[:col3]%> </td>
                           <td><%=app[:col4]%> </td>
                        </tr>

                    <% end %>
                    </tbody>
                    </table>
                <%= will_paginate @myData%>
                </div>

Это даст вам pagnation 30 строк на странице по умолчанию.

Если вы еще не читали http://railstutorial.org, начните читать его сейчас.

Ответ 7

Вы можете реализовать разбиение на страницы даже без каких-либо драгоценных камней. Я видел это Как разбить массив на части? , Простая реализация в Kaminari Gems Doc. Пожалуйста, посмотрите ниже пример, который я получил от Kaminari Gems Doc

arr = (1..100).to_a
page, per_page = 1, 10
arr[((page - 1) * per_page)...(page * per_page)] #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
page, per_page = 2, 10
arr[((page - 1) * per_page)...(page * per_page)] #=> [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]