Storing and retrieving session objects - ruby-on-rails

I'm storing an object in hash which is in session object like this :
hash_key = ImportantData.new
hash_key.test_id = params[:test_id]
hash_key.user_id = params[:user_id]
session[:important_data] ||= {}
session[:important_data][hash_key] = nil
And then I print this map session[:important_data][hash_key] in my other controller and try to check whether the object is in there or not like this :
hash_key = ImportantData.new
hash_key.schedule_id = #test.id
hash_key.user_id = #user.id
in_hash = session[:important_data].has_key?(hash_key) unless session[:important_data].nil?
in_hash is always false to me, what am I doing wrong? and is there a better way to do this?

In Ruby, hash keys work by equality. You can store and retrieve a value in a hash as long as the key you're using is equal to the key that's stored.
For instance:
hsh = { 'hello' => 'world' }
p hsh['hello'] #=> "world"
'hello'.eql? 'hello' #=> true
You can retrieve the value because the same value string is always eql? in Ruby.
This is not the case for most objects:
class Example; end
object1 = Example.new
object2 = Example.new
object1.eql? object2 #=> false
Therefore, the key that you use to store in the hash must be eql? to the one that you're using to retrieve. eql? is equivalent to == and equal?.
You're creating two instances of ImportantData, which will not be equal to each other. It looks like you can accomplish what you want with a single hash key:
hash_value = ImportantData.new
hash_value.test_id = params[:test_id]
hash_value.user_id = params[:user_id]
session[:important_data] ||= hash_value
puts session[:important_data].class.name #=> ImportantData
session[:important_data].test_id #=> puts out value of test_id

I think you should assign it like this
session[:important_data][:hash_key] = hash_key
and access it
session[:important_data][:hash_key]

Related

Is there an equivalent method for Ruby's `.dig` but where it assigens the values

Let's say we're using .dig in Ruby like this:
some_hash = {}
some_hash.dig('a', 'b', 'c')
# => nil
which returns nil
Is there a method where I can assign a value to the key c if any of the other ones are present? For example if I wanted to set c I would have to write:
some_hash['a'] = {} unless some_hash['a'].present?
some_hash['a']['b'] = {} unless some_hash['a']['b'].present?
some_hash['a']['b']['c'] = 'some value'
Is there a better way of writing the above?
That can be easily achieved when you initialize the hash with a default like this:
hash = Hash.new { |hash, key| hash[key] = Hash.new(&hash.default_proc) }
hash[:a][:b][:c] = 'some value'
hash
#=> {:a=>{:b=>{:c=>"some value"}}}
Setting nested values in that hash with nested defaults can partly be done with dig (apart from the last key):
hash.dig(:a, :b)[:c] = 'some value'
hash
#=> {:a=>{:b=>{:c=>"some value"}}}

Kind of ugly- default value for non-existent hash key?

I'm working with an API that returns a hash to represent a product:
prod = API.getProduct(id)
prod["name"] => "Widget"
The problem arrises because not all products contain identical attribute pages, so I find myself doing a lot of one-off error catching- some products will have a key for size or color, some won't.
What's the easiest way to get to prod["non-existent attribute"] => "NA"?
As Dave Newton said, you can add the default value to the hash constructor:
hash = Hash.new { |hash, key| hash[key] = "NA" }
hash[:anything] == "NA" # => true
Or use the #default method:
hash = Hash.new
hash.default = "NA"
hash[:anything] == "NA" # => true
EDIT The quick syntax for setting the default value when initializing the hash is:
hash = Hash.new("NA")
hash[:anything] == "NA" # => true
Take a look at this: http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-default
You can use prod.default = "NA".

How to check if any of the Objects have the same data for the same field?

Is there a sweet irb line of code that could check is any of the Object's have the same data in their field?
For example, could I see if any of the Object's have the same email? Alternatively, check and see if any of the objects are not unique?
You could try it this way:
Create a hash with all instance variables as key-value pairs and then compare the hashes:
Assuming you have two objects a and b:
hash_a = a.instance_variables.inject({}){|res,v| res[v] = a.instance_variable_get(v); res }
hash_b = b.instance_variables.inject({}){|res,v| res[v] = b.instance_variable_get(v); res }
if hash_a == hash_b
puts "equal"
else
puts "not equal"
end
Edit:
If you are talking about Rails Models then you need this:
if a.attributes == b.attributes
puts "equal"
end

Ruby on Rails 2 search string in Hash

I need help with this...
I have a hash like this:
#ingredients = Hash.new
#ingredients[1] = "Biscottes Mini(recondo)"
#ingredients[2] = "Abadejo"
#ingredients[3] = "Acelga"
#ingredients[4] = "Agua de Coco"
#ingredients[5] = "Ajo"
#ingredients[6] = "Almidón de Arroz"
#ingredients[7] = "Anillos Con Avena Integral cheerios (nestle)"
#ingredients[8] = "Apio"
I need to search into that hash in order to find "Biscottes Mini(recondo)" when I write "scotte"
Some help?
Thk!
Why do you use a Hash here and not an Array? You do not seem to use other keys than integers.
Anyway, this solution works for both Array and Hashes:
search_term = 'scotte'
# you could also use find_all instead of select
search_results = #ingredients.select { |key, val| val.include?(search_term) }
puts search_results.inspect
See http://ruby-doc.org/core/classes/Enumerable.html#M001488
You can call select (or find if you only want the first match) on a hash and then pass in a block that evaluates whether to include the key/value in the result hash. The block passes the key and value as arguments, so you can evaluate whether either the key or value matches.
search_value = "scotte"
#ingredients.select { |key, value| value.include? search_value }

returning an array that contains an array and hash in ruby method?

HI
is it possible to return an array that contains an array and hash from a method in ruby?
i.e
def something
array_new = [another_thing, another_thing_2]
hash_map = get_hash()
return [array_new, hash_map]
end
and to retrieve the array:
some_array, some_hash = something()
thanks
Sure, that's perfectly possible and works exactly as in your example.
You will only ever be able to return one thing. What you are returning there is an array containing an array and a hash.
Ruby methods can be treated as if they return multiple values so you can collect the items in an array or return them as separate objects.
def something
array_new = Array.new
hash_new = Hash.new
return array_new, hash_new
end
a, b = something
a.class # Array
b.class # Hash
c = something
c.class # Array

Resources