I have an index view for a model(nested ) that never gets called from the model, but is rendered from a couple different models. One view can render the index with either JS or html. With JS is it in a #related div in the show view and a data-remote link. Another option uses the same controller action to render it only has html.
All was fine until I added Kaminari paging. In the full page view, there was no #related div so paging didn't work. I broke out the guts into a partial and added a #related div and rendered the partial. From js I just rendered the partial from JS. That worked fine in the full page view, but in the show page it would render the partial, but the links didn't work, looks like it renders the entire show page. Clinking on another tab and then going back to the Progressions tab loads the partial and all works fine. It is just on the initial load of the show page that I can't get the page links to work.
I can load another tab that does not use paging first and solve my problem, but this was kind of the main information that you go to this page for.
Any ideas?
EDIT Request for code
The controller action method. The index method in this controller also sets #progressions
def progressions
authorize! :read, Progression
#stage = Stage.find(params[:id])
#progressions = #stage.progressions_by_score.page(params[:page]).per(20)
if params[:status] && !params[:status].blank? && #progressions
#progressions = #progressions.where(status: params[:status]).page(params[:page]).per(20)
end
respond_to do |format|
format.js
format.html {render :template => "progressions/index"}
end
end
The progressions.js.erb file in the stages view
$("#related").html("<%= escape_javascript(render('progressions/index'))%>");
The relations div in the show view. This is pretty much my scaffold template where I display or link to related information. The <div id="related"> is where any date-remote links will load the data. On initial load it loads the _index partial.
<div class="relations">
<span class="navspan">
<%= link_to 'Progressions: Status ->', progressions_stage_path(#stage), :'data-remote' => true,
:onclick => '$("#progression_status").val("")' %>
<span class="huh">
<%= hidden_field_tag :stage_id, params[:id]%>
<%= select_tag :progression_status, options_for_select(Progression.statuses["all"], params[:status]),
:prompt => 'All', :class => 'f-left' %>
</span>
<%= link_to 'Assessors', assessors_stage_path(#stage), :'data-remote' => true %>
<%= link_to 'Events', events_stage_path(#stage), :'data-remote' => true %>
<%= link_to 'Select', select_stage_path(#stage) if can? :select_candidates, #stage %>
<%= link_to 'Ad Mgmt', edit_ad_stage_path(#stage) if can? :manage_ad, #stage %>
</span>
<div class="f-clear"></div>
<div id="related">
<%= render "progressions/index"%>
</div>
</div>
The index.html.haml file
#related
= render "progressions/index"
The _index.html.haml file is just an index table listing the progressions but it does contain:
= paginate #progressions, :remote => true
Shortly after posting some code, I went back in my memory and used javascript to load the related div. I've tried to stay away from javascript, but in this case I added this to the end of the page after adding :id => "status_id" to the progressions link:
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$("#status_link").trigger("click");
})
</script>
While this fixes my problem, I still don't understand why the initial html response does not respond to the page links in the related div. I'll leave that as something else to learn. I'll put it in coffescript after I figure out how to have fire only on initial load of the show page.
Related
How do I render a partial view via its controller when loading a separate view in Ruby on Rails?
Thanks for your help in advance
Problem: I have a show.html.erb for my Patients controller, when this loads I have a series of tabs, one of which is a list of notes added to that patient record. Notes is a separate model. I want to load the list of notes when loading show.html.erb.
I can use the code below to render the view directly and can pass variables in this way, but I would rather go through the controller and deliver notes/_list.js.erb, via the Patients Controller.
<%= render "notes/list", :remote => true %>
I have a solution that loads the partial via a link_to but because the link is in a tab it then breaks my tab javascript, and would rather just load the information on initial page load rather than have the user interact with an element.
<%= link_to "Notes".html_safe,{:controller => "patients", :action => "notes", :remote => true } %>
It needs to be in a partial as I am then using pagy to paginate the results and if I display it via a controller dependent partial then the pagy navigation links function as expected.
Relevant Routes
get 'patients/:id/show' => 'patients#show', as: :show_patient
get 'patients/:id/notes' => 'patients#notes', as: :notes_patient
Relevant Patients Controller
def notes
#pagy, #notes = pagy( Note.where(:patient_id => params[:id]).reverse_order, items: 2 )
respond_to do |format|
format.html { render "notes/list" }
format.js { render "notes/list" }
end
end
notes/list.js.erb
$('#notes-list').html('<%= escape_javascript(render('notes/list')) %>');
notes/_list.html.erb
<% #notes.each do |note| %>
<%= render partial: note %>
<% end %>
<%== pagy_materialize_nav(#pagy) %>
<span class="pagy-info"><%== pagy_info(#pagy) %></span>
I believe you can do something like this in the controller:
# or whatever this partial is called
#notes_rendered = render_to_string "notes/list"
And then use it in the view you want.
I'm trying to render a partial on home page. Code is a follows:
<%= render :partial => 'spree/shared/slider' %>
The thing is I want it to render/show the partial only if I'm on the home page .To summaries for a particular page/pages only.
Can anyone help me with this? Thank you.
You can use a conditional for deciding whether the partial should be rendered:
<%= render :partial => 'spree/shared/slider' if #slider %>
The condition could be an instance variable (e.g. #slider) which can be set from the view (when not set, it remains nil by default):
<% #slider = true %>
Now the partial will only be rendered if #slider has been explicitly set to true in the view or in the controller.
This is my view
<div style="width:10%;float:left;margin-bottom:357px">
<%= form_for(:img, method: "post", url: {action: "printer"},:target => "frame") do |f| %>
<input type="hidden" id="image_attach" name="image_attach">
<%= f.submit "Preview", {:id => "submit"} %>
<%end%>
</div>
<div style="width:45%;float:left">
<iframe id="frame" name="frame"height="600px" width="630px" src="<%=%>"></iframe>
</div>
What should I put in the source?
This is my controller
def printer
#image_file1=params[:image_attach]
#posts = Post.all
render(:action =>"printing.pdf",:image => #image_file1)
end
def printing
#image_file1=params[:image_attach]
#posts = Post.all
redirect_to(:layout => "frame")
end
end
Without iframe it works properly but with iframe nothing appears in the iframe...
please help
An <iframe> element is used to embed another web page. The description from these mozilla docs says:
The HTML <iframe> Element (or HTML inline frame element) represents a
nested browsing context, effectively embedding another HTML page into
the current page.
The source for your iframe should be the url for the page you intend to display.
It's not entirely clear why you are doing this - perhaps you should check out some other options for PDF rendering.
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>
Im trying to implement an Ajax call with the will_paginate gem, I found this guide http://ramblinglabs.com/blog/2011/11/rails-3-1-will_paginate-and-ajax which seemed like a simple solution, though it includes coffeescript which i am not familiar with, so if anyone has a different solution then please advise..
My code is as follows
My View
<div class="container">
<div class="row">
<div id="userRecipes">
<%= render partial: 'userrecipes' %>
</div>
</div><!--/row-->
My partial (userrecipes)
<% #recipes.each do |r| %>
<div class="span3">
<div class="thumbnail">
<%= image_tag r.avatar.url(:myrecipes) %>
</div>
<h4><%= link_to r.dish_name, r %></h4>
<hr>
<p><%= truncate r.description, :length => 90 %></p>
<p><%= link_to "Edit Recipe", edit_recipe_path(r.id) %></p>
<p><%= link_to "Delete Recipe", recipe_path(r.id), :confirm => "Are you sure?", :method => :delete %></p>
<p><%= link_to "Add to favorites", {:controller => 'favourites', :action => 'create', :recipe_id => r.id}, {:method => :post } %></p>
</div><!--/span3-->
<% end %>
<%= will_paginate #recipes %>
updated userrecipes.js.erb file
$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();
Coffeescript
$ ->
$.setAjaxPagination = ->
$('.pagination a').click (event) ->
event.preventDefault()
loading = $ '<div id="loading" style="display: none;"><span><img src="/assets/loading.gif" alt="cargando..."/></span></div>'
$('.other_images').prepend loading
loading.fadeIn()
$.ajax type: 'GET', url: $(#).attr('href'), dataType: 'script', success: (-> loading.fadeOut -> loading.remove())
false
$.setAjaxPagination()
When i click on the next anchor tag to show the next set of results the page stays as it is and no new content appears
When using the console to see if there are any errors i can see any, the output is
GET http://localhost:3000/my_recipes?page=2&_=1355055997639
Am i missing something here? or is there an issue with my userrecipes.js.erb file because in other Ajax examples i have seen thy are using escape_javascript when rendering the partial?
Edit
Whilst inspecting the response in the console it is also showing that the new recipes to be loaded are being loaded but nothing is happening in the view
Any pointers appreciated
Thanks
Why not try a simpler approach, create a new helper (ex. app/helpers/will_paginate_helper.rb) with the following content:
module WillPaginateHelper
class WillPaginateJSLinkRenderer < WillPaginate::ActionView::LinkRenderer
def prepare(collection, options, template)
options[:params] ||= {}
options[:params]['_'] = nil
super(collection, options, template)
end
protected
def link(text, target, attributes = {})
if target.is_a? Fixnum
attributes[:rel] = rel_value(target)
target = url(target)
end
#template.link_to(target, attributes.merge(remote: true)) do
text.to_s.html_safe
end
end
end
def js_will_paginate(collection, options = {})
will_paginate(collection, options.merge(:renderer => WillPaginateHelper::WillPaginateJSLinkRenderer))
end
end
Then in your view use this tag for ajax pagination:
<%= js_will_paginate #recipes %>
Remember that the pagination links will include existing params of the url, you can exclude these as shown below. This is standard will paginate functionality:
<%= js_will_paginate #recipes, :params => { :my_excluded_param => nil } %>
Hope that solves your problem.
Explanation:
Will_paginate allows you to create your own custom renderer. The WillPaginateJSLinkRenderer is such a custom renderer and this class could be defined anywhere, it doesn't have to be defined inside the helper module. The custom renderer extends the standard renderer (LinkRenderer) and redefines only two methods.
The prepare method is overriden to explicitly remove the cache buster parameter since will_paginate creates the page urls with all parameters that were present when rendering the page and we do not want to reuse the cache buster parameter.
The link method is a copy paste from the original LinkRenderer source code but creates a link with remote: true to make it a JS resquest.
Finally the js_will_paginate method is a standard view helper method to call the normal will_paginate view helper method but adds our custom renderer to the options so that it will be used instead of the normal renderer.
Just in case someone is looking for Rails 4 solution. I liked the answer from Pierre Pretorius, but it failed for me on 4.1.1 with "method undefined" for link_to_function on the line:
#template.link_to_function(text.to_s.html_safe, ajax_call, attributes)
I just replaced the line to:
#template.link_to(text.to_s.html_safe, '#', attributes.merge(:onclick => "#{ajax_call} event.preventDefault();"))
I hope it may help someone.
You are not escaping javascripts in your js.erb, it should be the problem.
$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();
The ajax_will_paginate is a superb method, but unfortunately it was messing up the UI of the paginate. I had employed another javascript method for more flexibility. And I call this method on pageRender.
function checkForAjaxPaginate(controller,make_ajax){
var href = "";
$(".pagination").find("ul").each(function(){
$(this).find("li").each(function(){
$(this).find("a").each(function(){
href = $(this).attr("href");
if(href.indexOf(controller+".js") != -1){
if(make_ajax){
$(this).attr("data-remote","true");
}
else{
$(this).attr("href",href.replace(".js",""));
}
}
});
});
});
}
For more flexibility, you just pass the action name in the "controller" variable and pass true to make_ajax if you want to convert it to ajax. All I am doing is to check if the href link is ".js", and if make_ajax is true, then adding an attr "data-remote=true", which in our ROR app makes it ajax. if make_ajax is not true then am just removing the ".js" so the code does not mess.
I hope this helps
Pierre Pretorius' answer is great, but I had to do a little more to make it work for me that wasn't already clear. Maybe this will be helpful to other beginners.
In addition to making that helper and using the js_will_paginate tag I did this:
After moving the content I was trying to paginate into a partial (_recipes.html.erb in the case above), I also created a show.js.erb file (in this same view alongside the partial) with text similar to this:
$('#recipes').html('<%= escape_javascript(render partial: 'recipes') %>');
Then I had to move the js_will_paginate tag to the partial as well at the bottom (so it would be updated as I paginated through or clicked next/previous). Then I had to wrap the render partial helper in the div id you're targeting in the js file, so in this example:
<div id="recipes">
<%= render partial: "recipes" %>
</div>
This may have been very clear to others, but I wasn't sure which steps from the OP had to remain and which were unnecessary. These steps worked for me. You don't need to add respond_to js in the controller as the helper takes care of that or have a coffeescript file.