Will paginate not paginating (instance variable error I suppose) - ruby-on-rails

H there, I can't get Will_paginate to paginate the photos a user has. See if someone can help me out with it...
My code is:
Users Controller
def show
#user = User.find(params[:id])
#photos = #user.photos.paginate(:page => params[:page],:per_page => 6)
end
Show Users View
<div class="row center semi_padding_top semi_padding_">
<%= will_paginate(#photos,:next_label => "<button class='semi_margin_right mediumbutton large-1 columns large-centered'>Más<i class='big icon-arrow-right2'></i></button>", :previous_label => "<button class='semi_margin_left mediumbutton large-1 columns large-centered'><i class='big icon-arrow-left'></i>Menos</button>", :page_links => false) %>
</div>
Thanks!

Related

How make caching work with pagination and search form?

I working with ruby on rails and my products views is cached and I can find products with search form. I want to use pagination as well, but when added, it didn't worked and also search form. Found code line ,but not sure how to use it, code below.
<% cache ["v1-#{params[:page]-#{params[:q]", cache_key_for_products]
> do %>
My code
Index.html.erb
<div class="products">
<div class="container">
<center><h1>All products</h1></center>
<div class="row">
<% cache(cache_key_for_products) do %>
<%= render #products %>
<% end %>
</div>
<%= will_paginate #comments, :container => false %>
</div>
</div>
_product.html.erb
<% cache product do %>
<div class="col-md-3 col-lg-3 col-sm-6 col-xs-12">
<div class="product-block">
<h4 id="product-name"><%= product.name %></h4>
<%= link_to product_path(product), class: 'product_link' do %>
<%= image_tag(product.image_url, class: "img-responsive") %>
<% end %>
<div class="price">
<h4>£ <%= product.price %></h4>
</div>
</div>
</div>
<% end %>
products_helper.rb
module ProductsHelper
def cache_key_for_products
count = Product.count
max_updated_at = Product.maximum(:updated_at).try(:utc).try(:to_s, :number)
"products/#{params[:q] || "all"}-#{count}-#{max_updated_at}#{signed_in? && current_user.admin? ? "-admin" : "normal"}"
end
end
products_controller.rb
def index
if params[:q].present?
search_term = params[:q]
if Rails.env.development?
#products = Product.where("name LIKE ?", "%#{search_term}%")
else
#products = Product.where("name ilike ?", "%#{search_term}%")
end
else
#products = Product.all.paginate(:page => params[:page], :per_page => 30)
end
end
In your controller, looks like you are paginating correctly when not performing a search, but need to add the pagination to your search query also:
def index
if params[:q].present?
search_term = params[:q]
if Rails.env.development?
#products = Product.where("name LIKE ?", "%#{search_term}%").paginate(:page => params[:page], :per_page => 30)
else
#products = Product.where("name ilike ?", "%#{search_term}%").paginate(:page => params[:page], :per_page => 30)
end
else
#products = Product.all.paginate(:page => params[:page], :per_page => 30)
end
end
Also you are caching each search result set, this means that the same products could be potentially cached multiple times in many different searches. This will quickly bloat your cache. It would be better to cache each product once and fetch these products from cache regardless of the search.
I see you are caching each product (in _product.html.erb partial). In index.html.erb change the code to this:
<div class="products">
<div class="container">
<center><h1>All products</h1></center>
<div class="row">
<%= render #products, cache: true %>
</div>
<%= will_paginate #comments, :container => false %>
</div>
</div>
This will take advantage of multi fetch fragment caching which Rails 5 has built in:
1.3.1 Collection caching
The render helper can also cache individual templates rendered for a
collection. It can even one up the previous example with each by
reading all cache templates at once instead of one by one. This is
done by passing cached: true when rendering the collection:
<%= render partial: 'products/product', collection: #products, cached:
true %> All cached templates from previous renders will be fetched at
once with much greater speed. Additionally, the templates that haven't
yet been cached will be written to cache and multi fetched on the next
render.
Otherwise if you are < Rails 5, use the Multi Fetch Fragments gem to enable this functionality.
In index.html.erb you could modify the collection cache rendering to something this to use a custom cache key:
<%= render #products, cache: Proc.new{|item| [item, 'show']} %>

Rails 5 - Iterating over part of an array for the view

I currently use EasyAutoComplete for a search form. If you hit 'View All' it redirects to the same page but with params[:name] to show all cards.
I render this with:
<% #cards.in_groups_of(6, false).each do |group| %>
<div class='row'>
<% group.each do |card| %>
<div class='col-sm-2 col-md-2'>
<div class="wrapperImg">
<%= link_to image_tag(card.image_url, class: "img-responsive"), {:controller => "cards", :action => "show", :id => card.id }%>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
However, if you look up a specific set of cards it's going to return a couple hundred (or more) of essentially the same card. I can identify these cards by a parameter(rarity)
I was originally going to try to modify it in the controller, but that is an issue because the 'def index' makes the EasyAutoComplete work
def index
wild_search = "%#{params[:name]}%"
#cards = Card.order(multiverse_id: :desc).limit(30)
# debugger
##cards = #cards.where("name like :name", name: wild_search).page(params[:page]) if params[:name]
#cards = #cards.where("name like :name OR setName like :name", name: wild_search).page(params[:page]) if params[:name]
end
Is there a way for me to do something like
cards = #cards.where('rarity IS NOT ?', 'Land') or something similar in the view, then modify my output from #cards.in_group_of to cards.in_group_of? Or is there a way to use the Controller to do this and use def search instead of def index?
Welcome any input.
Like this?
<% #cards.where.not(rarity: "Land").in_groups_of(6, false).each do |group| %>
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods/WhereChain.html

How do I implement a show all comments feature in ruby on rails?

I'm implementing show/hide feature for users comments.
Discussed here: https://stackoverflow.com/a/10174194/439688
My aim was to:
1. Limit the default shown comments to 2.
2. Have a span with text that states the number of total comments for that particular micropost and when clicked by a user have it expand and show all comments for that micropost. I would be using Jquery/Ajax to hide, show, prepend etc.
The first change was to limit the amount of comments shown to the user and I achieved this by creating a method in my helper called "comments" and here I pass in the id of the micropost the comment belongs to.
def get_comments(micropost_id)
Comment.limit(2).order("created_at DESC").where(:micropost_id => micropost_id)
end
Now the each loop that loops through each comment will only show the 2 most recent comments.
<<% #microposts.each do |m| %>
<% if m.poster_id.nil? %>
<div class="postHolder">
<nav class="micropostOptions">
<ul class="postMenu">
<li class="deletePost"><%= link_to content_tag(:span, "Delete post"), m, :method => :delete, :confirm => "Are you sure?", :title => m.content, :class => "message_delete", :remote => true %>
</li>
<li class="disableCommenting"><%= link_to content_tag(:span, "Pause commenting"), "2" %></li>
<li class="blockCommenter"><%= link_to content_tag(:span, "Block commenter"), "3" %></li>
<li class="openInNewWindow"><%= link_to content_tag(:span, "Open in new window"), "4" %></li>
<li class="reportAbuse"><%= link_to content_tag(:span, "Report abuse"), "5" %></li>
</ul>
</nav>
<%= link_to image_tag(default_photo_for_current_user, :class => "poster_photo"), current_users_username %>
<div class="post_content">
<div class="post_container">
<div class="mainUserNameFontStyle"><%= link_to current_users_username.capitalize, current_users_username %> - <div class="post_time"> <%= time_ago_in_words(m.created_at) %> ago.</div>
</div>
<%= simple_format h(m.content) %> </div>
<div class="commentsCount">
<%= content_tag :span, pluralize(m.comments.count, 'comment'), :class => "view_all_comments" if m.comments.any? %>
</div>
<% if m.comments.any? %>
<% comments(m.id).each do |comment| %>
<div class="comment_container">
<%= link_to image_tag(default_photo_for_commenter(comment), :class => "commenter_photo"), commenter(comment.user_id).username %>
<div class="commenter_content"> <div class="userNameFontStyle"><%= link_to commenter(comment.user_id).username.capitalize, commenter(comment.user_id).username %> - <%= simple_format h(comment.content) %> </div>
</div><div class="comment_post_time"> <%= time_ago_in_words(comment.created_at) %> ago. </div>
</div>
<% end %>
<% end %>
<% if logged_in? %>
<%= form_for #comment, :remote => true do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :micropost_id, :value => m.id %>
<%= f.text_area :content, :placeholder => 'Post a comment...', :class => "comment_box", :rows => 0, :columns => 0 %>
<div class="commentButtons">
<%= f.submit 'Post it', :class => "commentButton", :disable_with => "Post it" %>
<div class="cancelButton"> Cancel </div>
</div>
<% end %>
<% end %>
</div>
</div>
From here this is where it gets confusing for me. I got slightly further using link_to but then decided I'd prefer not to have the url to the comments count show in the browser status bar. This is why I switched to using span.. but now it's not quite easy to do what I wish to do as I can't use the link_to/remote => true now.
How do I make it so when a user clicks the comment count span an ajax call is made pointing to:
def load_comments
#load_comments = Comment.where(:micropost_id => params[:id])
respond_to do |format|
format.js { render :load_comments }
end
end
I thought about putting a click function in users.js but how would I pass the params of the micropost that is in the each loop in the code above into users.js? I don't think it's possible.
All my comment posting is done via ajax but because I used forms for these it was so much easier for me to just add remote => true and create some js templates and do something on success of ajax post.
Not sure if I'm even going about this the right way. I'd appreciate some help/advice from more experienced rails programmers.
Kind regards
Rails partial
#Display all the comments based on local passed to this partial
# Initially pass limit as 2(or whatever you want). then on click of span pass limit as nil. then you can check if limit is nil you can query the model without limit specifier.
<% #comments = Comment.custom_find(#your_params) %>
<% #comments.each do |comment| %>
<%= comment.title %>
<% end %>
javascript/jquery
function load_all_comments(id)
{
new Ajax.Updater('show_comments',
'<%=url_for(:controller => "your_controller", :action => "your_action")%>', {
parameters: {'id':id },
method: 'get',
onSuccess: function(request){
div_comments = document.getElementById("partial_comments_list");
div_comments.innerHTML = request.responseText;
}
});
} // you can call this js function on span click. use jquery if you want.
Controller:
Then inside your_action of your_controller, dont forget to render the partial
render :partial => "show_comments", :layout => false
Edit:
you can even pass locals to your partial
render :partial => "show_comments", :locals => {:post => #post}
Using this every time your partial view will get updated, on the basis of locals you pass.
of course this is just an example not a complete code/solution.
There may be better ways. but this worked fine for me.
Another option is to just output all of the comments and hide the ones you don't want to show first. <div class="hidden_comments" style="display:none;"> a comment </div>
Then just have some javascript to show them when the span is clicked?
<script type="text/javascript">
$("#span_id").click(function() {
$('.hidden_comments').show();
});
</script>
This works great if you do not don't have a ton of comments.
If you really want to do it your way, I have done it before but it gets messy.
Put this in your application.js
$('.comment_span').live('click', function () {
$.get(this.data_url, null, update_row, 'json');
return false;
});
Your span would look like this:
<span class="comment_span" data_url="http://website.com/resource/more_comments">
show all comments
</span>
This example returns the data as json, so I used the update_row function to update replace the comments data.
function update_row(data, status) {
$("#comments-table").append(data.html);
};
Here is what my controller looked like:
def more_comments
#comments = Comments.all
if #comments
respond_to do |format|
format.js {
render :json => {
:html => render_to_string(:partial => "comments"),
}.to_json
}
end
end
end
You should do this via your index action.
Pass a param to it to determine if you want to show all comments or just the current set (I'd use will_paginate to handle this.
Haven't looked too deep into your code as I'm on my phone right now, but something like this:
class CommentsController < ApplicationController
def index
If params[:show_all] == "true"
#comments = Comment.all
else
#comments = Comment.where(foo: bar).paginate(per_page: 2, page: params[:page])
end
end
Then you have it respond to JavaScript and send the page param with your Ajax request

Rails: Rendering with Pagination Issues of a Comment Model

The current page that I have been working on is a page where a user can create a comment under a specific micropost. All the microposts are shown on the same page and those microposts are paginated. Under each specific micropost, there are comments and those comments should be paginated and the issue I am currently having is that the pagination only happens when the HTML code is this:
HTML
<div id='comments'>
<%=render #comments %>
<%= will_paginate #comments, :class =>"pagination" %>
</div>
But the thing is when it is like that only the comments for the first micropost will show up on every single micropost rather than the specific micropost comments. So I figured why not put the code like this:
HTML
<div id='comments'>
<%=render micropost.comments %>
<%= will_paginate #comments, :class =>"pagination" %>
</div>
This basically set all the specific comments in the right micropost BUT it didn't paginate but the pagination links showed, so I figured putting this would work but it didn't, got an error:
HTML
<div id='comments'>
<%=render micropost.comments %>
<%= will_paginate micropost.comments, :class =>"pagination" %>
</div>
I am very confused and unsure what to do and yes the micropost is suppose to have no #
I would appreicate any suggestions that would help! Thank you!
My User#Show
User Controller
class UsersController < ApplicationController
def show
#user = User.find_by_id(params[:id])
#school = School.find(params[:id])
#micropost = Micropost.new
#comment = Comment.new
#comment = #micropost.comments.build(params[:comment])
#comments = #micropost.comments.paginate(:page => params[:page], :per_page => 10)
#microposts = #user.microposts.paginate(:per_page => 10, :page => params[:page])
end
end
This will work, but the fact that you need to do an assignment inside your view tells you this is probably not the way to do it:
<div id='comments'>
<% comments = micropost.comments.paginate(:per_page => 10, :page => params[:page]) %>
<%= render comments %>
<%= will_paginate comments, :class =>"pagination" %>
</div>
Do realize that the micropost & comments both use the same page parameter. So that if you want to view the second page of comments of any of the given microposts you will also switch to the second page of microposts. I would reconsider showing all this information on the same page.

different action to index page. how to?

I have this code:
<% #cars.each do |car| %>
<div class="scroll-content-item ui-widget-header">
<%= link_to image_tag( car.profile_avatar.asset.url(:thumb) ), car %>
</div>
<% end %>
..which will display the number of cars that are defined in the index action:
def index
#search = Car.search(params[:search])
#cars = #search.all.paginate :page => params[:page], :per_page => 5
..so I'll have 5 images in the slider. I can't change it because I use it for the main <div>.
The question is, how do I make another statement in the controller and how do I make a reference to it in the view so that I can have more car pictures in the slider?
Thanks.
I got it.. I just add a new instance in controller like
#cars_footer = #search.all.paginate :page => params[:page], :per_page => 3
then I call it in the view with
<% #cars_footer.each do |car| %>
<div class="scroll-content-item ui-widget-header">
<%= link_to image_tag( car.profile_avatar.asset.url(:thumb) ), car %>
</div>
<% end %>
SO easy... well.. I am new in rails.

Resources