Reputation: 887
I have two models, Task and Unit. A task has_many :units. I would like to order the units based on some kind of precedence. For example: There are two units A and B. A must be completed before B. Users can add another unit, for example C, between A and B. Unit C could also then be deleted - A and B's precedence will remain intact. Whats the most simple/straight forward way to implement this in Rails?
Ideas I have considered:
Adding a precedence integer column to the units table that gets updated on any operations that change the collection of units.
Adding a self join association to unit model pointing to the next/previous unit and modifying the associations when the unit collection is changed.
Upvotes: 1
Views: 60
Reputation: 37657
The right way to model your problem depends on how complicated your Task structures are going to be.
If a Task's Units can always be put into first-to-last order, giving each Unit an integer order will make it easiest to put Units into that order, with order
in ActiveRecord or sort
in memory. The only disadvantage is that when you add or remove a Unit you may need to save other Units to update their orders. That's probably not a big disadvantage if Tasks have smallish integer numbers of Units.
If a Task can have cycles, each Unit will need a reference to the Unit that precedes it. You might even end up needing a model to represent the relationship between a Unit and the Unit that follows it. So think through the use cases you expect to need to support and see which applies.
Upvotes: 1
Reputation: 322
You can use acts_as_votable gem. This migration can solve your problem:
class AddCachedVotesToPosts < ActiveRecord::Migration
def self.up
add_column :posts, :cached_votes_total, :integer, :default => 0
add_column :posts, :cached_votes_score, :integer, :default => 0
add_column :posts, :cached_votes_up, :integer, :default => 0
add_column :posts, :cached_votes_down, :integer, :default => 0
add_column :posts, :cached_weighted_score, :integer, :default => 0
add_column :posts, :cached_weighted_total, :integer, :default => 0
add_column :posts, :cached_weighted_average, :float, :default => 0.0
add_index :posts, :cached_votes_total
add_index :posts, :cached_votes_score
add_index :posts, :cached_votes_up
add_index :posts, :cached_votes_down
add_index :posts, :cached_weighted_score
add_index :posts, :cached_weighted_total
add_index :posts, :cached_weighted_average
# Uncomment this line to force caching of existing votes
# Post.find_each(&:update_cached_votes)
end
def self.down
remove_column :posts, :cached_votes_total
remove_column :posts, :cached_votes_score
remove_column :posts, :cached_votes_up
remove_column :posts, :cached_votes_down
remove_column :posts, :cached_weighted_score
remove_column :posts, :cached_weighted_total
remove_column :posts, :cached_weighted_average
end
end
Especially this column add_column :posts, :cached_votes_up, :integer, :default => 0
and this index add_index :posts, :cached_votes_score
Upvotes: 0