我有一个从多个ActiveRecord对象数组中提取的复杂表。此列表是所有特定用户的“最喜欢”项目(歌曲,消息,博客帖子等)的组合显示。这些项目中的每一项都是一个成熟的AR对象。
我的目标是为用户提供简化的搜索,排序和分页界面。用户不需要知道歌曲有歌手,并且消息有作者 - 对于最终用户,表格中的两个条目都将显示为“用户”。因此,搜索框将只是一个下拉列表,询问他们要搜索的内容(用户名,创建时间等)。在内部,我需要将其转换为适当的对象搜索,组合结果并显示。
我可以单独进行分页(mislav will_paginate),排序和过滤,但我在组合它时遇到了一些问题。
例如,如果我对组合的项目列表进行分页,则分页插件处理它就好了。由于分页在应用程序与数据库之间发生,因此效率不高,但我们假设预期的用例表明绝大多数用户将拥有少于30个收藏项和所有其他行为,服务器功能等。表明这不会成为瓶颈。
但是,如果我希望对列表进行排序,我无法通过分页插件对其进行排序,因为它依赖于假设结果集是从单个SQL查询派生的,并且字段名称始终是一致的。因此,我必须通过ruby对合并的数组进行排序,例如
@items.sort_by{ |i| i.whatever }
但是,由于项目不共享通用名称,我必须先询问对象,然后调用正确的排序依据。例如,如果用户希望按用户名排序,如果排序的对象是消息,我按作者排序,但如果对象是歌曲,我按歌手排序。这一切都很严重,感觉非常像红宝石。
同样的问题与过滤器一起发挥作用。如果用户过滤“父项”(消息的主题,歌曲的专辑),我必须将其转换为适当的集合对象方法。也很糟糕。
这不是确切的设置但足够接近。请注意,这是一个遗留应用程序,因此更改它非常困难,尽管并非不可能。此外,是的,可以做一些DRY,但不要专注于以下代码的风格或优雅。然而,解决方案的风格/优雅很重要! :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 :(得分:3)
你应该尝试思考 - 狮身人面像。只是为了了解它的工作原理,您可以访问我的网站www.campzero.com并尝试使用“达卡”进行搜索
Thinking-sphinx是一个rails插件,可以帮助您搜索多个模型/字段,并在内置中进行分页/排序。更多thinking-sphinx网站。
答案 1 :(得分:0)
就像一个FYI一样,我设法用一个非常胖的模型来完成所有这些,但它看起来效果很好。
答案 2 :(得分:0)
您还可以为每种类型的item
添加#collection_title和#title方法,并通过ducktyping进行排序。