Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is "render 'new' " changing my URL? (Ruby On Rails)

I have a view called new.html.erb for clients at localhost:3000/clients/new. I validate it for errors. If there's an error I render the new view again to show all the errors. The problem is that it is showing as localhost:3000/clients in my browser instead of localhost:3000/clients/new. Why is that? Isn't "render" supposed to not change anything from the URL? This gives problems when I refresh the page because I have no "index" view and it's triggering an error instead of showing the "new" view as it's supposed to.

new.html.erb

<% if @client.errors.any? %>
    <div class="alert alert-danger">
        <h4 class="alert-heading">Error</h4>
            <% @client.errors.full_messages.each do |msg| %>
                <p><%= msg %></p>
            <% end %>
     </div>
<% end %>

<%= form_for @client, url: clients_path, remote: false do |f| %>
    <div class="form-group  row"><label class="col-sm-2 col-form-label">*Name</label>
        <div class="col-sm-3">
            <%= f.text_field :name, class:"form-control" %>
                <% if @client.errors[:name].any? %>
                    <script>$('#client_name').css('border-color', 'red');</script>
                <% end %>
         </div>
</div>

<div class="col-sm-4 col-sm-offset-2">
    <%= f.submit "Submit", id:"submit", class: 'btn btn-primary btn-sm'%>
    <%= link_to "Cancel", controller:"mainpages", action:"index", :html=>{:class=> "btn btn-primary btn-sm"}%>
</div>
<% end %>

clients_controller.rb

def new
    @client = Client.new
  end

  def create
    @client = Client.new(client_params)

      if @client.save 
        return redirect_to :root
      end
      render 'new'
  end

routes.rb

  root to: "mainpages#index"

  get '/mainpages', controller: 'mainpages', action: 'index'
  get '/planes', controller: 'planes', action: 'planes'

  resources :clients
  resources :planes

client.rb

class Client < ApplicationRecord
    validates :name, presence: true
end
like image 548
FlowMafia Avatar asked Sep 21 '19 19:09

FlowMafia


People also ask

How do I get the current URL in Ruby on Rails?

You should use request. original_url to get the current URL. Source code on current repo found here.

What is the difference between render and redirect in Rails?

Render tells Rails which view or asset to show a user, without losing access to any variables defined in the controller action. Redirect is different. The redirect_to method tells your browser to send a request to another URL.

What does render do in Rails?

Rendering allows you to return content to the users of your application & it's one of the final steps inside your controller actions. Understanding rendering helps you write better Rails applications.

What is render partial in Ruby?

Ruby on Rails Views Partials Partial templates (partials) are a way of breaking the rendering process into more manageable chunks. Partials allow you to extract pieces of code from your templates to separate files and also reuse them throughout your templates.


1 Answers

Your expectation is completely wrong but quite common among Rails beginners.

In Rails flavor REST GET /clients/new is just a page that contains the form for creating a new resource. Since its a GET request it is idempotent - that means its stateless and looks the same for all visitors.

When you submit the form your browser is sending a POST request to /clients. Again in Rails flavored REST this is how you create a resource.

If the validation fails rails simply renders a response containing the form. This SHOULD NOT redirect the user as what you are seeing is the result of the non-idempotent POST request. This is not the same resource as GET /clients/new.

In fact render 'new' is just a shortcut to render 'app/views/clients/new.html.erb'. The two endpoints share a view - nothing else.

Why is that? Isn't "render" supposed to not change anything from the URL?

You are completely mistaken. render does not change the URL. Submitting the form earlier changed the URL in the browser. Render just renders the view and returns it as the body of the response. Look at the logs of your Rails app if you want to get an idea of how the interchange between client and server actually works.

You can contrast this with redirect_to which sends a location header back and the correct response code (302) which will redirect the browser to the new location.

This gives problems when I refresh the page because I have no "index" view and it's triggering an error instead of showing the "new" view as it's supposed to.

To resolve this you need to add an index action which can be a simple redirect to /clients/new. When you reload the page you are sending a GET request to /clients which should render the index.

I would really recommend that you try just creating a scaffolded rails app so that you get an idea of how the rails conventions do simple CRUD operations before you start imposing your own ideas.

like image 160
max Avatar answered Nov 14 '22 11:11

max