Ruby on Rails будет_страивать массив - PullRequest
70 голосов
/ 04 декабря 2010

Мне было интересно, может кто-нибудь объяснить, как использовать 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

Спасибо

Ответы [ 7 ]

212 голосов
/ 07 декабря 2011

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

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

require 'will_paginate/array'

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

my_array.paginate(:page => x, :per_page => y)
9 голосов
/ 04 декабря 2010

Вы можете использовать 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])
4 голосов
/ 04 декабря 2010

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

list = OpinionRating.where(:opinion_id => params[:id]).includes(:profile).paginate(:page => params[:page])
@agree_list = list.map(&:profile)
1 голос
/ 29 июня 2013

Если вы не хотите использовать файл конфигурации или у вас возникли проблемы с ним, вы также можете просто убедиться, что вы возвращаете ActiveRecord :: Relation вместо массива.Например, вместо этого используйте accept_list как список пользовательских идентификаторов, а затем выполните 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.

0 голосов
/ 22 мая 2019

Вы можете реализовать нумерацию страниц даже без каких-либо драгоценных камней. Я видел это Как разбить массив на части?Простая реализация в 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]
0 голосов
/ 18 марта 2011

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

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

gem install will_paginate

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

Контроллер

class DashboardController < ApplicationController
    include StructHelper

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

end

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

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

Посмотреть

<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>

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

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

0 голосов
/ 04 декабря 2010

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

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.

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

...