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
You should use request. original_url to get the current URL. Source code on current repo found here.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With