Rails, Tracking Last Viewed? Thoughts on Implementing a Sortable List
I have projects in my web app...
A user can have lets say 10 or more projects at a given point. When I output the user's project list, I'd like that list to be ordered by their last开发者_如何学C view.. Meaning at the top of the user's project list is the project they most recently visited and at the bottom is the project they visited last.
What's the best way for doing something like this? I do have a permissions table that manages the user's project permissions. I was thinking of adding it there, but that might be messy or inappropriate, IDK, love to hear your thoughts on that.
Also, at some point I'd like to give the user the ability to reorder their project lists, like a manual override, using a jQuery UI plugin like Sortable. Has anyone ever implement a Sortable type plugin for Rails?
thanks!!!
Since Projects are first class citizens of your app, they deserve the best attention--probably not a good idea to try to cram some aspect of them onto a permission model which has a different purpose.
Since Projects can have many users and users can have many projects, you'll need to add a many-to-many table model between them. Eg
class Project < ActiveRecord::Base
has_many :project_orders,
has_many :user_in_orders, # users who viewed the project, in order of view time
:class_name => "User", :through => :project_orders,
:order => "project_orders.last_viewed DESC"
class ProjectOrder < ActiveRecord::Base
# id
# user_id
# project_id
# position # default => 10000 # don't use field name of 'order'
# last_viewed
class User
has_many :project_orders,
has_many :orders, # The user's projects
:through => :project_orders,
:order => "project_orders.position, project_orders.last_viewed DESC"
You'd then be able to list the User's orders by last_viewed (default), with an override possible by setting the position field.
Since you want the rows with a position setting to sort first we use a very high number as the default position value. (Definitely a hack)
Added in response to comment about using nil as the default for position:
MySQL Order by clause puts null values first, not last, with an ascending sort. So if you want to override the last_viewed sort by explicitly setting the position field, you want the position fields that are set explicitly to have smaller values than the rows with the default. So we use a very high default, eg 10,000. (Figuring that users who want to explicitly order 10,000 projects will already have other issues to deal with.)
The other way to do it is to have the default be nil or 0, and sort the position field descending. But since the goal is to be able to explicitly override the last_viewed order, it is easier to think of position of 1 being the first listed, 2 being second listed, etc.
Also, remember that simply adding project_order records will sort them correctly. The most recently viewed will be shown first. The sort by position clause will have no effect in the default case since all of the records for a user will have the same default value for position. Sorting two records by position and last_viewed DESC is the exact same as sorting by only last_viewed DESC if both records have the same value for position.
Re: show most recently viewed first. -- Correct, you've spotted a bug. I should have included the DESC keyword. (Now fixed.)
I am not sure there is a "best" way to achieve this, a simple way would be to introduce a user_project_view (project_id, date, user_id, override_order)
table with a primary key on (project_id, user_id)
, and simply update this table when a user looks at a project.
Then on display, join and sort on that table. (you could order on [override_order, date] - which would allow users to override the order if they wish)
For the per user ordering, you could use something like act_as_list
You asked about JQuery-UI's Sortable being used in Rails. This is a great resource for setting that up in your app: #147 Sortable Lists (revised). I used that to implement Sortable in an app, and it worked with very little effort.
I think Larry K. is right: You should put a "last_viewed" attribute on your Project model. You'll also need the "position" attribute if you want to use sortable.
Good luck!
精彩评论