Redirect and passing params?

I have two forms that people need to fill out, an Incident form and a Timesheet form. I want the Timesheet form to appear right after a user submits the Incident form.

This is my code for the Incident controller;

Finne Jager wrote in post #968107:

I have two forms that people need to fill out, an Incident form and a Timesheet form. I want the Timesheet form to appear right after a user submits the Incident form.

This is my code for the Incident controller; --------------------------------------------------- if @incident.save   format.html { redirect_to new_timesheet_path(@incident.id) } ---------------------------------------------------

Bizarre. new_*_path doesn't normally take an argument (except for an optional format string, which is why you're getting the .16 below).

After clicking submit, that takes me to this URL (a blank page): http://localhost:3000/timesheets/new.16

What does your routes file look like, or the output from rake routes?

What do I put in the Timesheets controller to make the new Timesheet form appear, and have it connected to the Incident that was just submitted?

Do you have any associations set up between the Timesheet and Incident models?

(Both Incident and Timesheet are top level resources.)

Perhaps they shouldn't be in this case.

Thanks!

Best,

Marnen Laibow-Koser wrote in post #968112:

Bizarre. new_*_path doesn't normally take an argument (except for an optional format string, which is why you're getting the .16 below).

Is there another way to pass the incident object to the New Timesheet method? The new Timesheet needs to know it's supposed to be attached to the Incident.

What does your routes file look like, or the output from rake routes?

resources :incidents resources :timesheets

Do you have any associations set up between the Timesheet and Incident models?

The Incident model has_one :timesheet

(Both Incident and Timesheet are top level resources.) Perhaps they shouldn't be in this case.

How can I nest them?

Finne Jager wrote in post #968117:

Marnen Laibow-Koser wrote in post #968112:

Bizarre. new_*_path doesn't normally take an argument (except for an optional format string, which is why you're getting the .16 below).

Is there another way to pass the incident object to the New Timesheet method?

new_timesheet_path goes to TimesheetsController#new , not Timesheet.new .

The new Timesheet needs to know it's supposed to be attached to

the Incident.

What does your routes file look like, or the output from rake routes?

resources :incidents resources :timesheets

Do you have any associations set up between the Timesheet and Incident models?

The Incident model has_one :timesheet

And Timesheet belongs_to :incident , I hope?

(Both Incident and Timesheet are top level resources.) Perhaps they shouldn't be in this case.

How can I nest them?

See the routing documentation. Once you *do* nest them, you get the routes you need for free.

If you don't want to nest them, other solutions are possible, but I'd advise nesting if it's feasible for your project.

Best,

Thank you, I appreciate your help so far, I feel like we're getting there!

And Timesheet belongs_to :incident , I hope?

Correct.

See the routing documentation. Once you *do* nest them, you get the routes you need for free.

If you don't want to nest them, other solutions are possible, but I'd advise nesting if it's feasible for your project.

Ok, I have nested them like this:

Finne Jager wrote in post #968122:

Thank you, I appreciate your help so far, I've been struggling with this for days now.

And Timesheet belongs_to :incident , I hope?

Correct.

See the routing documentation. Once you *do* nest them, you get the routes you need for free.

If you don't want to nest them, other solutions are possible, but I'd advise nesting if it's feasible for your project.

Ok, I have nested them like this: ---------------------------- resources :incidents do resources :timesheets end ----------------------------

And I changed Incidents#create to this: ---------------------------- if @incident.save format.html { redirect_to incident_timesheet_url(@incident) } ----------------------------

Is that the 'free route' you mentioned?

It's one of them, yes.

On a side note, by changing the resources to nested instead of top level, it broke my Index page which shows a list of Incidents and their Timesheets. It pointed out this line of code:

---------------------------- <td><%= link_to 'View Time Sheet', timesheet_path(incident) %></td> ----------------------------

Right, of course. Run rake routes to see what your routes look like now.

Best,

Finne Jager wrote in post #968122:

Thank you, I appreciate your help so far, I've been struggling with this for days now.

And Timesheet belongs_to :incident , I hope?

Correct.

See the routing documentation. Once you *do* nest them, you get the routes you need for free.

If you don't want to nest them, other solutions are possible, but I'd advise nesting if it's feasible for your project.

Ok, I have nested them like this: ---------------------------- resources :incidents do resources :timesheets end ----------------------------

Something else I just realized. Since Incident :has_one Timesheet, you probably want a singular resource -- resource :timesheet instead of resources :timesheets . Again, please check the docs rather than taking my word for it.

Best,

On a side note, by changing the resources to nested instead of top level, it broke my Index page which shows a list of Incidents and their Timesheets. It pointed out this line of code:

---------------------------- <td><%= link_to 'View Time Sheet', timesheet_path(incident) %></td> ----------------------------

Right, of course. Run rake routes to see what your routes look like now.

Ok, I ran 'rake routes' and it showed:

Finne Jager wrote in post #968131:

On a side note, by changing the resources to nested instead of top level, it broke my Index page which shows a list of Incidents and their Timesheets. It pointed out this line of code:

---------------------------- <td><%= link_to 'View Time Sheet', timesheet_path(incident) %></td> ----------------------------

Right, of course. Run rake routes to see what your routes look like now.

Ok, I ran 'rake routes' and it showed: -------------------------------- incident_timesheet GET /incidents/:incident_id/timesheet(.:format)    {:action=>"show", :controller=>"timesheets"} ----------------------------------

So I changed the code in my Index view to: --------------------------------- <td><%= link_to 'View Time Sheet', incident_timesheet %></td> ---------------------------------

That triggers: undefined local variable or method `incident_timesheet'

Of course. You forgot the _path.

Please go read the routing docs again, paying particular attention to the autogenerated helpers.

Best,

On a side note, by changing the resources to nested instead of top level, it broke my Index page which shows a list of Incidents and their Timesheets. It pointed out this line of code:

---------------------------- <td><%= link_to 'View Time Sheet', timesheet_path(incident) %></td> ----------------------------

Right, of course. Run rake routes to see what your routes look like now.

Ok, I ran 'rake routes' and it showed: -------------------------------- incident_timesheet POST /incidents/:incident_id/timesheet(.:format) { :action=>"create", :controller=>"timesheets"} ----------------------------------

So I changed the code in my Index view to: --------------------------------- <td><%= link_to 'View Time Sheet', incident_timesheet %></td> ---------------------------------

That triggers: undefined local variable or method `incident_timesheet'

--

OK, you're really close. However, think about that route. It needs want to do incident_timesheet_path(incident)

-Rob

Rob Biedenharn Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/ rab@GaslightSoftware.com http://GaslightSoftware.com/

OK, you're really close. However, think about that route. It needs an :incident_id and you haven't given one. For the create, you'll want to do incident_timesheet_path(incident)

Thank you, I realized that as well and put the (incident) parameter: <td><%= link_to 'View Time Sheet', incident_timesheet_path(incident) %></td>

When I click on the View Timesheet link in the Index, I get:

Finne Jager wrote in post #968154:

OK, you're really close. However, think about that route. It needs an :incident_id and you haven't given one. For the create, you'll want to do incident_timesheet_path(incident)

Thank you, I realized that as well and put the (incident) parameter: <td><%= link_to 'View Time Sheet', incident_timesheet_path(incident) %></td>

When I click on the View Timesheet link in the Index, I get: ---- undefined method `edit_timesheet_path' ----

Which has to do with this line in timesheets/show.html.erb: <%= link_to 'Edit', edit_timesheet_path %>

Am I referencing this edit path correctly?

Instead of asking us, look at your rake routes output again! That's why it's there.

As per your advice I will go ahead and read the whole Routing documentation from front to back again because I think this will keep coming up as I adjust the rest of the code I already had.

Best,

Instead of asking us, look at your rake routes output again! That's why it's there.

Thanks, I just did and realized what I had to change.

With these nested resources in place, do I still have to set @timesheet in TimesheetsController#show?

This is what I had before:

Finne Jager wrote in post #968340:

Instead of asking us, look at your rake routes output again! That's why it's there.

Thanks, I just did and realized what I had to change.

With these nested resources in place, do I still have to set @timesheet in TimesheetsController#show?

Of course. Changing routes.rb only changes the routing, nothing else.

You may want to use a plugin such as make_resourceful to abstract some of this.

This is what I had before: ------------------------- def show @timesheet = current_user.timesheets.find(params[:id]) -------------------------

Why the current_user part? Just Timesheet.find(params[:id]) should do the trick -- after all, the ID is unique.

The reason I'm asking is because in timehsheets/show.html.erb I have: ------------------------- <p>   <b>Date:</b>   <%= timesheet.date %> </p> ------------------------- which is not working (undefined local variable or method `timesheet'). I just want to retrieve the value for 'date' in the database timesheet table..

Of course that's not working. You haven't defined timesheet anywhere.

Best,

Why the current_user part? Just Timesheet.find(params[:id]) should do the trick -- after all, the ID is unique.

I read in Beginning Rails 3 that current_user makes sure that the logged in user can not see other people's incidents/timesheets. I have the same thing in the IncidentsController:

All the link does is build a URL for you with appropriate params. In the controller action you then have to do things with the params. Have a look in log/development.log and you will see what params are being passed. Also I suggest having a look at the Rails Guide on debugging. You can then use ruby-debug to break into your code before the find call you have shown and inspect params to see what is there and work out why the find is not working. You can also experiment then calling find from the console to see what works.

Colin

Finne Jager wrote in post #968357:

Why the current_user part? Just Timesheet.find(params[:id]) should do the trick -- after all, the ID is unique.

I read in Beginning Rails 3 that current_user makes sure that the logged in user can not see other people's incidents/timesheets.

True enough, though I'd probably use an authorization plugin for that.

I have the same

thing in the IncidentsController: ------------------------------ def index     @incidents = current_user.incidents.all -------------------------------

But now that Timesheets are nested within Incidents, I don't have to have current_user for that I guess.

Of course that's not working. You haven't defined timesheet anywhere.

@timesheet = Timesheet.find(params[:id])

Seems to be not working...

No, I'm sure it's working fine. But you're defining @timesheet in your controller, then calling timesheet (without the @) in the view.

Does it even need to find by ID if I'm already using the incident_timesheet_path(incident) link?

Yes. That only passes the ID. HTTP has no means of passing ActiveRecord objects around.

Best,

All the link does is build a URL for you with appropriate params. In the controller action you then have to do things with the params. Have a look in log/development.log and you will see what params are being passed. Also I suggest having a look at the Rails Guide on debugging. You can then use ruby-debug to break into your code before the find call you have shown and inspect params to see what is there and work out why the find is not working. You can also experiment then calling find from the console to see what works.

I didn't think of checking the log, very useful tip! I need to use the incident_id that's being passed to find the timesheet.

I tried: @timesheet = Incident.find(params[:id]).timesheet

"Couldn't find Incident without an ID".

I checked by hardcoding it: @timesheet = Incident.find(1).timesheet

That did work, so it must be params[:id] that's not working. The log says that incident_id is being passed as a param though.

Started GET "/incidents/1/timesheet" for 127.0.0.1 at 2010-12-14 12:33:48 -0500   Processing by TimesheetsController#show as HTML   Parameters: {"incident_id"=>"1"}

No, I'm sure it's working fine. But you're defining @timesheet in your controller, then calling timesheet (without the @) in the view.

Got it, I changed it back to @timesheet.

Does it even need to find by ID if I'm already using the incident_timesheet_path(incident) link?

Yes. That only passes the ID. HTTP has no means of passing ActiveRecord objects around.

Ok, thanks for the development log tip! I wasn't aware of it. I now use the incident_id to set @timesheet like this: @timesheet = Incident.find(params[:incident_id]).timesheet

And it looks like it's working!

Great. Do have a go with ruby-debug too. You should not need it often but sometimes when you just cannot understand what is going on then it is invaluable.

Colin