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:

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

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

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

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

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?

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,

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&gt;

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.

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

Stuart Fellowes 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

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

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

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

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

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

hiya!

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 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