Rails hash TypeError - ruby-on-rails

I have the following hash, #example_set that I want to get and store data from.
{"Example1"=>{:campaign=>"Example1", :impressions=>12, :conversions=>1, :clicks=>14,
"Example2"=>{:campaign=>"Example2", :impressions=>4042, :conversions=>2, :clicks=>11}}
I want to do the following to combine the total conversions but am running into a TypeError: no implicit conversion of Symbol into Integer.
#totals = 0
#example_set.each do |report|
#totals += report[:conversions]
end
Ideally this would set #totals to 3
I am new to rails so any additional detail and instruction would be much appreciated (especially if there is a better way to do this.. which I assume there is)

You want to iterate over values of that map, I think.
#example_set.values.each

Related

ruby on rails pass a value to .last()

I'm pretty new to ruby on rails, so I'm probably missing some syntax. Big picture I am trying to get the value for a specified percentile. Conceptually I am taking my table 'Scores', sorting it, getting the last 'x' values, and then taking the first value. I can't seem to figure out how to pass 'x', which is based on the length of the dataset to the chain.
def get_percentile()
record_count = Scores.count(:id)*0.05
record_threshold = record_count.round()
Score_percentile = Scores.order(:points).last(record_threshold).first().points
return Score_percentile
end
get_percentile
If I just enter .last(20) this works as I expect, so I just don't know how to pass the variable.
Thanks.
You may be passing a 0 into your .last() function with your rounding.
There are a variety of options to make sure you pass at least a 1
[record_threshold, 1].max will give you at least 1. https://apidock.com/ruby/Enumerable/max
Changing .round() to .ceil() rounds up in all instances. https://apidock.com/ruby/Float/ceil

how to use dynamic variable for symbols in ruby where statements

I dont how to accomplish this problem.
I faced with this problem 3 times and each time I put it in my todo list but even tho I tried to find a solution I couldnt.
For examples,
I m trying to create a query with dynamic variables of this example;
User.search(first_name_start: 'K')
there are 3 arguments in this example;
1)first_name - My model attribute
2)start - Query type (start/end/cont )
3)'3' - value
I was able to create dynamic ActiveRecord using static symbols but how am I suppose to make dynamic input
Thanks in advance
EDIT: ADDITIONAL INFORMATION
let me show you a some kind of pseudo-code
varArray.each_with_index |x,index|
queryString=varArray[i]+"_"+filterArray=[i] #lets say varArray[i], this will be first_name, an actual model attribute/a column in my db
#and filterArray like /start/end/with a filter type
#and finally valArray a string value like 'geo' or 'paul'
User.where(queryString valArray[i]).result
I tried to use send(variable) but that didnt help me either, so i dont how should i proceed,
This is one of a few cases where new fancy Ruby 1.9 syntax for defining hashes doesn't cut it. You have to use the traditional hashrocket (=>) that allows you to specify not only symbols, but any arbitrary values as hash keys:
column = "#{first_name}_size_#{query_type}".to_sym
User.where( column => value )
AFAIK, ActiveRecord is able to accept strings instead of symbols as column names, so you don't even need to call to_sym.

Rails validation scope of serialized text array

I have a Rails model that has a field array_field, which is a serialized text array. I want the combination of this array value and the value of another_field to be unique.
Should be straightforward, no?
class Foo < ActiveRecord::Base
validates_uniqueness_of :array_field, scope: [:another_field]
serialize :filters, Array
end
This doesn't work. However, if I switch them around in the validations,
validates_uniqueness_of :another_field, scope: [:array_field] works as expected.
Can someone explain why this is the case? Is this expected behavior?
The Postgres error for the former setup when array_field's value is nil or [] is this:
PG::SyntaxError: ERROR: syntax error at or near ")"
LINE 1: ...other_field" = 103 AND "foo"."array_field" = ) LIMIT 1
When array_field is [[1, 2], [3, 4, 5]] (a sample multiarray I was using), it's:
PG::UndefinedFunction: ERROR: operator does not exist: text = integer
LINE 1: ...other_field" = 103 AND "foo"."array_field" = 1, 2, 3, 4, 5) LIMIT 1
It seems that Rails doesn't know how to translate the serialized object for this query. Am I missing something or is this a bug?
Edit: This is occurring in Rails 4.0.2.
Second Edit:
Clarification: I understand why this is happening (Rails has custom logic for list queries), and I'm using both a custom validator to manually perform the serialization before validating and a custom serializer to avoid problems with comparisons of Yaml strings (as detailed in my other question here).
At this point I'm mostly just wondering why validates_uniqueness_of treats the primary field differently from the scope fields, and am hoping someone can shed some light.
I can't explain why the validations work one way around, but not the other.
But I think basically your problems are due to the fact that serialize only defines that an attribute is to be serialized using Yaml on save and deserialized upon load.
In other words: the only thing you say by doing serialize :filters, Array is that
when saving a Foo, serialize it's filters attribute using Yaml first,
when loading a Foo from the DB, make sure that the value of the
filters attribute is an Array after deserialization, otherwise raise an exception
It does not affect how queries are constructed. Instead, Rails' usual rules for queries are used. So an array is converted into a comma separated list of numbers. This makes sense for example when constructing a LIKE query. This is the reason why the query fails. The DB field is a string but you're trying to compare it to a list.
I haven't used native PostgreSQL array columns with Rails 4, but my guess is that these issues would solved if you used those instead a serialization-type solution. You get the added benefit of being able to search within the contents of arrays on the DB level.

jRuby / Rails sort hash by another hash value

I have a hash that will render my html differently based on a particular variable. The variable is within the hash. So I am wondering how I can pass a hash value to a group by. to sort the rest heres what I am trying, maybe this will explain it better than me wording it.
<% grouped = svcs.group_by { |svc| svc[val[:sorttype]] } %>
val is a multidimensional hash. the first 2 key value pairs sorttype and one other are simple key and value, the 3rd piece (svcs) contains the equivilent of a 2D hash. Which if I manually type the type of sort I want to apply to it for the group by it works ie:
<% grouped = svcs.group_by { |svc| svc[:service_name] } %>
in PHP i know in a similar instance I can pass a variable of some sort to something like this and have it work. I assume such is the case here. However Im not sure how to put the variable in. Cause all the ways Ive tried don't work
It depends a little.
Rails' has a HashWithIndifferentAccess that will not distinguish between string and symbol keys; if you're using one of those, it should work as-is.
If it's not, it depends what the val entries are--if they're strings, convert to a symbol using to_sym, e.g., svc[val[:sorttype].to_sym].

activerecord sum returns a string?

This seems very strange to me, an active record sum returns a string, not a number
basket_items.sum("price")
This seems to make it work, but i thought i may have missed something, as this seems like very strange behaviour.
basket_items.sum("price").to_i
According to the (rails 2.3.9) API:
The value is returned with the same data type of the column, 0 if there’s no row
Could your price column be a string or text?
https://github.com/rails/rails/pull/7439
There was a reason it returned a string - calling to_d on a Fixnum in Ruby 1.8 would give a NoMethodError. This is no longer the case in Ruby 1.9 so it's probably okay to change.
ActiveRecord sum:
Difference:
1) basket_items.sum("price")
It will also sum non integer also and it will return non integer type.
2) basket_items.sum("price").to_i
This above will convert into integer.
# File activerecord/lib/active_record/relation/calculations.rb, line 92
def sum(*args)
if block_given?
self.to_a.sum(*args) {|*block_args| yield(*block_args)}
else
calculate(:sum, *args)
end
end
Calculates the sum of values on a given column. The value is returned with the same data type of the column, 0 if there’s no row.
http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-sum
Github:
https://github.com/rails/rails/blob/f8f4ac91203506c94d547ee0ef530bd60faf97ed/activerecord/lib/active_record/relation/calculations.rb#L92
Also see, Advanced sum() usage in Rails.

Resources