I've created a Resource where I want to group each response by an attribute from an belong_to association.
I've accomplished that with the following code:
fixtures_controller.rb
def index
#q = Fixture.ransack(params[:q])
scope = #q.result(distinct: true)
#fixture_leagues = scope.filter_by_date_range.group_by {|fixture| fixture.league.name}
end
fixtures/index.erb
<%= turbo_frame_tag "table" do %>
<p class="loading">Loading...</p>
<div class="-mx-4 overflow-hidden sm:-mx-6 md:mx-0">
<ul compact="container mx-auto gap-4 list-none">
<%# render #fixtures %>
<% #fixture_leagues.each do |league, fixtures| %>
<h2 class="text-base"><%= league %></h2>
<% fixtures.each do |fixture| %>
<%= render partial: "fixture", locals: {fixture: fixture} %>
<% end %>
<% end %>
</ul>
<% end %>
</div>
My issue is that the response can sometimes be really large so I want to have som pagination on the response. But do not know how to accomplish that with a grouped response?
I use Pagy Gem for pagination for my other resources.
And I want the response to be
League 1
Fixture 1
Fixture 2
Fixture 3
League 2
Fixture 4
Fixture 5
League 3
Fixture 6
Fixture 7
Fixture 8
Fixture 9
Fixture 10
(trigger pagination) to see more items.
Related
I'm using the following code to display posts to my users.
_feed.html.erb partial:
<% #posts_by_month.each do |monthname, posts| %>
<%= monthname %>
<ul>
<% posts.each do |post| %>
<li><%= post.created_at %></li>
<% end %>
</ul>
<% end %>
Controller:
def home
if logged_in?
#post = current_user.posts.build
#posts_by_month = current_user.feed.group_by { |post| post.created_at.strftime("%B") }
This renders my posts as follows:
Post 1
Post 2
Post 3
Post 4
I want to change it so that the posts are displayed like:
Post 1 Post 2 Post 3
Post 4 etc etc
etc
I've tried several approaches to this, including the in_groups_of(3) method however the way it is currently setup means nothing works. I feel like there is an obvious solution I'm missing - can anyone help?
[Edit to expand on the in_groups_of(3) error]
If I change line 4 in the _feed partial to:
<% posts.in_groups_of(3, false).each do |post| %>
It gives the error: undefined method `created_at' for #< Array:0xbb8f258 >
The #in_groups_of method returns an Array of Arrays each containing 3 Post objects.
So you now also need to iterate over the returned array that contains your three Posts, something like:
<% posts.in_groups_of(3, false).each do |post_group| %>
<% post_group.each do |post| %>
<li><%= post.created_at %></li>
<% end %>
<% end %>
You can use facets gem. This provides and each_by method. You can use each_by to create groups and iterate further on these groups.
Here is code snippet on how to use each_by
<div class = "small-9 columns vertical-border-left">
<%- #client.contact_details.each_by(3) do |contact_details| %>
<div class="row">
<%- contact_details.each do |contact| %>
<div class="small-3 columns small">
<div> <%= contact.contact_detail_type %> contact </div>
<div> <%= contact.contact_email %> </div>
<div> <%= contact.contact_phone %> </div>
</div>
<% end %>
</div>
<% end %>
</div>
I am creating a quiz like website.
I have categories, questions and choices as tables.
What i want is, where i list my categories, when i click on category, i want it to take me to the categories/1/questions/<random question> path.
the relationships are set up
here is what i have so far.
index.erb.html (of categories)
<ul class="categories-list">
<% #categories.each do |category| %>
<% if category.header %>
<% #count = #count + 1 %>
<li class="panel header" id="cat<%= #count %>">
<%= category.title %>
<small>781 of 781 questions remaining</small>
</li>
<% else %>
<li class="panel sub hidden subcat<%= #count %>" >
<%= link_to category.title, category_question_path(category,category.questions.limit(1).order("RAND()")) %>
<small>781 of 781 questions remaining</small>
</li>
<% end %>
<% end %>
</ul>
categories-controller.rb
def index
#count = 0
#categories = Category.order(:tag)
end
The most generic way to do this (independent of database vendor):
category.questions.offset(rand(category.questions.count)).first
Vendor specific queries are also possible:
category.questions.order("RANDOM()").first # postgres
category.questions.order("RAND()").first # mysql
Define new action /random_question:
def random_question
category = Category.find params[:category_id]
question = category.questions.offset(rand(category.questions.count)).first
redirect_to question_path(question)
end
I'm building a basic forum application in Ruby on Rails (v4.1.7) and I'm having an issue with displaying the topics in descending order based on their last post. The code I'm using below will show the topics in the correct descending order, however the last post times and last poster name are wrong.
When I view the topic with comments#index, these data are correct. Both comments#index and topics#index call the same partial to display the topic:
I believe this may have to do with me calling topic.comments.last
Testing it out, it seems to be displaying the FIRST comments userdata and created_at, rather than the last, however the forums ARE showing up in the correct order.
Partial: _topic.html.erb:
<article class="topic">
<h2><%= link_to(topic.title, topic_comments_path(topic)) %></h2>
<div class="author">
By <strong><%= topic.user.name %> </strong>
on <%= topic.created_at.strftime('%b %d %Y') %>
</div>
<div class="stats">
Viewed <%= pluralize(topic.view_count, 'time') %>.
<% if topic.comments.any? %>
Last comment <%= time_ago_in_words(topic.comments.last.created_at) %> ago
by <%= topic.comments.last.user.name %>.
<% else %>
No comments.
<% end %>
<span class="pull-right">
<%= pluralize(topic.comments.count, 'comment') %>.
</span>
</div>
</article>
topics_controller#index (produces incorrect data):
def index
#topics = Topic.includes(:comments).order('comments.created_at desc')
end
I have also attempted:
def index
#topics = Topic.includes(:comments).paginate(page: params[:page]).order('comments.created_at desc')
end
topics/index.html.erb(wrong data):
<% provide(:title, 'Forum Index') %>
<%= render partial: #topics, spacer_template: 'shared/hr' %>
Viewing a specific thread (in this case the topic.comments.last.user.name and topic.comments.last.created_at are the correct values):
def index
#context = context
#comments = #context.comments.paginate(page: params[:page])
end
#...
private
def context
Topic.find(params[:topic_id]) if params[:topic_id]
end
topics/index.html.erb (right data):
<% provide(:title, #context.title) %>
<h1>View Discussion</h1>
<%= render(partial: 'topics/topic', object: #context) %> # Partial with right data
<hr />
<%= render(partial: 'comment',
collection: #comments,
spacer_template: 'shared/hr',
locals: { topic: #context }) || 'No comments.' %>
<hr />
<%= render partial: 'comment_form', locals: { context: #context,
comment: #context.comments.new } %>
topic.comments.last
should be
topic.comments.first
because you're placing the latest comments first.
Where it's working fine, it is because you aren't ordering the comments and the last will fetch the comment with the highest primary index value which is most likely the ID.
Hope that clears it up.
And just FYI:
topic.comments.count
will fire up another query in your view. Change the count to size
Expanding on New row every 3 items -- I'm trying to insert ads in between my Forem (https://github.com/radar/forem) topics -- one in between every 3 topics for the first 3 groups of topics (3 ads in total).
UPDATE
I ended up with this thanks to the answer below, unfortunately it doesn't seem to pass on test as a valid local (can't find topic inside forem/topics/topic):
<% #topics.in_groups_of(3).each_with_index do |grouped_topics, index| %>
<%= render partial: "forem/topics/topic", collection: grouped_topics %>
<% if index < 3 %>
<p>Ad</p>
<% end %>
<% end %>
Live test app (click the big green Run button to test):
http://runnable.com/VFUNK2ho3Fpr8Fp2/forem-with-ads-in-between-topics
File in question: views/forem/forums/show.html.erb
in_groups_of split your array into array of arrays, so that should be:
<% #comments.in_groups_of(3, false).each_with_index do |grouped_comments, index| %>
<% grouped_comments.each do |comment %>
...
<% end %>
<% if index < 3 %>
<%= image_tag "selfie.jpg">
<% end %>
<% end %>
I am working on a RoR WebApp. I'm trying to group results on the search page based on their taxonomy. What I want to do is to show a header for a category and list all results under that category. Something like:
CAT 1
products
CAT2
products
CAT3
.
.
I am trying using the following code:
<% if products.any? %> #products is the list of search results
<%= render :partial=> 'product_listing_feature', :locals => {:scope => scope, :scope_type => scope_type} %>
<div id="ql_product"></div>
<div class="product_rows">
<%taxons.each do |taxon|%> # taxons contains the list of unique categories in products
<div class = "product_row">
<h1><%=taxon%></h1>
<% taxonProducts = Array.new %>
<% products.each do |product| %>
<%#ptaxon = product.get_taxonomy%>
<%if #ptaxon == taxon%>
<% taxonProducts.push(product) %>
<% end %>
<% end %>
<div class ="featured_product_list">
<ul class = "featured_products">
<div class = "page">
<%= render :partial=> 'product_listing', :locals=>{:collection=> taxonProducts} %>
</div>
</ul>
</div>
</div>
<% end %>
</div>
<% end %>
Surprisingly it starts the 2nd category from a new row, but the following categories appeared jumbled up, something like
CAT1
products
CAT2
products CAT3
products
picture would give a better idea.
I am really surprised why it works only for one iteration. Could someone please help me fix this.
Thanks a lot
Way, way too much logic for a view. Just use group_by in your controller, which will give you a mapping of names to arrays of products:
products = Product.includes(:taxon).group_by { |p| p.taxon.name }