I need to iterate through a database table where it's conditions will change:
<%# if #story.category == 5 %>
<% #users.where(generalLabour: 1).find_each do |user| %>
<% else %>
<% #users.each do |user| %>
.... Iterate and display data.....
So I need to do something like this, unfortunately this does not seem to work as I cannot run statements like this alongside else statements
I also need to do integer comparisons:
<% #users.where(starttime: > 12 ).find_each do |user| %>
How I do something like this?
Maybe I should do all this in Javascript instead of rails?
Try this
query= ""
if #story.category == 5
query = "generalLabour = 1"
elsif #story.category == 4
query = "generalLabour = 2"
elsif #story.category == 6
query = "generalLabour = 3"
end
#users.where(query).each do |user|
.........
end
query= ""
if #story.category == 5
query = "SaturdayS <= #{story.startTime}"
elsif #story.category == 4
query = "SaturdayE >= #{story.endTime}"
end
#users.where(query).each do |user|
.........
end
You can use a hash with mappings:
x = { 5 => 1, 4 => 2, 6 => 3 }[#story.category]
Or use case statement (which is the ruby version of switch):
x = case(#story.category)
when 5
3
when 4
2
when 6
3
else
raise "Doh! I did not think of this."
end
But it is very likely that you are just doing it wrong. Hardcoding IDs in your application is not a good solution and you should instead solve this by setting up a proper association and getting the related items through it.
Related
I am working on a kind of order where I have multiple amount in different currencies in just one attribute. So am trying to make sum on different currencies inside that attribute using other attributes in the table, which works fine but outputs the result as a count of all the rows instead of just showing the sum of the random values calculated.
orders_controller.rb
module Admin
module Statistic
class OrdersController < BaseController
def show
#orders_grid = ::Statistic::OrdersGrid.new(params[:statistic_orders_grid]) do |value|
value.page(params[:page]).per(20)
end
#assets = #orders_grid.assets
##fee_groups = {:fee => #assets.sum(:fee)}
#fee_groups = {
:fee => #assets.sum{|t|
olaoa = t.type
market_string = t.currency
base_currency = market_string.slice(0..2)
quote_currency = market_string.slice(3..5)
if olaoa == 'OrderBid' and base_currency == 'btc'
"#{ t.fee.to_s + ' ' + base_currency.upcase }"
elsif olaoa == 'OrderAsk' and quote_currency == 'ngn'
"#{ t.fee.to_s + ' ' + quote_currency.upcase }"
end
}
}
#orders_filter = true
#orders_group = true
end
end
end
end
summary.htm.slim
.panel.panel-default
.panel-heading
h4.panel-title.row
a data-parent="#filter-accordion" data-toggle="collapse" href="#summary"
span.col-xs-8.text-muted = t('admin.statistic.summary')
span.col-xs-4.text-right.text-muted = t('admin.statistic.click-to-expand')
#summary.panel-collapse.collapse
.panel-body
.datagrid-groups
- if !#orders_group
- if groups
- groups.each do |key, val|
.datagrid.group.row
span.col-xs-2.title = t("admin.statistic.#{controller_name}.#{controller.action_name}.#{key}")
span.col-xs-10.value = val
- if #orders_group
/ Summary Count Loop
- if groups
- groups.each do |key, val|
.datagrid.group.row
span.col-xs-2.title = t("admin.statistic.#{controller_name}.#{controller.action_name}.#{key}")
span.col-xs-10.value = pluralize(val, 'Order')
/ Summary Fees Loop. This is the Fee loop causing problem if am rigth and I dont know how to fix this.
- if #fee_groups
- #fee_groups.each do |key, val|
.datagrid.group.row
span.col-xs-2.title = t("admin.statistic.#{controller_name}.#{controller.action_name}.#{key}")
span.col-xs-10.value = val
The result of the code
So as you can see it renders 0.0BTC 5 times because the filter only has 5 orders. How do i deal with this. I want just the sum of all BTCs to show in the result instead of showing it 5 times.
Any help will be appreciated.
Because you sum strings in you're #fee_groups query that will results in putting strings next to each other instead of a total amount.
If you call it like this
#fee_groups = { fee: #assets.sum{|t| t.fee}}
You will get the total sum of you're assets.
I was handed a project from someone else, it's in Ruby On Rails, which I know VERY LITTLE. Basically, there is an EXPORT button, that the user clicks to send data to a CSV. I am tasked with sending this data to the view to be seen in HTML. (Thinking I could use dataTables). I have tried following examples, such as:
#example = StudentGroup.where(survey_id: #survey.id).order("groupNum")
and then using <%= #example %> in the view just to see the data and I get nothing. (Also extremely new to MySQL). I'll post the method, if ANYONE can help me, I'd very much appreciate it.
def download_results
if (user_signed_in?)
else
redirect_to new_user_session_path
end
#survey = Survey.find(params[:survey_to_view])
filename = #survey.name + " - " + Date.today.to_formatted_s(:short)
require "csv"
CSV.open(#survey.name+".csv", "wb") do |csv|
csv << [filename]
StudentGroup.where(survey_id: #survey.id).order("groupNum")
csv << []
csv << ["Summarized Results"]
csv << ["UCA","Group Number","Criteria 1","Criteria 2","Criteria 3","Criteria 4","Criteria 5","Criteria 6","Criteria 7","Criteria 8","Overall Team Contribution","Average(Would Work With Again)","Average(C1..C8)","Overall Team Contribution MINUS Average(C1..C9)"]
questions = #survey.questions
numQuestions = 0
questions.each do |q|
if(q.question_type != 2 && q.question_type != 4)
numQuestions = numQuestions+1
end
end
groups.each do |g|
answersCount = Answer.where(student_group_id: g.id).count
if(answersCount == numQuestions && answersCount != 0)
othersInGroup = StudentGroup.where(groupNum: g.groupNum, survey_id: #survey.id).order("groupNum")
size = othersInGroup.count-1
arr = []
criteria = SurveyQuestionDatum.where("number > 24 AND number < 35")
multiAvg = 0
teamCont = 0
criteria.each do |c|
avg = 0
othersInGroup.each do |o|
a = Answer.where(survey_question_datum_id: c.id, student_group_id: o.id).first
if(o.uca != g.uca)
if(a.nil?)
size = size-1
else
avg = avg + a.answer[g.uca].to_i
end
end
end
avg = avg.to_f/size
if(c.number == 33)
teamCont = avg
end
if(c.number < 33)
multiAvg = multiAvg+avg
end
arr << avg
end
multiAvg = multiAvg.to_f/8
arr << multiAvg
arr << teamCont-multiAvg
arr.insert(0,g.uca, g.groupNum)
csv << arr
end
end
csv << []
csv << []
csv << ["Raw Student Answers"]
groups = StudentGroup.where(survey_id: #survey.id).order("groupNum")
size = groups.count
csv << ["UCA", "F-Number", "Group Number"]
groups.each do |g|
answersCount = Answer.where(student_group_id: g.id).count
if(answersCount == numQuestions && answersCount != 0)
othersInGroup = StudentGroup.where(groupNum: g.groupNum, survey_id: #survey.id).order("groupNum")
csv << []
csv << [g.uca, g.FNum, g.groupNum]
answers = Answer.where(student_group_id: g.id)
csv << ["Question Number", "Question", "Answer"]
answers.each do |a|
datum = a.survey_question_datum
question = datum.question
#question_types = {"0" => "short", "1" => "paragraph",
#2" => "title", "3" => "fivept", "4" => "fixed",
#5" =>"ranking", "6"=>"tenpoints","7"=>"hundredpoints"}
ansText = ""
if(question.question_type == 0)
ansText = a.answer
elsif (question.question_type == 1)
if(question.rule == 'perMember')
othersInGroup.each do |o|
ansText = ansText+"#{o.uca},#{a.answer[o.uca]},"
end
elsif(question.rule == 'default')
ansText = a.answer
end
else (question.question_type == 3)
othersInGroup.each do |o|
ansText = ansText+"#{o.uca},#{a.answer[o.uca]},"
end
end
ansText = ansText.chomp(',')
ansText = ansText.split(',')
ansText.insert(0,datum.number,question.question_text)
csv << ansText
end
end
end
end
send_file(#survey.name+".csv", :filename => filename+".csv")
end
You need a new controller action. Take a look at http://guides.rubyonrails.org/layouts_and_rendering.html
Create an index (or show, or whatever you want to call it, maybe example) action. Make sure it is in your routes.
http://guides.rubyonrails.org/getting_started.html#adding-a-route-for-comments
do not use the download_results code.
set your #example variable the way you were trying to do.
create a view for your index action
add the data to your index view.
If you put code in your download_results method (action) it will never get rendered because of the send_file method call.
Did you create a brand new controller / action / view? Did you use generators? Have you really practiced doing this setup exactly the way the examples, videos, tutorials say to do it? If you have, you have seen how all the pieces (models, controllers, actions, views) come together. You should have seen how render statements come into play. Do that, exactly as the tutorials say to do it and you will get the idea.
If you want to use the same content that the download action uses, refactor the code to extract a method that is used both actions.
This is related to respond_to part, check the docs.
send_file(#survey.name+".csv", :filename => filename+".csv")
Your code above simply means you click the button, the controller will respond you with a csv file. So, if you want a html, the controller should be able to respond to html as well.
I have a students collection result set and I need following.
Display names should be resolved following these rules: If there are no other students in the collection with the same first name, their display
name should be just their first name.
If there are multiple students in the collection with the same first name, their display name should be their first name followed by a space and their last initial(e.g. “John Smith” would resolve to “John S”)..
Try this
#results.each do |object|
displayname = (#results.select { |filter_object| filter_object.first_name == object.first_name }.count > 0) ? object.first_name : object.first_name + " " + object.last_name.initial
end
here's an example, this might not specifically be what you need (this kinda sounds like homework), but hopefully it gives you an idea.
# in Student model
attr_accessor :display_name
# in controller
students = Student.all
students.each do |student|
if students.count { |s| s.first_name == student.first_name } > 1
student.display_name = s.first_name
else
student.display_name = "#{student.first_name} #{student.last_name[0].upcase}"
end
end
# in view
<% students.each do |student| %>
<%= student.display_name %>
<% end %>
First find out duplicate first names.
dup_first_names = Student.select(:first_name).group(:first_name).group(:first_name).having("COUNT(*) > 1").uniq.pluck(:first_name)
Then for each student check whether the first name is in the dup_first_names array.
Student.all.each do |s|
if dup_first_names.include?(s.first_name)
puts "#{s.first_name} #{s.last_name.first}"
else
puts "#{s.first_name}"
end
end
I have created a loop, to calculate a total rating of a record. To do this I am first looping through all the child records (ratings), extracting the rating from each row, adding it to the total and then outputting the total.
<% total = 0 %>
<% for ratings in #post.ratings %>
<% total = (total + ratings.rating) %>
<% end %>
<%= total %>
My question is, simply, Is this the rails way?
It achieves the desired result, although needs 5 lines to do so. I am worried I am bring old habits from other languages into my rails project, and I am hoping someone could clarify if there is an easier way.
The following, preferably in the controller, will do it succinctly:
#rating = #post.ratings.sum { &:rating }
If that seems cryptic, you might prefer
#rating = #post.ratings.inject(0) { |sum, p| sum + p.rating }
Note, however, that this will fail if any of the ratings are null, so you might want:
#rating = #post.ratings.inject(0) { |sum, p| sum + (p.rating || 0) }
You should generally keep logic out of your views. I would put that code in a helper or a controller, and the call a method to calculate the total
Put the following in your controller, then you just need to use #rating in your view:
total = 0
#rating = #post.ratings.each { |r| total += r.rating }
Or you could move it into the Post model and do something like:
def self.total_rating
total = 0
ratings.each { |r| total += r.rating }
total
end
and then simply call #post.total_rating
I have an array of objects and I need to find the last element that matches a specific condition. I tried to do it with each_reverse, but it ended up with too much of a code:
matching_item = nil
items.reverse_each do |item|
if (item.type_id == 10)
matching_item = item
break
end
end
Is it possible to make it shorter?
Try:
matching_item = items.reverse.find{ |i| i.type_id == 10 }
I would probably use Array#select and return the last match:
matching_item = items.select {|i| i.type_id == 10}.last
Leave off the .last if you decide you want all matches:
matching_items = items.select {|i| i.type_id == 10}
items.reverse_each.detect{|item| iterm.type_id == 10}
#or
items[items.rindex{|item| item.type_id == 10}]