2009-12-30 3 views
0

У меня есть сложная таблица, вытащенная из массива объектов multi-ActiveRecord. Этот список представляет собой комбинированный показ всех «любимых» предметов определенного пользователя (песни, сообщения, сообщения в блогах, что угодно). Каждый из этих элементов является полноценным объектом AR.Сортировка/разбиение на страницы/многокомпонентные многоуровневые таблицы объектов в рельсах

Моя цель - предоставить пользователю упрощенный интерфейс поиска, сортировки и разбивки на страницы. Пользователь не должен знать, что у песни есть певец и что у сообщения есть автор - для конечного пользователя обе записи в таблице будут отображаться как «Пользователь». Таким образом, поле поиска будет просто выпадающим списком с запросом на поиск (имя пользователя, созданное на и т. Д.). Внутри мне нужно было бы преобразовать это в соответствующий поиск объектов, объединить результаты и отобразить.

Я могу, отдельно, разбивать на страницы (mislav will_paginate), сортировать и фильтровать, но вместе у меня возникают проблемы с их объединением.

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

Однако, если я хочу сортировать список, я не могу сортировать его через плагин для разбивки на страницы, потому что он полагается на предположение, что результирующий набор получен из одного SQL-запроса, а также что имя поля согласовано во всем. Таким образом, я должен сортировать объединенный массив через ruby, например.

@items.sort_by{ |i| i.whatever } 

Но, так как элементы не имеют общие названия, я должен сначала допросить объект, а затем вызвать правильную сортировку. Например, если пользователь хочет сортировать по имени пользователя, если отсортированный объект является сообщением, я сортирую по автору, но если объект является песней, я сортирую певцом. Все это очень грубо и выглядит совсем не-рубиново.

Эта же проблема вступает в игру с фильтром. Если пользователь фильтрует «родительский элемент» (поток сообщения, альбом песни), я должен перевести его на соответствующий метод объекта коллекции. Также брутто.

Это не точная настройка, но достаточно близко. Обратите внимание, что это устаревшее приложение, поэтому его изменение довольно сложно, хотя и невозможно. Кроме того, да, есть некоторые СУХИЕ, которые можно сделать, но не фокусируйтесь на стиле или элегантности следующего кода. Стиль/элегантность решения важны, однако! : D

модели:

class User < ActiveRecord::Base 
    ... 
    has_and_belongs_to_many :favorite_messages, :class_name => "Message" 
    has_and_belongs_to_many :favorite_songs, :class_name => "Song" 
    has_many    :authored_messages, :class_name => "Message" 
    has_many    :sung_songs,  :class_name => "Song" 
end 

class Message < ActiveRecord::Base 
    has_and_belongs_to_many :favorite_messages 
    belongs_to    :author, :class_name => "User" 
    belongs_to    :thread 
end 

class Song < ActiveRecord::Base 
    has_and_belongs_to_many :favorite_songs 
    belongs_to    :singer, :class_name => "User" 
    belongs_to    :album 
end 

контроллер:

def show 
    u = User.find 123 

    @items = Array.new 
    @items << u.favorite_messages 
    @items << u.favorite_songs 
    # etc. etc. 

    @items.flatten! 

    @items = @items.sort_by{ |i| i.created_at } 

    @items = @items.paginate :page => params[:page], :per_page => 20 
end 

def search 

    # Assume user is searching for username like 'Bob' 

    u = User.find 123 

    @items = Array.new 
    @items << u.favorite_messages.find(:all, :conditions => "LOWER(author) LIKE LOWER('%bob%')") 
    @items << u.favorite_songs.find(:all, :conditions => "LOWER(singer) LIKE ... ") 
    # etc. etc. 

    @items.flatten! 

    @items = @items.sort_by{ |i| determine appropriate sorting based on user selection } 

    @items = @items.paginate :page => params[:page], :per_page => 20 
end 

вид:

#index.html.erb 
    ... 
    <table> 
    <tr> 
     <th>Title (sort ASC/DESC links)</th> 
     <th>Created By (sort ASC/DESC links))</th> 
     <th>Collection Title (sort ASC/DESC links)</th> 
     <th>Created At (sort ASC/DESC links)</th> 
    </tr> 
    <% @items.each |item| do %> 
     <%= render { :partial => "message", :locals => item } if item.is_a? Message %> 
     <%= render { :partial => "song", :locals => item } if item.is_a? Song %> 
    <%end%> 
    ... 
    </table> 

    #message.html.erb 
    # shorthand, not real ruby 
    print out message title, author name, thread title, message created at 

    #song.html.erb 
    # shorthand 
    print out song title, singer name, album title, song created at 

ответ

0

Как и FYI, мне удалось выполнить все это с действительно толстой моделью, но, похоже, она работает очень хорошо.

3

Вы должны попытаться думать-сфинкс , Чтобы получить представление о том, как это работает, вы можете посетить мой сайт по адресу www.campzero.com и попробовать поиск с помощью «Дакки»

Thinking-sphinx - это плагин для рельсов, который поможет вам в поиске нескольких моделей/полей и он имеет разбиение на страницы/сортировку в построенных. Подробнее на thinking-sphinx сайт.

+0

Мне нравится, но установка поисковой системы для этой маленькой функции кажется излишней (поскольку она не является триалом для запуска сфинкса и т. Д.) –

+1

Срок действия вашего домена истек. –

0

Вы также можете добавить методы #collection_title и #title для каждого типа item и выполнить сортировку с помощью ducktyping.

Смежные вопросы