the problem I have is probably easy to solve, although I did a lot of search and cant find a solution.
I have in my _errors.html.erb
<% if obj.errors.any? %>
<div class="row">
<div class="col-md-8 col-md-offset-2 col-xs-12">
<div class="panel panel-danger">
<div class="panel-heading">
<h2 class="panel-title">
<%= pluralize(obj.errors.count, "error") %>
prohibided this form from being saved:
</h2>
<div class="panel-body">
<ul>
<% obj.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
</div>
</div>
</div>
<% end %>
Then I have in my edit.html.erb that has a form and:
<%= render 'layouts/errors', obj: #my_obj_here %>
Then in the controller update/create (lets use the update as example):
def update
if #my_obj_here.update(params[:my_obj_here].permit(:body))
redirect_to my_path_here_path(#my_obj_here), notice: "Something."
else
render 'edit'
end
end
The issue happens when I try to update and the submit info is invalid, which will fall into the "render 'edit'"
The errors show correctly (in this case max length 100) but my url changes from:
my_obj_here/1/edit to my_obj_here/1
which should not happen.
So next I tried replacing the "render 'edit'" with "redirect_to :back" but this just ignores the
<%= render 'layouts/errors', obj: #my_obj_here %> in the edit.html.erb.
Can someone help me out figuring out how to render the same my_obj_here/1/edit?
I believe I need to use the "render" my method because the redirect will just skip the errors partial.
Also, in my update method you probably noticed this "if true":
redirect_to my_path_here_path(#my_obj_here), notice: "Something."
I could the the same and just change my code to:
redirect_to :back, :notice => "something."
This would work, but does not show the errors as I want them to shown when my the errors partial is used.
The errors show correctly (in this case max length 100) but my url
changes from: my_obj_here/1/edit to my_obj_here/1 which should not
happen.
This is is a very common misconception. Rails uses RESTful conventions where the HTTP methods used are extremely important.
When you click an edit link it you're performing a GET request to my_obj_here/1/edit. This is an idempotent action - the result is always the same and it does not alter any resource. In fact the new and edit actions in Rails don't do anything but display forms.
When you submit the form your sending a PATCH request to my_obj_here/1. This is a non-idempotent request as it alters the resource. When the validation fails and you render you're actually displaying the result of an attempt to update a resource. This is fundamentally different than the GET request to my_obj_here/1/edit - it's not cacheable and cannot be revisited.
http://guides.rubyonrails.org/routing.html#resource-routing-the-rails-default
Related
I am learning Ruby On Rails.I'd like to understand how RoR works. I have the following url when i want to edit user informations:
http://localhost:3000/users/3/edit
Here is my controller :
# GET /users/1/edit
def edit
end
The form is :
<div class="ui middle aligned center aligned grid">
<div class="column">
<h1>Profil</h1>
<div class="ui form segment">
<%= render "form" %>
</div>
</div>
</div>
<%= link_to 'Show', #user %> |
<%= link_to 'Back', users_path %>
I understand that the form is print by the code <%= render "form" %>. I'd like to know how to see what contains form ? Which informations are available in form ?
In your case
<%= render "form" %>
renders partial. You should find file with name _form.html.erb
or read more about partials in GUIDE
The render method is used to load a partial. A partial is basically repeated fragment of code in a view. To keep things dry, you separate it out in a partial and then pass it to the render method to render it.
In your case, the form is a partial.
You will most probably find it at app/views/users/_form.html.erb
Partials are always prefixed with a _ in their filename.
I have a User model, and each user has_many: Deliveries. I have a partial called _currentDeliveries, that shows a user some information about each of their Deliveries.
Each Delivery that is shown has a delete button next to it (which is just a little square div for now), and I'm using Ajax so if a user clicks the delete button next to one of their Deliveries, that delivery will be destroyed removed from the list (by re-rendering the partial) without refreshing the page.
I have it almost working the way I want, the only problem is when I click the delete button for one Delivery, it is not removed from the list until I click the delete button of another delivery. And, the second delivery I delete is not removed from the list until I click a third delete button, and so on.
Basically, the partial is always one move behind where it should be, which makes me think the partial is being rendered before the Delivery is completely Deleted.
Here is the div that contains the partial:
<div id="currentDeliveriesArea">
<%= render "currentDeliveries", user: #user %>
</div>
Here is the partial:
<% user.deliveries.each do |d| %>
<div class="deliveryBox">
<div class="deliveryBoxLeft">
<div class="editDeliveryButton">
</div>
</div>
<div class="deliveryBoxCenter">
<p class="deliveryTitleText">Delivery</p>
<p class="deliveryTimeText">
<% if d.minute > 9 %>
<% if d.am == 1 %>
<%= d.hour %>:<%= d.minute %> am
<% else %>
<%= d.hour %>:<%= d.minute %> pm
<%end%>
<% else %>
<% if d.am == 1 %>
<%= d.hour %>:0<%= d.minute %> am
<% else %>
<%= d.hour %>:0<%= d.minute %> pm
<%end%>
<%end%>
</p>
</div>
<div class="deliveryBoxRight">
<div class="deleteDeliveryButton" onclick="getDeleteDelivery(<%= d.id %>);">
</div>
</div>
</div>
Here is the javascript function that is called when div "deleteDeliveryButton" is clicked:
function getDeleteDelivery(delivery){
$.get("/deleteDelivery", {delivery: delivery})}
Here is the deleteDelivery action in the users_controller:
def deleteDelivery
#user = current_user
puts "made it to delete action"
#user.deliveries.each do |d|
puts "Delivery ID " + d.id.to_s
end
#delivery = params[:delivery]
puts "User deliveries count before: " + #user.deliveries.count.to_s
Delivery.find(#delivery).destroy
puts "User deliveries count after: " + #user.deliveries.count.to_s
respond_to do |format|
format.js
end
end
Here is the deleteDelivery.js.erb file that gets called from the action and re-renders the partial:
$("#currentDeliveriesArea").html("<%= j(render partial: 'currentDeliveries', locals: {user: #user}) %>");
If I refresh the page after every delete button click, deliveries are removed from the list each time, but for some reason the Ajax seems to lag 1 click behind. The console says that the delivery is deleted completely, and #user.deliveries.count is one less, before it says the _currentDeliveries is rendered and then deleteDelivery.js.erb is rendered, so I'm not really sure what is going on.
Sorry about the bad naming conventions btw!
I am using the following code in my layout to display two types of flash messages:
<% if !flash[:notice].nil? %>
<div class="row">
<div class="flash notice col-xs-12">
<%= flash[:notice] %>
</div>
</div>
<% end %>
<% if !flash[:error].nil? %>
<div class="row">
<div class="flash error col-xs-12">
<%= flash[:error] %>
</div>
</div>
<% end %>
<%= debug(flash[:notice]) %>
<%= debug(flash[:error]) %>
They both work fine, but whenever one is triggered, it will still appear for one additional page view. I'm not using any caching gems.
Why is this happening? And how do I fix it?
Use flash.now instead of flash.
The flash variable is intended to be used before a redirect, and it persists on the resulting page for one request. This means that if we do not redirect, and instead simply render a page, the flash message will persist for two requests: it appears on the rendered page but is still waiting for a redirect (i.e., a second request), and thus the message will appear again if you click a link.
To avoid this weird behavior, when rendering rather than redirecting we use flash.now instead of flash.
The flash.now object is used for displaying flash messages on a rendered page. As per my assumption, if you ever find a random flash message where you do not expect it, you can resolve it by replacing flash with flash.now.
New to AJAX and search. I feel like I'm an inch away on this one, but I'm not sure what to fix. Also, my controller looks really hacky to me right now.
At any rate, I'm trying to create a search that allows users to search through blog posts on my page using AJAX. Here are the (relevant parts of the) parts:
posts_controller.rb
def show
#posts = Post.all.reverse
#post = Post.find(params[:id])
#link_num = 10
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to #post }
end
end
def search
#link_num = 10
#posts = Post.all.reverse
#post = Post.find(params[:id])
#The including function returns the search results
#search = Post.first.including(params[:term])
render 'show'
end
What strikes me as "hacky" here is that I repeat all the variable assignments (there are others I didn't show cause they're not relevant). Shouldn't an AJAX call ideally not have to redefine/reload all these variables? Also, I have to pass :id to my search action through a hidden field. This feels weird/wrong to me.
show.html.erb
<h1 class="squeeze">Recent Posts</h1>
<%= form_tag("/search", method: "get", class: "search") do %>
<%= text_field_tag(:term, '', placeholder: "Search posts:") %>
<%= hidden_field_tag(:id, #post.id) %>
<%= submit_tag("Search", class: "btn search_button", remote: true) %>
<% end %>
<% if !#search%>
<ul>
<% #posts.first(#link_num).each do |p| %>
<li>(<%= p.created_at.strftime("%b %d, %Y") %>)</span></li>
<% end %>
<% if #posts.length > #link_num %>
<div class="link_disclaimer">
<h4>---</h4>
<h5><%= "Only showing #{#link_num} most recent posts." %></h5>
<h5>Search to narrow results.</h5>
</div>
<% end %>
</ul>
<% elsif #search.empty? %>
<h3>Term not found!</h3>
<% else %>
<ul>
<% #search.first(#link_num).each do |p| %>
<li>(<%= p.created_at.strftime("%b %d, %Y") %>)</span></li>
<% end %>
<% if #search.length > #link_num %>
<div class="link_disclaimer">
<h4>---</h4>
<h5><%= "Only showing first #{#link_num} relevant hits." %></h5>
<h5>Narrow search for more specific results.</h5>
</div>
<% end %>
</ul>
<% end %>
routes.rb
match '/search', to: 'posts#search'
Currently, the search itself works fine, with three major problems:
The aforementioned messiness of my Controller.
The fact that the whole page reloads. Isn't that the opposite of what AJAX is supposed to do? How can I get it to reload just the list of links?
The URL. It's super messy (i.e "/search?utf8=✓&term=limits&id=11&commit=Search"). I'd ideally have it remain untouched by the search, but if that's not possible, maybe just something like "/search?=". How's that done?
Based on the comment here is basic logic to make the function work(Sorry for no real code as that is too time consuming)
In controller you make a method say "search". The method need an argument which is the phrase to search. It gets the result from db and respond to JSON only with the result.
In template you have a search form.
In JS, you listen the event of user clicking the submit button, catch the characters they write, and handle it to ajax function.
Write Ajax code, preferred using jQuery's ajax(). Basically use ajax() to send the typed characters to controller method in #1 as argument. Then ajax() will get the response(the search result) from server.
Update the result in DOM. You can either add a new div to show search result, or replace current main content div to show result.
Alright, I've got to be missing something simple.
I'm using a partial "/shared/_error_messages.html.erb" to handle
<%= render 'shared/error_messages', object: f.object %>
in my forms (one for adding programs, one for adding metrics).
When I navigate to any form (/programs/new and metrics/new), the validation appears when the page loads.
The programs_controller and metrics_controller are structurally the same (swapping #metrics for #programs in metrics_controller):
#programs_controller.rb
def new
#programs = Program.new(params[:name])
if #programs.save
flash[:success] = "Program saved"
redirect_to "/program"
else
render 'new'
end
end
any ideas what might be causing this?
Here's the partial:
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I don't know what the errors are but the problem is that your are saving your object in the new action. The saving generates the object errors; that is why you see them.
In a RESTful way, the new action should just instantiate a model and pass the object to your form. The form will submit it to the create action; where you should save your object and check errors.
Something like:
#programs_controller.rb
def new
#programs = Program.new
end
def create
#programs = Program.new(params[:program])
if #programs.save
# success
else
# failure
end
end