This is my first attempt using will_paginate (I know! Where have I been??)
titles_controller.erb
def index
#titles = Title.active.sorted.paginate(:page => params[:page])
end
index.html.erb
<% will_paginate #titles.each do |title| %>
Error:
undefined method `total_pages' for #<Enumerator:0x00000002bacaf0>
WTF am I doing wrong? Thanks in advance.
Please read will paginate docs. You need to write:
<%= will_paginate #posts %>
There is no need for adding each.
So entire view would look like:
<% #titles.each do |title| %>
<!-- do smth with title -->
<% end %>
<%= will_paginate #titles %>
In your case you dont acctually need to write:
<%= will_paginate #titles %>
Because it is in the context of the title_controller, will_paginate will assume their is a #titles variable available. Thus it is possible to just write:
<%= will_paginate %>
Related
I'm discovering the gem will_paginate which is great ! But I'm facing a problem of using. I'm building a group>post>comments app, so in my group show page i'm displaying posts and their comments. To limit the numbers of queries, i'm using includes method like this :
Group_controller :
def show
#posts = #group.posts.order(upd_at: :desc).includes(:user).includes(comments: :user).paginate(page: params[:page], per_page: 10)
end
So I would like to also paginate my comments. Do you know a way to do that ?
My code :
Group_show =
<h1>Groupe <%= #group.name %></h1>
<div class="post_list<%=#group.id%>">
<%= render #posts %>
</div>
<%= will_paginate #posts, renderer: BootstrapPagination::Rails %>
And my posts/_post =
<% #comments = post.comments %>
<ul id="comment_list<%=post.id%>">
<%- if #comments.any? %>
<%= render #comments, post: post %>
<%= will_paginate #comments, renderer: BootstrapPagination::Rails %>
<% end %>
</ul>
By the way if you have a method to define #comments directly in the Groups_controller(show), it can be really useful ;)
Not 100% tested, but I think this should work. Do you know how all these components work? If not, let me know and I can explain.
posts/_post
<% #comments = post.comments.order(created_at: :desc).limit(3) %>
<ul id="comment_list<%=post.id%>">
<%- if #comments.any? %>
<%= render #comments, post: post %>
<%- if post.comments.offset(3).exists? # this is more efficient than count > 3 bc it quits counting after 3 %>
<!-- the below link_to creates: href="/posts/:id/comments" ... -->
<!-- ... and `remote: true` makes that an ajax request -->
<li><%= link_to "more", comments_post_path(post), class: "more-comments-btn", remote: true %></li>
<% end %>
<% end %>
</ul>
config/routes.rb
resources :posts do
# `member do` is explained here: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
member do
get :comments
end
end
posts_controller.rb
# GET /posts/:id/comments
def comments
#post = Post.find(params[:id])
#comments = #post.comments.order(created_at: :desc)
# since you requested this url via ajax with `remote: true` rails will automatically render `posts/comments.js.erb` ...
# ... rather than a typical html request where rails would automatically render `posts/comments.html.erb`
end
views/posts/comments.js.erb
// some people like to use render #comments as shorthand like you did above. I'm a fan of being more explicit like the below
$("#comment_list<%= #post.id %>").html("<%= escape_javascript(render partial: 'comments/comments', locals: {comments: #comments, post: #post}) %>");
// now remove the more comments button
$("#comment_list<%= #post.id %>").find(".more-comments-btn").remove();
The documentation here explains the use of remote: true for ajax requests. Scroll down to section "3.1.2 link_to" and then section 5.1 for the controller and js.erb view.
I have a loop that looks like this
<% #user.collections.each do |collection| %>
<h1 class="impact"> <%= collection.name %><br></h1>
<%= collection.stories.count %>
<% end %>
It works perfectly to show the Collections that belongs to a User, and then show how many Stories are in each Collection.
However, I want to use a helper that does this.
in the view
<% #user.collections.each do |collection| %>
<h1 class="impact"> <%= collection.name %><br></h1>
<%= number_of_stories_in_collection %>
<% end %>
in the helper
module CollectionsHelper
def number_of_stories_in_collection
collection.stories.count
end
def render_stories_count
if number_of_stories_in_collection.zero?
'No stories in this collection yet'
else
"#{number_of_stories_in_collection} #{'story'.pluralize(number_of_stories_in_collection)}"
end
end
end
I get an error that says
undefined method `stories' for #<Collection::ActiveRecord_Relation:0x007f510f504af8>
Any help is appreciated, thanks!
The 'collection' variable isn't an instance variable, so the helper can't see it.
Change your view to this:
<% #user.collections.each do |collection| %>
<h1 class="impact"> <%= collection.name %><br></h1>
<%= number_of_stories_in(collection) %>
<% end %>
And your helper method to:
def number_of_stories_in(collection)
collection.stories.count
end
This way you are passing the variable to the helper correctly.
extending #Richard's answer and little bit of optimisation to avoid n+1 queries..
<% #user.collections.includes(:stories).each do |collection| %>
<h1 class="impact"> <%= collection.name %><br></h1>
<%= render_stories_count(collection) %>
<% end %>
helper:
module CollectionsHelper
def number_of_stories_in(collection)
collection.stories.length
end
def render_stories_count(collection)
if (count = number_of_stories_in(collection)).zero?
'No stories in this collection yet'
else
"#{count} #{'story'.pluralize(count)}"
end
end
end
This is so simple but isnt working. What am I missing?
controlelr
#guide = Guide.friendly.find(params[:guide_id])
#category = #guide.categories.friendly.find params[:id]
#items = #category.category_items
view
<% #items.each do |item| %>
<%= item.category_item_values.value %>
<% end %>
gives the no method error of
undefined method 'value' for #<CategoryItemValue::ActiveRecord_Associations_CollectionProxy:0x007ff9706d24c0>
There is a values column in the category_item_values table so I'm not sure what the problem is.
item.category_item_values is the CollectionProxy instance (one might think of it as of an kinda array.)
Each category_item has [likely, you did not provide sufficiently enough info to guess more precisely] many values. If the assumption above is correct, here you go:
<% #items.each do |item| %>
<% item.category_item_values.each do |value| %>
<%= value %> # or maybe (depending on your model) <%= value.value %>
<% end %>
<% end %>
You will have to loop over each of the category_item_values to get the result as this suggests <CategoryItemValue::ActiveRecord_Associations_CollectionProxy:0x007ff9706d24c0> that your category_item_value is a association.
So you could do something like
<% item.category_item_values.each do |category_item_value| %>
<%= category_item_value.value %>
<% end %>
Old usage:
<% form_tag %>
...
<% end %>
<% form_for %>
....
<% end %>
New usage:
<%= form_tag %>
...
<% end %>
<%= form_for %>
....
<% end %>
(I was learning Head First Rails and know the differences in this list)
I knew that scriptlet don't need = in the <>, but if <%= form_tag %> is not a scriptlet, why does it need a <% end %>?
Does anyone have ideas about this?
Firstly, I've got no idea what a 'scriplet' is; anyway, this was a change in rails 3.0 - see the release notes: http://guides.rubyonrails.org/3_0_release_notes.html#helpers-with-blocks.
Rails 3 brings overall consistency in the API and in this case in the view API.
Rule is:
(want_to_display?) ? (use =) : (don't use =)
So Im listing out all the members of my site and grouping them by name so that the list will be organized better. So in my view all my members are grouped by the first letter of their member name like:
B
Bakedfish
Beercan Dan
Bigmike33x
C
Cynicalassassin
ect..
Anyway, I also want to paginate this list but I cant add Kaminari's pagination arguments to my controller if Im using order because I get an undefined method error.
so this doesnt work:
#members = Member.all.group_by{|u| u.fullname[0].titleize}.page(params[:page]).per(18)
my view looks like this:
<div class="content">
<%= paginate #members %>
</div>
<% #members.keys.sort.each do |starting_letter| %>
<h3>
<%= link_to starting_letter, {:action => :browse, :controller =>:members, :letter => starting_letter } %>
</h3>
<ol>
<% #members[starting_letter].each do |member| %>
<li>
<% if member.is_artist? %>
<%= link_to member.full_name, member_path(member), :class=>"artist" %>
<% else %>
<%= link_to member.full_name, member_path(member) %>
<% end %>
</li>
<% end %>
</ol>
<% end %>
Here is my error message:
NoMethodError (undefined method `page' for #<Hash:0x007f78d4bf48f8>):
app/controllers/members_controller.rb:10:in `index'
Kaminari adds page method to ActiveRecord::Relation but Member.all.group_by returns hash. That is why you get this exception.
I'd suggest to perform grouping after pagination, e.g.:
#members = Member.order(:full_name).page(params[:page]).per(18).to_a.group_by { |u| u.fullname[0].upcase }
UPDATE
In order to use paginate helper you could assign 2 variables, e.g.:
#paginated_members = Member.order(:full_name).page(params[:page]).per(18)
#members = #paginated_members.to_a.group_by { |u| u.fullname[0].upcase }
And pass #paginated_members to the paginate helper.