5

In the update action of my preferences controller in my Rails app, if there are any errors in the validation/save etc there's a call to:

format.html { render :edit }

Nothing too unusual there - however, when this code is hit, the address in the browser changes and loses the /edit in the URL.

For example:

To start with, my browser shows I am on the page at following address: http://localhost:3000/preferences/1/edit

However, once the errors are detected and the render is called the address in the is changed to http://localhost:3000/preferences/1

I can't say I've ever noticed this behaviour before - but Is there a way to force the /edit to stay on the end of the URL? Without the /edit it is effectively showing the URL of the show page (and I don't have a template for that!)

Many thanks, Ash

Ash
  • 2,330
  • 2
  • 18
  • 23

2 Answers2

6

Instead of calling render, you can redirect_to the edit page, and use flash to keep track of the model:

def update
  # ...
  if !@model.save # there was an error!
    flash[:model] = @model
    redirect_to :action => :edit
  end
end

And then in the edit action you can reload the values from flash[:model], ie:

def edit
  if flash[:model]
    @model = flash[:model]
  else
    @model = ... # load model normally
  end
end

Update:

As commented below, I think when I wrote this answer I was trying to provide a way to both update the URL (which requires a redirection) and keep the changed attributes of the model, which is why the model was stored in flash. However, it's a pretty bad idea to stick a model into flash (and in later versions of Rails it'll just get deserialized anyways), and RESTful routes don't really require making the URL contain edit.

The usual pattern would be to just render the edit action with the model already in memory, and forego having the "ideal" URL:

def update
  # Assign attributes to the model from form params
  if @model.save
    redirect_to action: :index
  else
    render :edit
  end
end

Alternately, if it's preferable to have the "ideal" URL and you don't care about maintaining changed attributes that failed validation, see @jamesmarkcook's answer.

Daniel Vandersluis
  • 91,582
  • 23
  • 169
  • 153
  • Fantastic! Thanks! I'd been trying to use redirect_to but was losing the flash messages! – Ash Jul 28 '10 at 08:42
  • This seems like odd behavior. Why does Rails strip off the /edit? – Joel Brewer Oct 14 '14 at 02:32
  • if you are using respond_to format use format.html { redirect_to :action => :edit } – jrich Dec 22 '14 at 19:21
  • It seems very messy to be passing the model around in the flash here. Why would you need to when the model should automatically be reloaded if you're redirecting to the correct edit path? See the solution below. – James Jan 05 '17 at 20:45
  • @jamesmarkcook you're right, this is very messy, I would not recommend doing this anymore. I think the intention was to have a way to both redirect and keep changes made to the model, which would be lost if you just reloaded the model. It would be better to just forget about making the URL contain `edit` and just render the form rather than redirecting. – Daniel Vandersluis Jan 08 '17 at 07:12
  • 2
    when you use `render :edit` (or `render :new` in a create action) and the user hits reload, you will get the show page in the first instance and a routing error in the second. – Michael Johnston May 26 '17 at 02:01
0

Simply redirect to the edit path and pass the model in to the rails path helper like so:

def update
  if @model.update_attributes(updated_params)
    // Success
  else
    redirect_to edit_model_path(@model), flash: { error: "Could not update model" }
  end
end

This will preserve your flash, redirect you to the correct path and reload your model.

James
  • 608
  • 6
  • 11
  • 3
    It will also lose all the user's edits, making for a very unfriendly UX. – Michael Johnston May 26 '17 at 02:01
  • its sad you cant have both, the changes and the same url, thats bad for the UX too. Whenever a user has errors and refreshes the page by hand in the browser, he is not longer editing but in the show action, which is ... sad. – silva96 Aug 27 '20 at 19:57