Ask A Question

Notifications

You’re not receiving notifications from this thread.

A `has_one :through` association issue

eelcoj asked in Rails β€’

Hi there, I just subscribed to GoRails and it has been really helpful so far already. πŸ‘

I've been unsure about how to tackle the following situation.

Imagine a Receipt model. It can have one Company. The Company can be added upon creation of the Receipt or added/edited later.
We don't want a simple has_one in Receipt. Since Companies can belong to many Receipts. This makes all sense, I hope.

I would go about it this way:

Receipt.rb
has_one :seller
has_one :company, through: :seller
Seller.rb
belongs_to :receipt
belongs_to :company
Company.rb
has_one :seller

Now this gives me an issue in edit with the receipts_controller, where I have build_company in the case no Company is set yet. The error is undefined method 'build_company' for #<Receipt:0x007fea82677298>. While I would definitely expect that to be possible at this stage.

Am obviously overlooking something, but I can't figure it out at this stage anymore.

Reply

Can't edit above post. Just to clarify: there are models above respectively: 'Receipt', 'Seller' and 'Company'.

Reply

I believe you want to create your assiciations more like this:

#seller.rb
has_many :receipts
has_many :companies, :through => :receipts

#company.rb
has_many :receipts
has_many :sellers, :through => :receipts

#receipt.rb
belongs_to :company
belongs_to :seller

This would give you methods such as

Company.first.receipts
Company.first.sellers
Seller.first.companies
Seller.first.receipts
Receipt.first.company
Receipt.first.seller

*edited

Try this association then update your controller as necessary. If you still can't get it to work as you want, include your controller action so I can see exactly how you're trying to save your object.

Reply

Huh, weird - get an error when trying to update posts and then when the page refreshed I had 3 input boxes...

See if this parses correctly...

Company.first.receipts
Company.first.sellers
Seller.first.companies
Seller.first.receipts
Receipt.first.company
Receipt.first.seller
Reply

Edit post stuff should be fixed now gentlemen. πŸ•

Reply

Thanks Jacob, interesting point where you go about it in a completly different way. I look at the models from "top to bottom". Where Receipt is "leading". Fyi. There's also an Account model who has_many :receipts. So an Account could have many Receipts and have one Company. The reason I have an extra join model is so that I don't have duplicate Companies in my DB.

How's my thinking here?

I need try your solution and have to make some changes to my DB for that. Will report back later. :)

Reply

Hey Jack, your associations should fit how you plan on querying and manipulating the data, not necessarily how your users interact with it or from one particular perspective. So the way I kind of look at it is you have 2 main components to a website - a frontend and a backend. Your frontend should be concerned with how your users interact with data on your site (UX) - and the backend should be concerned with how your server interacts with the data. This ensures that your users can use your site as effeciently as possible, and your application can run on your server as efficiently as possible. Your controllers and helpers get to then be the middleman that helps the two ideas communicate correct. Check out http://stackoverflow.com/questions/2116017/rails-has-one-through-association to get an idea of what I mean.

Regarding the account model, off the top of my head I believe I would adjust my models to be like this:

#seller.rb
has_many :receipts
has_many :companies, :through => :receipts
# no foreign_keys here

#company.rb
has_many :receipts
has_many :sellers, :through => :receipts
has_one :account
# no foreign_keys here

#receipt.rb
belongs_to :company
belongs_to :seller
# need company_id, account_id, seller_id fields here

#account.rb
has_one :company
has_many :receipts, :through => company
# need company_id here

This should let you then query Account.first.receipts to display all the receipts for that account and there wouldn't be any duplication of any records. You'd also get Company.first.account and Receipt.first.account You'll want to make sure you have the proper foreign_keys setup. I included a comment under each model for the keys that should be all you need.

Reply

Thanks again, Jacob. Makes way more sense to go about data/models/associations that way. I always went for the more "visual" way to make it easier to grasp. βœ”οΈ

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 81,842+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

    © 2024 GoRails, LLC. All rights reserved.