Help with nested resource

I was talking about this problem on here about a week ago, and then had
to
break off from working on it. Returning again.
I’m having an issue with a show action on a nested resource (REST based
controllers).

The main resource (not the nested one) is Candidates
The nested resource is Canbackgrounds

To show the relevant database columns(with example):
Candidates table:
| id | user_id | …other fields |
±----±-------------±---------------------|
| 12 | 1 | |

Canbackgrounds table:
| id | candidate_id | user_id |
±–±--------------------±--------------+
| 28 | 12 | 1 |

so to display candidates here, candidates/12
to display canbackgrounds - candidates/12/canbackgrounds/28 (And this
works)

The problem is the link_to
<%= link_to ‘show’, canbackground_url(@candidate) %>

when i hold the cursor over this link it shows
candidates/12/canbackgrounds/12 (maybe this is wrong)

which produces this error:
couldn’t find Canbackground with ID=12 AND (canbackgrounds.candidate_id

In the Canbackgrounds contoller I have a before filter which seems to be
necessary otherwise the error is “couldn’t fine without id”

before_filter :find_candidate
private
def find_candidate
@candidate_id = params[:candidate_id]
redirect_to candidate_url unless @candidate_id
@candidate = Candidate.find(@candidate_id)
end

Can anyone tell me where my problem is ?

TIA
Stuart

Stuart Fellowes wrote:

The problem is the link_to
<%= link_to ‘show’, canbackground_url(@candidate) %>

Doesn’t that need to be

canbackground_url(@candidate, @canbackground)

or

canbackground_url(@canbackground)

?

The url for a single background (which is what I understand that to be)
would need a background, surely.

A.

On 11/30/06, Alan F. [email protected] wrote:

or

canbackground_url(@canbackground)

?

The url for a single background (which is what I understand that to be)
would need a background, surely.

A.

Neither even comes close and throws an error loading the page.
It still needs to pass the candidate id,
However the link should be showing (in this instance)
candidates/12/canbackgrounds/28

Stuart

On 11/30/06, Dark A. [email protected] wrote:

A.

Neither even comes close and throws an error loading the page.
It still needs to pass the candidate id,
However the link should be showing (in this instance)
candidates/12/canbackgrounds/28

Stuart

Looking at AWDWR (latest)
GET/articles/1/comments/99show
comment_url(:article_id=>1,:id=>99)

Which I interpret for my resources as
<%= link_to ‘show’, canbackground_url(:candidate_id => @candidate, :id
=>
@canbackground) %>

Yet this takes me to ‘index’ and not ‘show’, Adding in :method => :get
adds
an error.

Stuart

Stuart Fellowes wrote:

Bump, sorry, can’t figure this out for a hill of beans.

Hi Stuart,

Sorry mate, I donb’t seem to be helping much.

From the peepcode RESTful episode cheatsheet:

ROUTE

map.resources :teams do |team|
team.resources :players
end

URLs (to get the nested bit)

plural

players_path(@team) => /teams/:team_id/players

singular

player_path(@team, @player) => /teams/:team_id/players/:player_id

These look like non-nested resources except that they have an additional
parameter at the front for the parent.

Some other questions, though.

1)You haven’t by any chance, got:

map.resources :canbackgrounds

and

map.resources :candidates | candidate|
candidate.resources :canbackgrounds
end

at the same time ?

  1. Are you on Edge Rails or the 1.2RC gem ?
  2. you do have the appropriate associations in the models ? ( candidate
    has_many canbackgrounds, canbackground belongs_to candidate )

If we dont get anywhere soon, feel free to mail me the whole project and
I’ll take a look and see if I can help. [gmail:alancfrancis]

Alan

On 11/30/06, Dark A. [email protected] wrote:

The url for a single background (which is what I understand that to

Yet this takes me to ‘index’ and not ‘show’, Adding in :method => :get
adds an error.

Stuart

Bump, sorry, can’t figure this out for a hill of beans.

Relevant routes:
map.resources :candidates do |candidate|
candidate.resources :canbackgrounds

Attempting to create a link for canbackgrounds/show.rhtml

Canbackgrounds.rb controller show action:
def show
@candidate_id = params[:candidate_id]
@canbackground = @candidate.canbackgrounds.find(params[:id])


end

Nothing I’m trying in the link seems to be working right -
Instead of posting all the crappy code that doesn’t work but I tried for
the
link ,
I’m thinking there should be a simple formula
A few that I’ve tried have taken me to ‘index’, but not show.

TIA
Stuart

On 12/1/06, Alan F. [email protected] wrote:

From the peepcode RESTful episode cheatsheet:
plural

players_path(@team) => /teams/:team_id/players

singular

player_path(@team, @player) => /teams/:team_id/players/:player_id

This takes me to the index page / action not the show action.

These look like non-nested resources except that they have an additional

parameter at the front for the parent.

Some other questions, though.

1)You haven’t by any chance, got:

map.resources :canbackgrounds

Nope

and

map.resources :candidates | candidate|
candidate.resources :canbackgrounds
end

at the same time ?

This is from my routes.rb
map.resources :candidates do |candidate|
candidate.resources :canpositions
candidate.resources :canbackgrounds
candidate.resources :canskills

  1. Are you on Edge Rails or the 1.2RC gem ?

Yes , Edge rails

  1. you do have the appropriate associations in the models ? ( candidate

has_many canbackgrounds, canbackground belongs_to candidate )

Yes

If we dont get anywhere soon, feel free to mail me the whole project and

I’ll take a look and see if I can help. [gmail:alancfrancis]

Alan

I went back to AWDWR and the example shows the nested resource ,
rendered
via a partial in the primary resource. That I can do.
In the Peepcode , code (which I have along with the podcast), sort of
confusing, in that the code shows for the nested resource
a seperate index and show page / view.
In the podcast though, he nixes the show and index actions in the
controller
using partials from the primary resource.
This might be my problem as I’m trying to call the nested resource
directly
from the primary one, either through show.rhtml or index.rhtml.

Stuart

Hi Stuart,

As far as using partials, you wouldn’t be using nested resources in
your routes to access them, because the code to load the Canbackground
data to use in the partial would either be invoked by the
Candidates::show action or in the RHTML file itself.

Out of curiousity, what is the relationship between candidates and
backgrounds? Can one candidate have multiple background records?

-Jared

On 12/1/06, Jared [email protected] wrote:

Hi Stuart,

As far as using partials, you wouldn’t be using nested resources in
your routes to access them, because the code to load the Canbackground
data to use in the partial would either be invoked by the
Candidates::show action or in the RHTML file itself.

Right, currently the Candidate::show action is rendering the partials
for
all the nested resources within Candidates. It uses, what
I believe is called the ‘conveinence method’ (:collection => @
candidate.nestedresource)

I think what your saying is find another method to invoke the
canbackground
record ?

Out of curiousity, what is the relationship between candidates and

backgrounds? Can one candidate have multiple background records?

From my models -
class Canbackground < ActiveRecord::Base
belongs_to :candidate

class Candidate < ActiveRecord::Base
has_many :canbackgrounds

But really in the long run, one candidate can have only one
canbackground.
I would check this probably via the user.id. However that is not
implemented as of yet.

-Jared

Stuart

Stuart Fellowes wrote:

On 12/1/06, Alan F. [email protected] wrote:

From the peepcode RESTful episode cheatsheet:
plural

players_path(@team) => /teams/:team_id/players

singular

player_path(@team, @player) => /teams/:team_id/players/:player_id

This takes me to the index page / action not the show action.

So are you saying that, in your app,

this

canbackground_path(@candidate, @canbackground)

actually generates

/candidates/x/canbackgrounds

and not

/candidates/x/canbackgrounds/y

?

or does it generate the correct url path, but when you click it it gets
routed to the wrong place ?

i.e. is the problem in the routes generated, or in the controler/action
mapping.

Alan

Stuart,

My first suggestion would be to alter your Candidate model to use a
has_one :canbackground association. Then you can easily call
@candidate.canbackground without needing a second ‘find’ call to load
the right record.

My advice would be to do away with the ‘find_candidate’ action in your
canbackgrounds_controller. The only places where you need to load the
candidate from the candidate_id are the ‘index’ and ‘new’ actions.

def index
@canbackground = Candidate.find(params[:candidate_id]).canbackground
end

def new
@canbackground =
Candidate.find(params[:candidate_id]).build_canbackground
end

The rest of your actions, such as ‘show’, can simply load the
canbackground by it’s ID.

def show
@canbackground = Canbackground.find(params[:id])
end

HOWEVER, all this is probably moot if you’re just using a 1 to 1
relationship between Candidates and Canbackgrounds. In that case, what
I would probably do is use the candidates_controller to create both the
candidate and the associated background in one view. There’s a useful
tutorial on the Rails Forum that discusses creating multiple models in
a single view. http://railsforum.com/viewtopic.php?id=717

You don’t even need new methods in your candidates_controller file, you
can use the standard 7 CRUD actions to perform all the necessary
operations on the canbackground object in the context of the candidate.

On 12/1/06, Alan F. [email protected] wrote:

actually generates

/candidates/x/canbackgrounds

Correct, and I’m not entirely sure that’s wrong. I believe , that show
/
get @candidate.canbackground would be the correct path.

and not

Alan


Posted via http://www.ruby-forum.com/.

On 12/1/06, Dark A. [email protected] wrote:

this
get @candidate.canbackground would be the correct path.
i.e. is the problem in the routes generated, or in the controler/action
mapping.

Alan

Latest news :slight_smile:
Found the secret sauce I think -
I’m still using primary resource
CandidateController
has_one :canbackground

In the candidate/show.rthml
I added - <%= link_to ‘Show’, canbackground_path(@candidate, @
candidate.canbackground)

This produces the correct url , canbackgrounds/show.rhtml now shows
correctly.

It was alot easier when all the partials rendered out of the
candidates/show.rthml

Stuart

On 12/1/06, Jared [email protected] wrote:

Stuart,

My first suggestion would be to alter your Candidate model to use a
has_one :canbackground association. Then you can easily call
@candidate.canbackground without needing a second ‘find’ call to load
the right record.

I must be losing it :), did the above suggest,
class Candidate < ActiveRecord::Base
has_one :canbackground
end

Added to candidates/show
<%= link_to ‘show’, canbackground_path(@candidate.canbackground) %>

So now, the link is backwards, in other words it’s got the id’s in the
wrong
place.
Should be (example) candidates/12/canbackgrounds/28
However it has candidates/28/canbackgrounds/12

HOWEVER, all this is probably moot if you’re just using a 1 to 1

relationship between Candidates and Canbackgrounds. In that case, what
I would probably do is use the candidates_controller to create both the
candidate and the associated background in one view. There’s a useful
tutorial on the Rails Forum that discusses creating multiple models in
a single view. http://railsforum.com/viewtopic.php?id=717

I do have them in the same view (or did)
Doing something like this:
<% unless @candidate.canbackgrounds.empty? %>
<%= render :partial => “/canbackgrounds/canbackground”, :collection =>
@
candidate.canbackgrounds %>
<% end %>

<% if @candidate.canbackgrounds.empty? %>
<%= link_to “Add background”, new_canbackground_url(@candidate) %>
<% end %>

Stuart

The Peepcode podcast is pretty good, plus it also covers things like
respond_to. I need to watch it more.
There are too minor errors though in the podcast. One, it showing
scaffold_resource using singular controller names,
and second error is the route.rb where it shows the primary resource in
the
do statement as plural. AWDWR shows it as singular and
I believe that’s correct.

Anyway, appreciate all the help guys!

Stuart

On 12/1/06, Jared [email protected] wrote:

Glad to hear that you’ve got it working! I’ve been wrestling with
these myself for the last month as well, so I know how frustrating it
can get when there’s one or two little pieces wrong derailing the whole
application.

-Jared

Stuart Fellowes wrote:

In the candidate/show.rthml
I added - <%= link_to ‘Show’, canbackground_path(@candidate, @
candidate.canbackground)

Wasn’t that what I suggested four posts ago ? :slight_smile:

Alan

Stuart Fellowes wrote:

Alan :wink: , but what made the difference was changing the association in
Candidates from has_many :canbackgrounds
to has_one :canbackground. I can’t say why that is so, but it made the
difference.

Fair point :slight_smile:

I’m not sure either, but it would sure be interesting to do a bit of
route spelunking and and find out

A,

Alan :wink: , but what made the difference was changing the association in
Candidates from has_many :canbackgrounds
to has_one :canbackground. I can’t say why that is so, but it made the
difference.

Stuart

On 12/2/06, Alan F. [email protected] wrote:


Posted via http://www.ruby-forum.com/.

hiya!

This produces the correct url , canbackgrounds/show.rhtml now shows
correctly.

It was alot easier when all the partials rend

ered out of the candidates/show.rthml

I have the same or at least a similar problem:

class Car
has_one :wheel
end

map.resources wheels
map.resources cars, :has_one => [ :wheel ]

Now if I try car_wheel_path(@car, @car.wheel) I get
undefined method `has_key?’ for #Wheel:0x48e3e20

car_wheel_path(@car) works but the url is wrong: /cars/1/wheel
and l get “Couldn’t find Wheel without an ID”

rake routes outputs:
------ POST /cars/:car_id/wheel {:controller=>“wheels”,
:action=>“create”}
------ POST /cars/:car_id/wheel.:format {:controller=>“wheels”,
:action=>“create”}
new_car_wheel GET /cars/:car_id/wheel/new {:controller=>“wheels”,
:action=>“new”}
formatted_new_car_wheel GET /cars/:car_id/wheel/new.:format
{:controller=>“wheels”, :action=>“new”}
edit_car_wheel GET /cars/:car_id/wheel/edit {:controller=>“wheels”,
:action=>“edit”}
formatted_edit_car_wheel GET /cars/:car_id/wheel/edit.:format
{:controller=>“wheels”, :action=>“edit”}
car_wheel GET /cars/:car_id/wheel {:controller=>“wheels”,
:action=>“show”}
formatted_car_wheel GET /cars/:car_id/wheel.:format
{:controller=>“wheels”, :action=>“show”}
------ PUT /cars/:car_id/wheel {:controller=>“wheels”,
:action=>“update”}
------ PUT /cars/:car_id/wheel.:format {:controller=>“wheels”,
:action=>“update”}
------ DELETE /cars/:car_id/wheel {:controller=>“wheels”,
:action=>“destroy”}
------ DELETE /cars/:car_id/wheel.:format {:controller=>“wheels”,
:action=>“destroy”}

Any ideas to solve this? How do I get the wheel_id for the wheels
controller? I’m really stuck :frowning:

thanks
bye Wolfgang