Skip to main content
Ask A Question
Notifications
You’re not receiving notifications from this thread.
Subscribe

A `has_one :through` association issue

Rails β€’ Asked by eelcoj

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.


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


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.


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

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


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. :)


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.


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. βœ”οΈ


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 29,763+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.