Trying to Wrap My Head Around HM:t and HABTM w/ a Sample App

I am cheap and in an attempt to learn about rails & relationships I’m
trying to create an application that my friends and I can use as a way
to split the cost of items we buy @ Costco.

Right now the models i have are:

User - Various people involved
Run - Represents Costco runs
Item - Individual items purchased during a Costco run

I was hoping that someone could point me in the right direction as to
how i setup up the relationships…

These are my models:

Item.rb

An item is purchased on a run and it’s cost can be split between many

Users. Because many Users can split the cost of an Item, it is owned by
1 or more Users.
belongs_to :run
belongs_to :user

Run.rb

A run is an individual trip to costco. On a run many items are

purchased.
has_many :items

User.rb

A User can participate in many runs and during the run will be buying

Items (or maybe buying a fraction of 1 item).
has_many :runs
has_many :items, :through => :participations #This is my area of
question

I realize this is incorrect as is, but could someone shed some light on
how i should be thinking about a situation like this?

Thanks for your time and for reading a big post like this :wink:

On Feb 13, 10:23 am, Marnen Laibow-Koser [email protected] wrote:

On Feb 12, 3:11 pm, Josh T. [email protected]
wrote:
[…]

User.rb

A User can participate in many runs and during the run will be buying

Items (or maybe buying a fraction of 1 item).
has_many :runs
has_many :items, :through => :participations #This is my area of
question

Why do you need a :through at all here? has_many :items should be
sufficient, if I understand the situation correctly.
[…]

Aack! Right after posting that, I realized something else. If a User
can participate in many Runs, and a Run can have many Users associated
with it, then you need

class Run
has_and_belongs_to_many :users
end

class User
has_and_belongs_to_many :runs
end

That will create a join table (called runs_users) associating Users
with Runs. The join table will not be able to hold any additional
information, and will not be associated with an ActiveRecord model
type. If you need the join to hold additional information or be an
ActiveRecord subclass, that’s what has_many :through is for.

In other words, has_and_belongs_to_many is kind of a special case of
the simplest type of has_many :through.

Does that help?

Best,

Marnen Laibow-Koser
[email protected]
http://www.marnen.org

On Feb 13, 10:30 am, Marnen Laibow-Koser [email protected] wrote:
[…]

class Run
has_and_belongs_to_many :users
end

class User
has_and_belongs_to_many :runs
end

That will create a join table (called runs_users) associating Users
with Runs.
[…]

Again with the posting too quickly…I made a silly error in this
description. Of course this won’t create a join table, but it will
expect one in the database as I described. Sorry about my incoherence
this morning.

Best,

Marnen Laibow-Koser
marnen@marnenorg
http://www.marnen.org

On Feb 12, 3:11 pm, Josh T. [email protected]
wrote:
[…]

belongs_to :user
This looks fine.

Run.rb

A run is an individual trip to costco. On a run many items are

purchased.
has_many :items

So does this. At some point, you might also need has_many :users; it
depends on what you’re doing.

User.rb

A User can participate in many runs and during the run will be buying

Items (or maybe buying a fraction of 1 item).
has_many :runs
has_many :items, :through => :participations #This is my area of
question

Why do you need a :through at all here? has_many :items should be
sufficient, if I understand the situation correctly.

I realize this is incorrect as is, but could someone shed some light on
how i should be thinking about a situation like this?

Thanks for your time and for reading a big post like this :wink:

You’re welcome!

Best,

Marnen Laibow-Koser
[email protected]
http://www.marnen.org

What about something like (not real code, just trying to convey the
idea):

Item (id, name)

an item is an item. given that you’ll probably

purchase the same item more than once, you could

generate an Item list as a shopping list for your

next Costco binge

has_many purchases

Purchase (id, item_id, run_id, amount)

on a run, you bought some item that cost some

amount, and someone’s gonna pay

belongs_to item
belongs_to run
has_many shares

Run (id, datetime?)

on this particular run, someone made some number of

purchases (User seems incidental to a run, important

only through its participation in shares)

has_many purchases

Share (id, user_id, purchase_id, percent)

the cost of each purchase can be divided between

one or more users

belongs_to user
belongs_to purchase

User(id, name)

each user can participate in any number of runs, and

would thereby be liable for some shares

has_many shares

Maybe this is a stupid follow up question, but could :through somehow
apply to this scenario?

Hi Ar Chron and Marnen Laibow-Koser,

Thanks a lot for responding. Both of your posts have helped me quite a
bit.

I think i need to go in the direction of Ar’s response though because it
seems a bit more robust. Especially considering the introduction of the
“Share” model as this will allow me to divide things up between Users
using different %s per user.

You do sometimes run into situations where people want to split things
in unequal percents – ie 24 box of Snickers; user1 takes 6 snickers,
user2 takes 6 snickers, and user3 gets 12 snickers and diabetes.

I will give this a go and if it turns out half descent put it on github
or something for other people who pride themselves on being cheap heheh

:slight_smile: