← Back to Upcase

Getting a nested resource in the show action


(Charlieanna) #1

why should we do a @card = deck.cards.find(params[:id]) where deck = Deck.find(params[:deck_id])
for a nested resource when we can do the same card using Card.find(params[:id]).
Isn’t id suppose to be unique?


(Charlieanna) #2

Is this so to save the look up on the database? Getting a deck and then a card only from that deck does a performance improvement while searching?


(Austin David) #3

Just joined learn and saw your question so I apologize in advance if this was already answered. But to answer your question, You can select from multiple decks and then cards from the selected deck so you need a way to find the deck first before choosing a card. Or to use Matt’s example of language flashcards, if you just got a card from Card.find(params[:id], how would you know if it’s from a Japanese deck, or a Russian deck.


(Charlieanna) #4

I am guessing that each Card belongs_to a Deck so if you first found the card you could do card.deck to find the associated deck.


(Austin David) #5

Just reread your original question again. I’m assuming the show action you’re referring to is in the Cards Controller, not the Decks Controller. In any case, don’t confuse the associations in the Card and Deck models with nested resources for cards and decks. The associations tell you which card belongs to what deck (card.deck) and what deck has what cards(deck.cards). Nested resources, on the other hand, tells the browser how to get to and display that deck and its cards via the show action. Type in rake routes from the command line and look for the route for the cards#show action, which should be ***/decks/:deck_id/cards/:id(.:format)***. You’ll see that in order to get a card you MUST get a deck id first. That’s why you have to do @deck=Deck.find(params[:deck_id] first before doing @card = deck.cards.find(params[:id]). Actually, if you replace those two lines in your Cards Controller with @card = Card.find(params[:id] as you suggest, you’ll get a routing error.


(Charlieanna) #6

But isnt card = Card.find(params[:id]) and

deck=Deck.find(params[:deck_id] 

@card = deck.cards.find(params[:id]) 

doing the same thing?


(Luís Ferreira) #7

If you’re querying for the unique id of a card, then it is. Unless you’re eager loading the cards from the deck, in which case, the second example will not go to the DB.

Here’s an example:

deck=Deck.includes(:cards).find(params[:deck_id]) # this will fetch the deck and all its cards (2 requests)
deck.cards.find(params[:id]) # this will fetch the cards from memory (0 requests)

The other example:

deck=Deck.find(params[:deck_id]) # fetches the deck (1 request)
card = Card.find(params[:id]) # fetches the deck (1 request)

As you can see, in this case you’ll do 2 requests in both approaches, but if you need to fetch more cards (or iterate over them), the first approach will still do only 2 request, whereas the second will do N+1 (for N equal to the number of cards for the deck).


(Austin David) #8

card = Card.find(params[:id]) only returns the front, back, and deck_id not the name of the deck.