I am currently trying to optimize rendering a page in ruby on rails.
I have a question, is there a way to make a page, only render another page when a link (href) associated to it is clicked.
some codes in index.html.erb:
.....
.....
<h4>
<%= item.name %>
<br/>Details
</h4>
<div id="<%=item.id%>_item_modal" class="modal fullscreen">
<div class="item-modal">
<%=render item%>
</div>
</div>
.....
.....
In code above, I am using modal. So that when the link is clicked, _item.html.erb will be shown appear in a smaller page. Similar like a popup.
When index.html.erb is loaded, then all codes inside _item.html.erb will also be loaded automatically and all queries inside will be executed because of
<%render item%>
code.
What I want is, I don't want index.html.erb also render all item inside _item.html.erb page unless I click "Details" button.
<br/>Details
I think by doing this think, I can save some amount of time when a user requests for item page, because the system doesn't need to retrieve all information which are not yet required.
Could you guys help me?
Please let me know if you need another information.
You have to use ajax in order to achieve this. You can create a hidden div with a specific id, say "modal".
Revert your h4 to this:
<h4>
<%= item.name %>
<br/>
= link_to 'Details', item_path(item), data: {remote: true}, item_details: true
</h4>
Then in your item controller, on the show action:
def show
# load the item
if params[:item_details]
respond_to {|format| format.js}
else
# do what you already do here
end
end
And in your item views folder, create a file show.js(.coffee):
$('#modal').html('<%= j(render partial: "item", object: #item) %>');
$('#modal').modal('show');
This is just the idea, you have to make it compatible with your code.
If you want to go the ajax route:
<h4>
<%= item.name %>
<br/>
<%= link_to "Details", item_path(item), remote: true %>
</h4>
Then in your items_controller:
def show
...
respond_to do |format|
format.js
end
end
Then create the view "views/items/show.js"
$(body).append(<%= escape_javascript(render partial: "items/item_modal") %>);
...code to show modal...
...hook to remove modal when it is dismissed...
And the view "views/items/_item_modal.html.erb"
<div id="<%=item.id%>_item_modal" class="modal fullscreen">
<div class="item-modal">
<%=render item%>
</div>
</div>
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'm trying to open a modal that displays a list of items. The list of items is already available in the view as a variable. How do I pass this variable to the modal?
Below is roughly how the main view looks like:
View.html.erb
<div>
<%= #users.each do |user|%>
<h1>user.name</h1>
<h2>user.email</h2>
<%= link_to remote: true, 'data-toggle' => 'modal', 'data-target' => '#taskModal do %>
<i><%= user.tasks.count%></i>
<% end %>
<% end %>
</div>
<div class="modal" id="taskModal" aria-hidden="true">
...
<%= render partial: 'list_modal' %>
list_modal is a partial with the structure of the modal.
As opposed to having the list of items already on the view, and wanting to pass it to the modal, One thing you can do is make the button ( or link ) for opening the modal to call a controller action by ajax, and then let the action respond to JS, where you will now use the corresponding view.js file to both populate the modal as well as programmatically render it ( after populating it ).
Example:
Link to open modal:
<%= link_to "Open users list", users_open_list_modal_path, remote: true %>
Users open list modal controller action:
def open_list_modal
#user_list = User.all
respond_to do |format|
format.js
end
end
open_list_modal.js.erb:
//populate modal
$('#modal').html('#{ escape_javascript(<%= render partial: 'user_list', locals: {user_list: #user_list} %> )}');
//render modal
$('#modal').openModal();
And then on the modal itself, you can now have access to the user_list (NOT #user_list) list.
Note: In this example, I made use of both erb, js, and material-modal. If you are using something different from these ( maybe slim, haml, coffee, bootstrap...), you will have to suite the example to your case.
Hope this helps.
you can just directly pass it to modal. here what i did thou, on my view i have a button that trigger my modal and then i created a partial (to DRY up my code) _modal.html.erband called that partial after my button.
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#modal"></button
<%= render 'modal' %>
make sure your modal has id <div class="modal fade" id="modal" tabindex="-1" role="dialog">...
gl mate!
You can set it as how you would normally do for view components. Better yet, separate out your model into partial, say it's _modal.html.erb. Then you can call the modal by
<%= render 'partial_name', :variable_name => your_current_variable %>
The variable would now be available as variable_name inside the partial. Also, if it's an instance variable like #your_current_variable then it will be automatically available in your partial.
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!
In my Rails app users have folders, and inside these folders are posts that they can add. Right now I have the folders displaying in my view like this:
<% current_user.folders.each do |folder| %>
<a href='#' id="addSubmissions">
<div id="post-container">
<%= folder.title %> <p id="created-time">Created <%= folder.created_at.strftime("%e/%-m") %></p>
</div>
</a>
<% end %>
What I'd like to do is load the submissions associated with a folder into a div when the #addSubmissions link is clicked. I've tried testing it out with this:
$('#addSubmissions').click(function(){
$('#post-container').append('<%= render :partial => 'contents', :locals => {:folder => folder } %>');
});
But it seems like that render code actually needs to be local beforehand.
The _contents.html.erb partial works, and is pretty simple:
<%= folder.title %>
<% folder.submissions.each do |i| %>
<%= i.title %>
<% end %>
How could I go about doing this? Again, I want to be able to click the link of a folder and load the submissions inside the folder into a div in the view. I'm thinking AJAX might be the solution, but I'm pretty new to Ruby so I don't know how to implement this.
This way it won't work. You need contoller method, which responds to JS, because you are fetching pure ruby variables.
Instead of:
<a href='#' id="addSubmissions">
you might try:
<%= link_to folder_content_path(folder), :remote=>true, :class=> "addSubmissions", :id=>folder.title %>
<div class="post-container" id="<%= folder.title %>">
<%= folder.title %> <p id="created-time">Created <%= folder.created_at.strftime("%e/%-m") %></p>
</div>
or other method name you want. Also note, that ID should be unique for page, otherwise you won't get expected result. Here I use folder name as ID, it probably unique, and it is easy way to find div we want modify with JS.
def folder_content
#folder=Folder.find(params[:id])
respond_to do |f|
f.js
end
end
folder_content.js.erb:
$("#"+"<%=#folder.title %>").append('<%= j render :partial => 'contents', :locals => {:folder => #folder } %>');
I'm attempting to make a two column layout. The column on the left is navigation, and the column on the right is content.
Is there a way to display show.html.erb, edit.html.erb, and new.html.erb at different times in the right div, when the corresponding navigation is selected, without re-loading the whole page?
I know I can use a partial for the left div, and render new pages, but I want to avoid having a separate page load for each view.
Item Controller:
def index
#item = item.find(:all, :order => "id DESC")
end
def new
#item = item.new
end
def create
#item = item.new(params[:item])
if #item.save
redirect_to root_path
else
render "new"
end
end
def edit
#item = item.find(params[:id])
end
def update
#item = item.find(params[:id])
if #item.update_attributes(params[:item])
redirect_to root_path
else
render "index"
end
end
HTML:
<div id="left" ">
<p id=link_to "Current_Item", item_path %></p>
<p id=Link_to "Add_Item", new_item_path %></p>
<p id=Link_to "Edit_Item", edit_item_path %></p>
</div>
<div id="right">
</div>
Routes File:
resources :items
Is "but I'm trying to avoid having a separate page load" means that you want to load your views by ajax instead of a complete new page? If so then your links should be a remote_link and your views should update the div id='right' with the content of corresponding view.
Your links should use :remote=>true option. See the details.
And your view should response to update the content within the <div id="right">.
Another link here with some more insights.
I would recommend modifying app/views/layouts/application.html.erb then put
<div id="left">
<p><%= link_to "Current_Item", item_path %></p>
<p><%= Link_to "Add_Item", new_item_path %></p>
<p><%= Link_to "Edit_Item", edit_item_path %></p>
</div>
<div id="right">
<%= yield %>
</div>
into it. Then the show.html.erb, edit.html.erb, and new.html.erb views should be automatically rendered for each appropriate action that gets called into the right section of your page.
Also I recommend Rails tutorial which is a great tutorial on rails. Then go to Codeschool to learn even more.