Doubts on what association to choose

Hello everyone,

I’m a beginner Rails developer and right now am building a sample project to show off at some job apply. The app is rather simple, I guess, but I have come to some doubts on what associations to chose and why.

Basically a User can create a bill(being its creditor) and the billing can have many other Users(as their debtors), so you can track up billings you share with other persons, like rent, market, food orders etc, and control what each one got to pay you.

Right now I have the following model:

class User < ActiveRecord::Base

has_many :billings, foreign_key: "creditor_id", dependent: :destroy

has_many :debts, foreign_key: "debtor_id", dependent: :destroy

end

class Billing < ActiveRecord::Base

belongs_to :creditor, class_name: "User"

has_many :debts, dependent: :destroy

end

class Debt < ActiveRecord::Base

belongs_to :billing

belongs_to :user

end

would this be the better approach? Or something like:

User has_many billings through debts

Billing has_many debts ?

And in that case, would appreciate some help to model those associations, because I’m still kinda lost on this flow.

Thanks in advance,

Diego Dillenburg Bueno

Assuming a single creditor and multiple debtors for a single billing, you will need a one to one relationship for the creditor -> billing (belongs_to on the billing, as you have done), but a many to many relationship for debts -> users.

Generally, it’s better to implement the many-to-many as a has_many :through so you can add logic. It’s probably doubly important when there is money involved!

I would rethink the dependent: destroy though. You probably want to use a soft delete instead, or else you will lose your past transactions.

Won’t I be able to add the logic I need for debts using has_many belongs_to? Basically all that I would need is to gather which debts I(as the user) have and be able to(in future) toggle their ‘paid/unpaid’ status. Or would it be better to have a relationship table? via has_many through?

As of the soft deleting I’m gonna narrow it down haha at first I’m just trying to build some concrete functionality, this is just to show some coding skills for an internship, gonna try 'n develop it much further when I get the time and skills.

Anywyay, thanks for helping!

Diego Dillenburg Bueno

Hi Diego,

You’re correct when you say you can add the logic for a has_many / belongs_to (which is a one to many relationship), but as far as I’m aware, you need a has_many :through for adding logic to a many-to-many relationship.

Good luck with the internship!

Timothy.

Diego,

You actually have a very good question here.

I don’t quite see all the foreign keys here, and I only grok 75% of your specific data model, so I will answer your question generally and give you some options rather than specifically tell you how to do it.

You probably read that the rails default is to use the class name as the association name. In the case of multiple associations to the same classes – possibly through join tables – this is actually a confusing way to name your associations.

Consider something that is not your data model: An “Article” that has both an Author (user object) and an Editor (user object)

The standard way to write your association is like so:

class Article < ActiveRecord::Base

belongs_to :user

end

But the problem here is that you actually want two relationships to two different user objects (one for author and another for editor).

As you have already discovered, you can use a different name for the association name, as long as you pass class_name as an option to your association declaration, like so:

class Article < ActiveRecord::Base

belongs_to :author, class_name: “User”

belongs_to :editor, class_name: “User”

end

In the example above, your Article table would have a foreign key for author and editor (my personal naming convention is to name these author_user_id and editor_user_id, that way the field conveys both the relationship itself and the class that it relates to).

The is a really, really good idea because the worst thing in an app is to have a relationship to a user_id and as the future developer be scratching your head wondering if the original developer intended that to be a “editor” or an “author”. I strongly recommend using this style of naming convention when you will have multiple relationships to the same classes, as you have in the example below (a user’s relationship to a billing can be either as a creditor or as a debtor).

Remember, the association name you give is for you (& Rails) to identify that association elsewhere in your codebase. Although the default is to use the name of the foreign class, it is by no means required.

As far as you actual question (should you use a direct relationship between User and Debt or should you use the has_many :through relationship, using the billings as a join table) – I think I understand that correctly — there is no one better to answer that than you. (Without knowing more about your data model I can’t advise).

But I can say that you should avoid duplicitous relationships (also known as circular dependancies). Note that if one relationship describe a creditor and the second one describes a debtor, that doesn’t actually count as duplicitous (for the purpose of my argument). It would be duplicitous if a foreign key describes the same relationship already described in another place (like a different foreign key or through a join table). That’s what you want to avoid.

The confusing part of your data model is that a Debt belongs_to a user (is that a creditor or debtor relationship? See how using non-default association names as explained above can be advantageous?)

If the context of the Debt record only has meaning by being related to a Billing, then it probably doesn’t make sense to also make it have a user_id (since you can derive that user by examining the relationship to the Billing object). Again, since you have some tricky stuff going on with debtors/creditors understand that I may not be understanding your data model fully.

I would recommend you create an old-fashioned ERD (Entity Relationship Diagram) on a napkin. Also you might want to learn a little bit about the ancient art of “3rd Normal Form”.

Hope this help!

Jason

Thank you very much for the attention, guys!
I think I have nailed the association modelling. And as of the debt relationship. It would be like: Someone pay for a bill(creditor) for many other people(those are debtors), that’s why I need to have 0, 1 or multiple debtors in one billing. That’s where I keep track of who owes me(creditor) money for that billing.

Now I’ve dived into a far more hairy problem:

I’m trying to dinamically generate nested forms(so I can input how many debtors I want at the billing creation)

I got it to work once, but now I don’t know what I might possibly have changed so it’s not working anymore.

Tried rbates railscast, then his gem nested_form, then cocoon and couldn’t get none of them to work properly anymore.

I tracked down the problem to be basically that: whenever I click the link to add fields it’s not triggering the creation of the new object, e.g. a Billing is created on action New but it’s not creating the further billing.debts that I need to store the multiple debtors I input in the forms.

I’m really lost at that point, tried everything, I just need to finish this functionality so I can add the ‘paid/unpaid’ status toggling and finish it.

If any of you guys can help me I’d reaaally appreciate!

The code is in my github: http://www.github.com/diegodlilenburg/codero

I don’t know which files are really relevant to this so I think it’s easier that I provide the full code, but mostly the functionalities are set in the views/billings, application_helper, application.js and the billings_controller.

All that code refers to the rbates railscast about nested forms(196 and 197 episodes) I can’t subscribe atm to see the revised version.

Any help trying to find the error would be awesome. I’m getting to my deadline. haha

Oh, and by the way, that 3rd normal form seems interesting, will take a look at it.

Thank you all again for the help!

Diego Dillenburg Bueno

Diego ,

Is the link working ? im getting a 404 error from github that repo does not exist.

Regards

Vivek

First look in development.log and check that the correct action is
being invoked and that the params are correct. Then you have to debug
your code. There are more sophisticated debug methods, but for a
start you can then put debug statements in the action to find out what
is going wrong. You can use logger.info to print stuff to the server
window to follow what is going on. For example
logger.info "At some interesting point in the code"
and
logger.info someobject.inspect

Then you should be able to work out where it is going wrong.

Having said that I assume that you have already worked right through a
good tutorial such as railstutorial.org (which is free to use online).
If not then go and do that first, it will save you time in the long
run.

Colin

Also look at http://guides.rubyonrails.org/debugging_rails_applications.html

Colin

Sorry, little typo there. corret is: http://www.github.com/diegodillenburg/codero I typed my name wrong hahaha.
@Collin, yeh I have debugparams in my views, which I learned on railstutorial, that’s how I somehow identified my problem. Anyway, I think I’ve managed to find the problem but still trying to find a way to work it around.

It’s either something related to my CSS messing up where the JS wants to apply its action or the way I render the form and fields_for

I think I know what it is now, but no clue why it happens.
It won’t work whenever I open a html tag before <%= form_for @billing do |billing| %> and close it before <%= f.fields_for :debts do |builder| %>

Anyone ever been through this or something similar? It must be some failure at the application.js script but I have no clue at all on how to handle it.

Do you mean you have <div><form>..</div>..</form>? if so then that is
not valid html. A useful technique when strange things are happening
is to copy the html source out of the browser and paste it into the
w3c html validator to check the html is valid. [1]

Colin

[1] http://validator.w3.org/#validate_by_input