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