I'm building a site where users can track their collection of figures for Dungeons & Dragons (www.ddmdb.com). The models/relationships involved in this funcitonality are the following:
User:
- id
- login (username)
- a bunch of other fields
Miniature:
- id
- name
- number (# in the set, not count)
- release_id (foreign key)
- a bunch of other fields and foreign keys
Ownership:
- id (is this really even needed?)
- user_id
- miniature_id
- have_count
- favorite (boolean)
The pertinent relationships I have set up are as follows:
User:
- has_many :ownerships
- has_many :miniatures, :through => :ownerships, :uniq => true, :conditions => "ownerships.have_count > 0"
- has_many :favorites, :through => :ownerships, :source => :miniature, :uniq => true, :conditions => "ownerships.favorite = true"
Miniatures:
- has_many :ownerships
- has_many :owners, :through => :ownerships, :source => :user, :uniq => true, :conditions => "ownerships.have_count > 0"
Ownership:
- belongs_to :user
- belongs_to :miniature
I have a page where user's can both view and update their collection, as well as view other user's collections. It contains a list of all the miniatures on the site and a text box next to each where the user can enter how many of each miniature they have. This functionality also exists in sub-lists of miniatures (filtered by type, release, size, rarity, etc.)
When a user creates an account they have no entries in the ownership. When they use the collection page or sub-list of miniatures to update their collection, I create entries in the ownership table for only the miniatures on the submitting page. So if it's the full Collection list I update all minis (even if the count is 0) or if it's a sub-list, I only update those miniatures. So at any time a particular user I may have: - no entries in ownership - entries for some of the miniatures - entries for all the miniatures.
The problem I'm having is that I don't know how to query the database with a LEFT JOIN using a "Rails method" so that if a user doesn't have an entry for a miniature in Ownerships it defaults to a have_count of 0. Currently I query for each user_id/miniature_id combination individually as I loop through all miniatures and it's obviously really inefficient.
View:
<% for miniature in @miniatures %>
<td><%= link_to miniature.name, miniature %></td>
<td><%= text_field_tag "counts[#{miniature.id}]", get_user_miniature_count(current_user, miniature), :size => 2 %></td>
<% end %>
Helper:
def get_user_miniature_count(user, miniature)
ownerships = user.ownerships
ownership = user.ownerships.find_by_miniature_id(miniature.id)
if ownership.nil?
return 0
else
return ownership.have_count
end
end
An alternate solution would be creating entries for all miniatures when a user signs up, but then I would also have to add a 0 have_count for all users when a new miniature is added to the database after they sign up. That seems like it could get a bit complex, but perhaps it's the right way to go?
Is there a way to do the join and supply a default value for miniatures where there's no entries in the Ownership table for that particular user?