I am trying to replace an array of names for a column of names out of a database.
I am new to Ruby on rails so it could be something simple.
This works fine:
<% students = %w(John Paul Ringo George) %>
<% teams = RoundRobinTournament.schedule(students) %>
<td><%= teams %></td>
This i get an error:
<% #players.each do |player| %>
<% students = player.first_name %>
<% teams = RoundRobinTournament.schedule(students) %>
<td><%= teams %></td>
Error:
undefined method `delete_at' for "John":String
Did you mean? delete
delete!
In the RoundRobinModule the "delete_at" what causes the error:
require 'round_robin_tournament/version'
module RoundRobinTournament
def self.schedule(array)
array.push(nil) if array.size.odd?
n = array.size
1.step(n / 2, 1).each do |i|
array.insert(n - i, array.delete_at(i))
end
pivot = array.pop
games = (n - 1).times.map do
day = [[array.first, pivot]] + (1...(n / 2)).map { |j| [array[j], array[n - 1 - j]] }
array.rotate!
day
end
array.push pivot unless pivot.nil?
games
end
end
students is supposed to be an array, yet students = player.first_name makes it a string.
I don't know if this is want you want, but the following should work:
<% students = #players.pluck(:first_name) %> # or #players.map(&:first_name)
<% teams = RoundRobinTournament.schedule(students) %>
<td><%= teams %></td>
Use .pluck if #players holds an ActiveRecord::Relation or .map if it's an array of Player objects.
But, the error tells you exactly what & where the problem is. You just need to pay attention. The code would have crashed earlier but both String and Array respond to .size.
Related
Issue: I am unable to have my API show me the results I want that match my StoreProduct model record stored in the database.
What I want: To display orders that have specific product_id's in them.
I have the following API json response
[[#<ShopifyAPI::LineItem:0x000055ef6161f110 #attributes={"id"=>1959792476209, "variant_id"=>15345627234353, "title"=>"Burton Custom Freestlye 151 37", "quantity"=>1, "sku"=>"", "variant_title"=>nil, "vendor"=>"Burton", "fulfillment_service"=>"manual", "product_id"=>19600013786737, ...
At the last record, you will see "product_id". I have this in in my StoreProduct model as store_product_id. I want to only display the product_id if it matches one i have in my StoreProduct database.
For instance, if I had this information stored in my own model/db, I would do:
#store_products = StoreProduct.all
#store_orders = Orders.where(product_id: #store_products.each {|store_product| store_product.store_product_id})
I tried this in my view:
<% #store_orders.each do |order| %>
<tr>
<% order.line_items.each do |line| %>
<% if line.product_id == #store_products.each {|store_product| store_product.store_product_id} %>
<td><%= line.product_id %></td>
<% end %>
<% end %>
</tr>
<% end %>
Controller:
#store_products = StoreProduct.all
#store_orders = ShopifyAPI::Order.all
And nothing appears.(I am doing this on the front-end before i migrate this to the controller so i can see what is happening)
If i remove the if statement, all of product_id's appear from the orders.
When i tried using a .where, it gives me an error that I am unable to use "where" with the Shopify API.
Question: How can I make it so only orders and product ID's appear that match any of the store_product.store_product_id's I have in the StoreProduct DB?
I have a collection of products users have purchased, grouped by their name, so I can count the number of unique products and how many of each has been purchased:
Controller:
#line_items = Spree::LineItem.joins(:order).where(spree_orders: {state: "complete"})
#products = #line_items.group_by(&:name)
View:
<% #products.each do |name, line_items| %>
<%= name %> - <%= line_items.count %><br>
<% end %>
Is there a way to order the .each loop so that it descends by line_items.count?
Thanks
It will perform better getting the correct data directly from the db:
#products = #line_items.group(:name).order("count_all DESC").count
That will give you the names and counts directly, e.g.
# => { "line_1" => 3, "line_2" => 2, "line_3" => 8 }
There's a bit of Rails magic at work here: the SQL generated using group, order and count will look like:
SELECT COUNT(*) AS count_all, name AS name FROM spree_line_items GROUP BY name ORDER BY count_all DESC
That's where count_all comes from: Rails attaches it to the count column automatically.
Then you can plug this directly into your view:
<% #products.each do |name, line_item_count| %>
<%= name %> - <%= line_item_count %><br>
<% end %>
Alternatively, if you're using the instance variable elsewhere, here's a simple Ruby solution:
#products = #line_items.group_by(&:name).sort_by { |_k, line_items| line_items.count }.reverse
This simply uses sort_by to get records ordered by the relevant count, then reverses to get decending order. There's a good benchmark on doing this here.
Hope that helps - let me know how you get on / if you've any questions.
This is my first time posting a question on this site; be gentle, please. This isn't homework. I'll try to be as concise as possible.
I have a table with 5 keyword columns, a date column, and a user ID column for identifying what user added that specific row of data. My goal is to print and count the number of matched keywords from a row iff:
1) Another row(s) contains those keywords AND has the same date.
2) The user ID for each row is unique.
For example:
Row1=> keyword1:(K1) keyword2:(K2) keyword3:(K3) keyword4:(K4) keyword5:(K5) date:(D1) user_id:(U1)
Row2=> keyword1:(K6) keyword2:(K7) keyword3:(K1) keyword4:(K2) keyword5:(K8) date:(D1) user_id:(U2)
Row3=> keyword1:(K6) keyword2:(K7) keyword3:(K1) keyword4:(K2) keyword5:(K8) date:(D2) user_id:(U2)
Row4=> keyword1:(K1) keyword2:(K2) keyword3:(K3) keyword4:(K4) keyword5:(K5) date:(D2) user_id:(U3)
Output:
K1 (2 times), K2 (2 times), on D1
K1 (2 times), K2 (2 times), on D2
Row3 should be excluded from the first count because even though the words matched, the user was a duplicate.
Here's how I've started:
<% #prophecies.each do |prophecy| %>
<% date1 = prophecy.datetwo %>
<% #prophecies.each do |prophecy| %>
<% if date1.eql?(prophecy.datetwo) == true %>
<tr>
<td><%= prophecy.keyone %></td>
<td><%= prophecy.keytwo %></td>
<td><%= prophecy.keythree %></td>
<td><%= prophecy.keyfour %></td>
<td><%= prophecy.keyfive %></td>
</tr>
<% end %>
<% end %>
<% end %>
But it's nowhere near what I'd like to accomplish. If anyone could even help me sort out the pseudocode for this I'd be happy.
First of all, it's better to do it in your model, not in your view.
You can define methods in your prophecy class something like that
def self.keywords_at_day(date)
#find prophecies for particular dae
prophecies = self.find_by(date:date)
# create hash with keywords for user
user_keywords = {}
prophecies.each do |prophecy|
user_keywords[prophecy.user] ||= []
user_keywords[prophecy.user] << prophecy.keyword
end
# create general array with all keywords
keywords = []
user_keywords.each do |user, kw|
keywords << kw.uniq
end
# count keywords
keywords_count = {}
keywords.each do |keyword|
keywords_count[keyword] ||= 0
keywords_count[keyword] += 1
end
keywords_count
end
def self.keywoards_lists
dates = Prophecy.all.map{|p| p.date}.uniq
keywords_lists = {}
dates.each do |date|
keywords_lists[date] = keywords_at_day(date)
end
keywords_lists
end
You controller
def index
#keywords_lists = Prophecy.keywords_lists
end
View
<%= #keywords_lists.each do |date, keywords_list| %>
<tr>
<td> <%= date %> </td>
<td>
<%= keywords_list.each do |keyword, count| %>
<%= "#{keyword} encountered #{count} times" %>
<% end %>
</td>
</tr>
<% end %>
If it's really not homework, I suggest you to read about MVC, ruby name convention(date_two instead of datetwo), booleans (you don't need "==true" for eql?).
And besides all it's not good type of question for stackoverflow
Cheers
My suggestion is to create a data structure that match your need. BAsically a hash where key is keyword, and content the list of uid that uniquely use your keyword:
r=[]<<{:keyword1=>"K1",keyword2:"K2",keyword3:"K3",keyword4:"k4",:date=>d1,uid:1}
r<<{:keyword1=>"K6",keyword2:"K7",keyword3:"K1",keyword4:"k2",:date=>d1,uid:2}
r<<{:keyword1=>"K6",keyword2:"K7",keyword3:"K1",keyword4:"k2",:date=>d2,uid:2}
(just for test purposes)
then:
r.inject({}) do |sum,aRow|
# loop for all keywords in the row.
[:keyword1,:keyword2,:keyword3,:keyword4,:keyword4].each do |keyword|
# get each entry or create it
sum[aRow[keyword]]=elem=sum[aRow[keyword]]||{}
count=elem[aRow[:date]]||{:users=>Set.new}
count[:users]<<aRow[:uid]
elem[aRow[:date]]=count
end
sum
end
The result if the following:
=> {"K1"=>
{2014-09-04 15:05:21 +0200=>{:users=>#<Set: {1, 2}>},
2014-01-01 00:00:00 +0100=>{:users=>#<Set: {2}>}},
"K2"=>{2014-09-04 15:05:21 +0200=>{:users=>#<Set: {1}>}},
"K3"=>{2014-09-04 15:05:21 +0200=>{:users=>#<Set: {1}>}},
"k4"=>{2014-09-04 15:05:21 +0200=>{:users=>#<Set: {1}>}},
"K6"=>
{2014-01-01 00:00:00 +0100=>{:users=>#<Set: {2}>},
2014-09-04 15:05:21 +0200=>{:users=>#<Set: {2}>}},
"K7"=>
{2014-01-01 00:00:00 +0100=>{:users=>#<Set: {2}>},
2014-09-04 15:05:21 +0200=>{:users=>#<Set: {2}>}},
"k2"=>
{2014-01-01 00:00:00 +0100=>{:users=>#<Set: {2}>},
2014-09-04 15:05:21 +0200=>{:users=>#<Set: {2}>}}
So you know that keyword "K1" has been used with two different date, and by two users (1,2) for first one, and 2 for second date.
Than, it will be easy to display this array.
I have a bunch of objects, and I grouped them by the day they happened.
scope :grouped_by_user_with_total_time, lambda {
group(:user_id, :day).select('user_id, SUM(time_worked) AS time_total, day, editable, approvable, accepted, comments')
}
I also have some methods that change editable, approvable, and accepted. But now since they are grouped, I get this error when trying to approve grouped objects.
Couldn't find TimeLog without an ID
My approve method:
def approve
#time_logs = []
t = TimeLog.find(params[:time_logs])
if t.instance_of?(Array)
#time_logs = t
else
#time_logs << t
end
end
What do I have to change so that the methods can work on all of the hourlogs that are grouped together?
<% #time_logss.each do |timelog| %>
<% if timelog.user_id != current_user.id %>
<tr>
<!--<td><%# check_box_tag 'accept' %></td>-->
<td><%= timelog.id_name %></td>
<td><%= timelog.day.strftime("%B %d, %Y") %></td>
<td><%= timelog.time_total %></td>
<td><%= timelog.state %></td>
<% if timelog.state == "Submitted" %>
<td><%= link_to "Approve", approve_time_sheets_path(time_sheets: timelog), method: :put %></td>
You are trying to combine an aggregate function with the need to access unique data. When you use .select(''), you are telling AR which fields to populate into the object (even attributes that do not exist directly in the database).
If you add in time_logs.*, you'll lose the aggregate on time_worked, since you'll then be forced to add id to the group clause.
What you need to do have 1 instance var with the time_logs and one with the aggregate data:
#time_logs = TimeLog.all
#time_totals = TimeLog.grouped_by_user_with_total_time
Then, in the view, you can pluck out the correct total for each time_log. Although, I'm not clear on how you will be able to relate the specific time_log with it's aggregate equivalent.
I'm new to rails, so forgive me if there is an easy answer. I'm trying to implement an "Alphabet Index" for a table in rails. I want to be able to click on a letter and have the table refresh - containing only the data on which the first letter of the last_name column matches the letter clicked.
My first thought was to generate an array of letter from the database
#visitor_array = []
#v = Visitor.all
#v.each do |visitor|
#visitor_array << visitor.last_name[0,1]
end
#visitor_array.sort!
#visitor_array.uniq!
This code gives me an array which has one of each of the first letters. I used this as my "alphabet". On my view I have the following code
<% #visitor_array.each do |visitor| %>
<%= link_to visitor, alphasort(visitor) %>
<% end %>
The thought here is to run a helper function when the letter is clicked. But here is where I'm stuck.
UPDATE:
Okay, thanks to the comments below, I was able to figure it out. In case anyone else was wondering, this is how it was accomplished.
CONTROLLER
# Create array consisting of the first letter of every visitor's last name
#visitor_array = []
#v = Visitor.all
#v.each do |visitor|
#visitor_array << visitor.last_name[0,1]
end
#Sort array alphabetically in ASC order
#visitor_array.sort!
#Remove duplicate elements
#visitor_array.uniq!
if (params[:letter] != nil)
#visitors = Visitor.order("last_name ASC").where("last_name like ?", params[:letter] +"%" )
else
#visitors = Visitor.order("last_name ASC")
end
VIEW
<% #visitor_array.each do |letter| %>
<%= link_to letter, :controller => "visitors" , :letter => letter %>
<% end %>
Use this to get the list of results for a specific letter:
visitors = Visitor.order("last_name ASC").where("last_name like '?'", letter)
Then on your view:
<% #visitor_array.each do |visitor| %>
<%= link_to visitor(visitor) %>
<% end %>
The syntax might be slightly off but the fundamental idea is there.
I'm not entirely sure what you mean by the last line though...