This code here groups a Users friends by highschool name.
<% #user.friends.group_by(&:highschool_name).map do |hsname, friends| %>
<% next if hsname.blank? %>
<div class="contentbox">
<div class="box-header">
<h3><%= hsname %></h3>
</div>
<ul class="friends-list">
<% friends.map do |friend| %>
<li><%= image_tag(friend.image) %>
<% end %>
</ul>
</div>
<% end %>
But it groups with out any order, I would like to order by highste value. Showing the highest group first and down. Any ideas?
group_by gives you a hash in return. You can sort on count of values before iterating:
groups = #user.friends.group_by(&:highschool_name)
sorted_groups = groups.sort_by{|key, values| values.count}.reverse
sorted_groups.each do |hsname, friends|
# do your thing here
end
Did you try?
#user.friends.group(:highschool_name).order("highschool_name DESC")
Related
I'm trying to split my records in half for display in my menu. The menu is two columns (col-md-4) but the methods I'm using with ODD number of records, puts the larger number on the wrong side (last_half) of my menu. What am I missing?
Menu
<div class="col-md-4">
<ul>
<li class="mega-menu-title">Products</li>
<% first_half(#menu_products).each do |product| %>
<li>
<%= link_to product_path(product) do %>
<span class="text-yellow"><%= product.name %></span> <%= product.subtitle %>
<% end %>
</li>
<% end %>
</ul>
</div>
<div class="col-md-4">
<ul>
<li class="mega-menu-title"> </li>
<% last_half(#menu_products).each do |product| %>
<li>
<%= link_to product_path(product) do %>
<span class="text-yellow"><%= product.name %></span> <%= product.subtitle %>
<% end %>
</li>
<% end %>
</ul>
</div>
<div class="col-md-4">
<!--- non-related code in last column in menu --->
</div>
Application Helper
def first_half(list)
list[0...(list.length / 2)]
end
def last_half(list)
list[(list.length / 2)...list.length]
end
You can use the following:
list.first((list.length/2).ceil) # will convert 1.5 to 2
And
list.last((list.length/2).floor) # will convert 1.5 to 1
The issue you had is that [7,8,9][3/2] returns 8, and the logic 3/2 (list.size / 2) was used in both first_half and last_half.
This is what I ended up doing to get it to work. I had to change the length to a float to_f, then I could get it to test in the console correctly.
def first_half(list)
list[0...(list.length.to_f / 2).ceil]
end
def last_half(list)
list[(list.length.to_f / 2).ceil...list.length]
end
Using .ceil on both methods then allowed the math to work.
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>
In my rails category show controller for categories I have it setup like this
def show
#categories = Category.find_by(params[:name])
end
But when I visit this controller it returns all records of products found in the category instead of single category.
Here is the code in my view controller for category
<div class="grid">
<% #categories.products.each do |product| %>
<%= link_to product_path(id: product.slug, category_name: product.category.name), class: "card" do %>
<div class="product-image">
<%= image_tag product.productpic.url if product.productpic? %>
</div>
<div class="product-text">
<h2 class="product-title"> <%= product.name %></h2>
<h3 class="product-price">£<%= product.price %></h3>
</div>
<% end %>
<% end %>
</div>
What am i doing wrong here?
First of all, for security purposes, you should never trust the params hash to retrieve records. Rails will "make the data safe" if you use a hash as your arguments. Use this code below:
def show
#category = Category.find_by(name: params[:name])
end
Second, usually on a show page, you only want to retrieve one record and therefore the variable should be named as singular. I corrected that above.
Third, it helps if you use proper indenting when posting examples. It makes it easier for us to help you.
Fourth, the line below (I changed #categories to #category) is basically saying: "Now that I have this single category, find all the products associated with it in the products table and put them into the |product| variable for iteration"
<% #category.products.each do |product| %>
I'm not sure what you want to do with the category, but if you keep this line of code, it will always show you all the products. Maybe you only want to show the most recent 3, in which case you could do something like this:
In your controller:
def show
#category = Category.find_by(name: params[:name])
#recent_products = #category.products.order(created_at: :desc).limit(3)
end
In your view:
<div class="grid">
<% #recent_products.each do |product| %>
<%= link_to product_path(id: product.slug, category_name: product.category.name), class: "card" do %>
<div class="product-image">
<%= image_tag product.productpic.url if product.productpic? %>
</div>
<div class="product-text">
<h2 class="product-title"> <%= product.name %></h2>
<h3 class="product-price">£<%= product.price %></h3>
</div>
<% end %>
<% end %>
</div>
You can do this way
in your controller you can write this code
def show
#category = Category.find_by_name(params[:name])
end
and in your view it will work
<div class="grid">
<% #category.products.each do |product|%>
// place your code what you want to display
<% end %>
</div>
I hope it would help you and still if you have any concern please let me know.
I've in my app, posts as ideas, and these ideas belongs to an activity and a status.
And I want to sort them by activity for one status so I did in my controller
#idees_en_place = Idee.where(statut_id= "2")
#activites = Activite.all
And in my view :
<% #activites.each do |activite| %>
<div class="idee en-place col-lg-5" style="background:#<%= activite.color%>">
<h2><%= activite.name %></h2>
<p>
<% #idees_en_place.where(activite_id = activite.id).limit(3).each do |idee| %>
<div class="idee">
<h6><%= link_to idee.title, idee %></h6>
</div>
<% end %>
</p>
</div>
<% end %>
But that doesn't work, in each part of an activity the ideas are not sorted.
I think it's a little mistake but I don't know how to resolve this
#idees_en_place = Idee.where(statut_id= "2")
There are two problems with this code.
First, id is a Integer type (unless you've defined it as String).
Second, its a key value you pass to where clause, and you pass these either as
:status_id => 2 # old hashrocket syntax
or
status_id: 2 # new syntax
The same goes with this part
#idees_en_place.where(activite_id = activite.id)
it should be
#idees_en_place.where(activite_id: activite.id)
In Controller
#idees_en_place = Idee.where(statut_id: 2)
#activites = Activite.all
In View
<% #activites.each do |activite| %>
<div class="idee en-place col-lg-5" style="background:#<%= activite.color%>">
<h2><%= activite.name %></h2>
<p>
<% #idees_en_place.where(activite_id: activite.id).limit(3).each do |idee| %>
<div class="idee">
<h6><%= link_to idee.title, idee %></h6>
</div>
<% end %>
</p>
</div>
<% end %>
I just wanna point out that you will run into an N+1 queries issue, to avoid this you should preload every thing, instead of doing queries in the views.
The controller:
#change if the association name is different
#activites = Activite.includes(:idees)
The view
<% #activites.each do |activite| %>
<div class="idee en-place col-lg-5" style="background:#<%= activite.color%>">
<h2><%= activite.name %></h2>
<p>
<% activitie.idees[0..2].each do |idee| %>
<div class="idee">
<h6><%= link_to idee.title, idee %></h6>
</div>
<% end %>
</p>
</div>
<% end %>
Notes:
I've used the [0..2] format because I wanted to avoid ActiveRecord from doing a new query, another method would be limiting the query using something like this
#activites = Activite.includes(:idees).merge(Idee.limit(3))
Then you won't need to use any limitation in the views, but I haven't tested this, don't have access on a rails machine right now.
I think that the following code will help you:
Since your Idee belong to activity and status that's why you have activity_id and status_id in your Idee table.
you may find out all the idee for a status by using:
Idee.where(:status_id => 2)
and you can sort Idee in Asc or desc order by using order
idees = Idee.join(:activity).where(:status_id => 2).order(:activity_id => :asc)
idees = Idee.join(:activity).where(:status_id => 2).order(:activity_id => :desc)
<% activity_id = -1%>
<#idees.each do |idee| %>
<div class="idee en-place col-lg-5" style="background:#<%= idee.activite.color%>">
<h2><%= idee.activity.name %></h2>
<p>
<% if activity_id != idee.activity_id %>
<% activity_id = idee.activity.id %>
<% counter = 0 %>
<% end %>
<% if counter < 3 %>
<% counter = counter + 1%>
<div class="idee">
<h6><%= link_to idee.title, idee %></h6>
</div>
<% end %>
</p>
</div>
I am trying to get shows on a certain day to show up just for that day and I would like to be able to see what shows are going on in the next couple of days as well.
The View:
<% t = Time.new %>
<h2 class="center" style="color:#2A2C2B"><u><%= t.strftime("%A, %B %e") %></u></h2>
<% #clubs.each do |club| %>
<!-- # <% club.shows.future.present? %> -->
<h1 class="club"><%= link_to club.name, club.website %> </h1>
<% club.shows.future.each do |show| %>
<h3 class="center"><%= show.pretty_start_time %></h3>
<% show.comedians.each do |comedian| %>
<div>
<ol>
<h4 class="comedian"><%= link_to simple_format(comedian.name),comedian_path(comedian) %></h4>
<p class="bio"><u><%= comedian.bio %></u></p>
</ol>
</div>
<% end %>
<% end %>
<%- end -%>
The Comedy Hub Controller:
class ComedyHubsController < ApplicationController
def show
#clubs = ComedyClub.all
end
end
This might work:
<% shows.goup_by{|show| show.date}.each do |dategroup| %>
<# do something to indicated the group up here? %>
<%= dategroup.each do |show| %>
<li> <%# put details here %> </li>
<% end %>
<% end %>
Assuming, there is a DateTime column on Show called start and the ComedyClub model has a a has_many :shows and the Show model has the belongs_to :comedy_club association defined
In your ComedayHubsController#show method, do the following query
#clubs = ComedyClub.join(:shows).where("shows.start >=?", DateTime.now).order("shows.start ASC")
Now only clubs with shows in the future will be sent to the view and already ordered by start.