Simple question about ActiveRecord associations - ruby-on-rails

My application has the concept of a "Loan". Each loan has a creditor, a debtor, and an amount.
From a database perspective, I know that I want the loans table to look something like this:
|id|Amount|creditor_id|debtor_id|
| 1| 100| 5| 7|
Where creditor/debtor ids reference User ids (i.e., the primary key for rows in my users table).
My question is how I should set this up in ActiveRecord. I can't do something like:
class Loan < ActiveRecord::Base
has_one :creditor
Since this will cause rails to look for a 'creditors' table (and the creditors are all stored in the users table).

The option (naturally, well-documented in the Rdoc) is :class_name. I believe the syntax is:
has_one :creditor, :class_name => 'User'
Also, you may want to bookmark this:
http://api.rubyonrails.org/
Could save a few minutes next time.

This is not as easy as it looks. Can users be both creditors and debtors? Can they have more than one loan?
Basically, it looks like you want a self-referential many-to-many relationhip. You want a join model called loan because you have extra data in your join table so you should use has-many :through. Here is a good blog post on the differences between habtm and has-many :through.
There are plenty of examples around of how to do complicated things with your model relationships. Be warned though that all the fancy model setup is not matched by examples of how to then setup your controllers and views. It seems the tutorial writers all steer well clear of full examples of many-to-many relationships with controllers and views because it is pretty hard.
Good luck

Related

Fun Rails ActiveRecord Join with attributes

I'm feeling rusty on my basic rails and working on a simple music stats service.
class User
has_many :monthly_top_artists # this model also has play_count and month attrs- not just a join
has_many :top_artists, through: monthly_top_artists, source: :artist
I've basically written my own #monthly_top_artists query method which queries for a specific month's artists. right now i'm working with a line like this:
current_top_artists = MonthlyTopArtist.where(user_id: id, month: time_range)
.joins(:artist).select('month,name,play_count,user_id,artist_id,monthly_top_artists.updated_at')
The purpose of this is to load up my MonthlyTopArtist model with all the artist data as well- but am I just forgetting some basic rails/active record methods that can handle this for me? I could also use user.top_artists with the code above, but this would give me the same problem- the monthly statistics are in another table. Am I overthinking this in trying to limit my db queries? I realize that writing my own getter method is a little bit more than vanilla rails but this join + selecting attributes not defined on my MTA model is making me think there is something bigger wrong with my schema (or i'm just forgetting something).

Referencing attributes across multiple tables in Rails

Let me try and condense my question:
I want to display data from multiple tables in a particular view. I want to list every person I have in a "People" table, and append there job on an "Affiliations" table listed with their company from an "Employers" table. Affiliations should belongs_to People and Employers, and Employers and People have_many Affiliations. What would the migration and controller look like?
I'm not entirely sure if this is the same as what you're asking, but using has_many and belongs_to may be a better solution. Using these associations would allow an employee to have many employers and then simply get the most recent one.
Please feel free to correct me if this isn't what you are asking.

How to design/model a has many relationship that has a meaningful join table?

I wasn't able to put well into words (in Question title) what I'm trying to do, so in honor of the saying that an image is worth a thousand words; In a nutshell what I'm trying to do is..
Basically, what I have is A Teacher has many Appointments and A Student has many Appointments which roughly translates to:
I'm trying to stay away from using the has_and_belongs_to_many macro, because my appointments model has some meaning(operations), for instance it has a Boolean field: confirmed.
So, I was thinking about using the has_many :through macro, and perhaps using an "Appointable" join table model? What do you guys think?
The Scenario I'm trying to code is simple;
A Student requests an Appointment with a Teacher at certain Date/Time
If Teacher is available (and wants to give lesson at that Date/Time), She confirms the Appointment.
I hope you can tell me how would you approach this problem? Is my assumption of using the has_many :through macro correct?
Thank you!
Both teachers and students could inherit from a single class e.g. Person. Then create an association between Person and Appointments. This way you keep the architecture open so that if in the future you want to add 'Parents' then they could easily be integrated and may participate in appointments.
It may not be completely straightforward how you do the joins with the children classes (Students, Parents, Teachers). It may involve polymorphic relationships which I don't particularly like. You should though get away with a single join table.
In any case, you want to design so that your system can be extended. Some extra work early on will save you a lot of work later.

rails rich join model controller example

I have been reading up on some rails stuff and one thing I never came across is an example of what the controller or the view pages of a rich join model looks like.
Is it general practice not to have a controller/view pages off of those models?
Does anyone have any code example of the controller/view for a rich join?
edit: defining rich join.
Model A
has_many :model_c
has_many :model_b, :through => model_c
Model B
has_many :model_c
has_many :model_a, :through => model_c
Model C
belongs_to :model_a
belongs_to :model_b
I am curious to see how the controller of model C looks like given it's a join model between model A and B. For example, when you need to create a new Model C page, how do you retrieve and store the values for model_a.id and model_b.id so that it's all connected.
Ok, so I can give you my personal opinion of this and that is "it depends". :)
I've seen projects where there is a full scaffold for the join-model, and I've seen projects where there's none. Generally the difference is in how important the join-model is. if there's only, like, one or two extra columns on it - and they're generally only displayed on, say, the user's profile page, then don't bother. But if the join-model really is richly decorated... well it's really a whole model in its own right - and deserves a full scaffolding to cover that.
Sometimes there's a full scaffolding but only from certain perspectives.
A good example of the latter might be where you have models A&B be "user" and "service" and model C as "subscriptions".
In some situations, users can only see a list of services, and a list of their own subscriptions to them... and a service could only see a list of subscribed users... and admins could see all of them.
so... it depends :)

Resources that best explain associations used in Rails

I am coming from a Java background where we write our own queries or stored procedures and deal directly with low level database stuff.
I am going though AWDR 3rd edition book and can not grasp the joins concept.
Can someone share a resource they used when first coming to Rails?
Let's say I want a Customer table and Order table. a customer can place many orders. So will my Customer Model class contain :has_many order_id
If I do the above, will it make foreign/primary keys in the actual database?
Now let's say I want to find all customers which order with id 5.
How will I do that?
Is it good to just go with find_by_sql?
Take a look at http://guides.rubyonrails.org/association_basics.html
It has a pretty good explanation of Rails Associations, how they work, why you need them, and how to use them.
I think I can give you a quick rundown.
You're used to dealing with SQL directly, and the nice thing is that Rails promotes good database design. If you have a books table and a chapters table, then a book will have many chapters, correct? So just as in other database setups, the chapter table should have a foreign key telling what book it belongs to.
Assuming you have this foreign key in the chapters table, you can setup your Book model like so:
# app/models/book.rb
class Book < ActiveRecord::Base
has_many :chapters
end
You're telling Rails that a book literally has many chapters. So if you have a book object, you can say book.chapters and that will return an array of the chapter objects that belong to this book. Rails will know to look at the chapters table for the book_id foreign key, no custom SQL required.
Conversely, assuming this same database setup, you can define your chapter model to be associated with books, like this:
# app/models/chapter.rb
class Chapter < ActiveRecord::Base
belongs_to :book
end
Notice :book here is singular, just an idiom that helps readability, since a chapter can only belong to a single book. Now if you have a chapter object and say chapter.book, it will return the book object that the chapter belongs to.
Just as in other database applications, the foreign key is always on the "belonged to" table.
I hope this helps!
As suggested the Ruby On Rails Guides is a good place to start, along with the RailsCast site
The key point is that the foreign keys, although implied by the use of the ActiveRecord abstractions such as :belongs_to, :has_many, :has_and_belongs_to_many etc, are not created for you. In the Rails Guides notes on Associations you'll notice comments like:
"In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations."
This note is often referenced in the details of the individual associations under the :foreign_key option.
I guess it's often not obvious and from my experience (esp. coming from a Java/C++ background) I found that I had to print out and read the set of guides a couple of times to really appreciate the elegance, simplicity as well as the wealth of information contained within them.
On a side note - it's great not to have to deal with all the low level plumbing as per the Java experience.

Resources