4

Rails project: Project has many Ticket's.

Path to editing a ticket: /projects/12/tickets/11/edit

When updating a Ticket and validation fails, I use render :action => "edit".

However, when the edit view renders this time, the path changes to /tickets/11/

Which means I lose some parameters. How can I keep the original path?

routes.rb:

  resources :projects do
    resources :tickets
  end
  resources :tickets

tickets_controller.rb

  def new
    @ticket = Ticket.new
  end

  def create
    @ticket = Ticket.new(params[:ticket])
    @ticket.user_id = session[:user_id]

    respond_to do |format|
      if @ticket.save
        format.html { redirect_to project_path(@ticket.project), :notice => "Ticket was created." }
      else
        format.html { render :action => "new" }
      end
    end
  end

  def edit
    @ticket = Ticket.find(params[:id])
  end

  def update
    @ticket = Ticket.find(params[:id])
    respond_to do |format|
      if @ticket.update_attributes(params[:ticket])
        format.html { redirect_to project_ticket_path(@ticket.project, @ticket), :notice => "Ticket was updated." }
      else
        format.html { render :action => "edit" }
      end
    end
  end
user1121487
  • 2,662
  • 8
  • 42
  • 63

2 Answers2

1

you are calling resources twice. if you don't want to "lose some parameters", remove the second one.

resources :projects do
  resources :tickets
end

However, if you want to have resources :tickets non nested as well, you can restrict it to only show and index to avoid losing some parameters when creating and editing.

resources :projects do
  resources :tickets
end
resources :tickets, :only => [:index, :show]

edit - I believe the problem is in your form than.
Make sure you have both objects:

form_for([@project, @ticket]) do |f| 

Also, you must find the project before creating or updating the ticket. So your new and edit actions must have something like:

@project = Project.find(params[:project_id])
@ticket = @project.ticket.build

and the same for create action:

@project = Project.find(params[:project_id])
@ticket = @project.ticket.build(params[:ticket])

edit2 - your update action should be something like:

@project = Project.find(params[:project_id])
@ticket = Ticket.find(params[:id])
if @ticket.update_attributes(params[:ticket])
...
gabrielhilal
  • 10,660
  • 6
  • 54
  • 81
  • I've tried that, but this gives me error page when trying to update a ticket: No route matches [PUT] "/tickets/10" – user1121487 Feb 11 '13 at 12:38
  • Ok, I've added :url => { :action => "update" } in my form_for, in the view. Now it works. However I used the form as a partial view, for create as well. Guess that can't be done? – user1121487 Feb 11 '13 at 12:43
  • I have edited the answer, you can use the same form for both (edit and update). – gabrielhilal Feb 11 '13 at 12:47
  • Excellent, this seem to work fine. I just changed a little bit: form_for [@ticket.project, @ticket] do |f| – user1121487 Feb 11 '13 at 12:52
  • Hmm, now it does not seem to work when you try to update the first time and there's error, the "/edit" in the path is cut off. The second time you try to update the "/project/12/" is cut off as well. – user1121487 Feb 11 '13 at 13:11
  • you must always find the project before dealing with the ticket. The `form_for([@project, @ticket])` in your form will ensure the full url, however you must check that your controller is correct. You can include the tickets_controller in your question, so we can find the problem for you. – gabrielhilal Feb 11 '13 at 13:20
  • I've tried your code in my controller, but didn't work for me... I've updated the question. I'm collecting the project_id through a hidden_field so I can map it directly to the object. – user1121487 Feb 11 '13 at 13:40
  • I solved it by specifying the action in the form_for with a variable so I could use the view as partial. :url => { :action => @the_action }. Don't know if it's the best solution, but is works as it should. – user1121487 Feb 11 '13 at 15:27
1

Take a look at http://guides.rubyonrails.org/routing.html#nested-resources . You should be able to redirect to the nested resource from your controller using nested route helpers, such as project_ticket_path(@project, @ticket).

tmaximini
  • 8,403
  • 6
  • 47
  • 69