how to store multidimensional array value - ruby-on-rails

I have an store which can be set directly as follows
self.xxx_bias_store[i][j] = [7,11]
where xxx can be different names
How do I set this using send. I have tried
self.send("#{name}_biases_store[#{i}][#{j}]=".to_sym, [7,11])
but this has no effect. Also interested in how to retrieve value i.e.
send("#{name}_biases_store[#{i}][#{j}]".to_sym)

I'm not quite sure why you're trying to use send for this, and looking at your comment I'm not convinced you're actually asking the right question but regardless, here's how this works.
The methods you're concerned with look like this:
class Array
def [](index)
# Look up the element of the array at index
end
def []=(index, value)
# Set the element of the array at index to value
end
end
thing[5] calls the [] method with argument 5 - that is, it sends the method [] to the receiver thing with the argument 5. Similarly, thing[5]=1 calls the []= method with arguments 5 and 1
A multi-dimensional array is just an array made up of other arrays, so...
thing = [[1,2], [3,4]]
p thing.send(:[], 1) # => [3,4]
p thing.send(:[], 1).send(:[], 0) # => 3
thing.send(:[], 1).send(:[]=, 0, 5)
p thing # => [[1,2], [5,4]]

send("biases_store[#{i}][#{j}]".to_sym)
There's your error, thinking that biases_store[i][j] is one long complex method name. It's not. biases_store is a method, which returns something. And then you call method [] on that value which gets you yet another object. On which you call method [] again.
dynamic_property_name = 'biases_store'
send(dynamic_property_name)[i][j] = whatever
Or, same code rearranged for easier understanding
store = send('biases_store')
store[i][j] = whatever

Related

Ruby - method changes input variable value

I'm new to Ruby and I'm having trouble understanding what's happening in this method.
I make this call in a Rails controller -
#arr = SomeClass.find_max_option(params[:x], #pos, params[:y], some_var)
I'm trying to return the value to #arr, which happens successfully, but manipulations I make to #pos within that method are being brought back as well; the value of #pos changes when I'm only trying to get the value for #arr.
Here's more details on the method
#before going into the method
#pos = [a,b]
def self.find_max_option(x, pos, y, some_var)
pos.collect! { |element|
(element == b) ? [c,d] : element
}
end
#new value of pos = [a, [c,d]] which is fine for inside in this method
... #some calculations not relevant to this question, but pos gets used to generate some_array
return some_array
But when the method is finished and gets back to the controller, the value of #pos is now [a,[c,d]] as well.
What's going on here? I thought that pos would be treated separately from #pos and the value wouldn't carry back. As a workaround I just created a new local variable within that method, but I'd like to know what this is happening
#my workaround is to not modify the pos variable
pos_groomed = pos.collect { |element|
(element == b) ? [c,d] : element
}
end
Instead of using collect!, just use collect (without the !). So, rewrite your method as:
def self.find_max_option(x, pos, y, some_var)
pos.collect { |element|
(element == b) ? [c,d] : element
}
end
When using the ! version of collect, you are replacing each element with the value returned by the block. However, when using collect without !, a new array is created, and the object where collect is being called it doesn't get changed. See the docs:
collect! vs collect
Using ! at the end of a method name is a common practice in Ruby. This question is related and would be worth taking a look.
You are using the destructive version of collect.
Destructive methods change the object on which the method is called, while non-destructive methods return new objects.
Ruby developers tend to call these methods 'bang methods', because the convention is that destructive methods have the ! suffix.
pos.collect! # changes pos and returns pos
pos.collect # creates a new object
Your workaround only works because you use the non-destructive collect, while the original code uses collect!
pos.collect do |element|
(element == b) ? [c,d] : element
end
Should work just fine.
As to why the object changes outside of the method:
In ruby, when you pass an argument to a method, you are actually passing the reference to the object.
So passing an array into a method doesn't make a copy, but simply passes the reference to original array.
There is no way to 'pass by value' but you can create a copy yourself with dup or clone, if you really have to.

correct way of modifying a passed argument in the same way for many objects

I have some rails services which (depending on the service) accept a specific type of object, an Array of that object, or an ActiveRecord::Relation of that object.
So:
FooService accepts Foo objects, BarService accepts Bar objects, etc.
But..all the service objects want to massage what is passed in into an array of their given objects.
within the scope of the called service method I could do this pretty easily.
I was trying to DRY things up and make a method to do this for all services, because each of them had the same chunk of code. Unfortunately, I run into issues with Ruby.
For example:
def change_obj(element)
element = [element]
end
blah = "hello"
change_obj(blah)
puts blah.class.to_s #I want it to be an array with the string in it now.
I understand why it doesn't work. But, I don't have a clear idea of what the correct way to do this is.
Ideally I want something like:
class BarService < Service
def initialize(foo)
#foo = foo
end
def do_something(bars)
massage_to_array(bars) #method inherited from Service. if bars is an ActiveRecordRelation, convert it to array..if bars is a singular object, flip it to an array with that object as the sole element.
process_array_of_bars(bars)
end
end
bars = massage_to_array(bars)
process_array_of_bars(bars)
as long as you are modifying passed object - ruby will keep the reference and update contents of that object and not create new object. For example if you pass an array as argument and then add element to an array inside the method - ruby will add element to the object that was passed in, but if you re-assign value to the object, then ruby will remove the reference to passed object and create new object in the local scope and add reference to it to the variable name.
That being said, you can still achieve similar result by creating class that will acts as a proxy. Remember ruby will maintain reference to original object as long as you dont re-assign the variable name to new variable. For example
class ArgProxy
attr_accessor :arg_object
def initialize(arg=nil)
self.arg_object = arg
end
end
def some_method(arg_proxy)
arg_proxy.arg_object = [arg_proxy.arg_object]
end
arg_proxy = ArgProxy.new("qwerty")
some_method(arg_proxy)
arg_proxy.arg_object #=> ["qwerty"]

Trouble on finding a class object in a array of classes

I am using Ruby on Rails 3.0.7 and I would like to understand how to handle the following code in order to retrieve a class objects with a specified id.
In my view file I have:
#records = Users.all # This returns an array (class)
In another file, a partial template, I would like to retrieve, for example, the user with id 1, but if I make this:
#records.find(1)
I get an enumerator (class) of all records:
<Enumerator: [<Users id: 1, ... ] >
How can I find the user with id 1 (or other ids) "a là Ruby on Rails Way"?
UPDATE
I use #records = Users.all in a view file because I aim to minimize calls to the database since I need to iterate almost over all records and check them existence. If I do for example:
some_hash.each { |key, value|
put User.find(value)
}
and I go in the log file, I will see a lot of database requests.
Even though this is probably quite slow, and I suspect there are some less than optimal designs in the app you're working on (not judging, we've all been there), Array#index seems to be what you're looking for:
#records[#records.index{|user| user.id == 1}]
Edit
Although if you need to do something for every user, and you need to access them by id quickly, I'd probably do something like this in your controller. Even if it's not really faster, it's much more readable (to me anyways):
#users_hash = {}
User.all.each{|user| #users_hash[user.id] = user}
Then in your views you can do:
#users_hash[id].username
Use User.scoped instead of User.all. #all will immediately query the database and return an array, whereas #scoped will return an ActiveRecord::Relation object which you can chain further queries. In this case, the database won't be hit until you try and somehow inspect or enumerate the result
Actually you're mistaken. #records.find(1) is returning an object of the class Enumerator (which is not the same as the class Enumerator itself).
The problem here is that, as you've noted, #records is an Array, not an ActiveRecord object, and Array#find (inherited from Enumerable#find--which, when not given a block, returns an object of class Enumerable) is not the same method as ActiveRecord::Base#find (i.e. User#find).
What you should do is, in your controller, pick out the one user record you want:
#user = User.find 1
...and then use #user directly in your template. Generally you should avoid doing ActiveRecord lookups (e.g. find) in your templates. That kind of logic should happen in your controller.
Last time for such case I ended up doing like this:
#assignments = Assignment.find_by_sql(' ... ')
#assignments.find(id: 1).first

proxy_reflection equivalent on ActiveRecord::Base#find?

I'm trying to make a helper which automatically picks the correct partial based on the types of objects returned by either ActiveRecord::Base#find or an association. Unfortuneatly I can't just look at the first element of the returned array because I want to pick the correct one in this case as well. If you call an association, it returns a proxy with the proxy_reflection method, which is exactly what I want, but it doesn't exist on the result of ActiveRecord::Base#find :(.
Example:
association_posts = Author.find(1).posts
association_posts.proxy_reflection.class_name # Returns "Post"
all_posts = Post.find(:all)
all_posts.proxy_reflection # no method exception, what do I call here instead?
I'm not sure if this is what you want, but try:
all_posts.first.class

Could I improve this method with duck typing?

Hopefully I haven't misunderstood the meaning of "duck typing", but from what I've read, it means that I should write code based on how an object responds to methods rather than what type/class it is.
Here's the code:
def convert_hash(hash)
if hash.keys.all? { |k| k.is_a?(Integer) }
return hash
elsif hash.keys.all? { |k| k.is_a?(Property) }
new_hash = {}
hash.each_pair {|k,v| new_hash[k.id] = v}
return new_hash
else
raise "Custom attribute keys should be ID's or Property objects"
end
end
What I want is to make sure that I end up with a hash where the keys are an integer representing the ID of an ActiveRecord object. I don't particularly enjoy having to iterate through the hash keys twice with all? to determine if I need to grab the ID's out.
Of course, I'll accept any other suggestions to improve this code as well :)
How you write this method should depend on whether you expect an exception to be thrown during the course of normal program execution. If you want a readable exception message because an end-user might see it, then throwing one manually makes sense. Otherwise, I'd just do something like this:
def convert(hash)
new_hash = {}
hash.each_pair { |k,v| new_hash[ k.is_a?(Integer) ? k : k.id ] = v }
return new_hash
end
This will accomplish exactly the same thing, and you'll still get an exception if an array key doesn't have an id field. Even better, this uses a little more duck typing because now anything that has an id field will be acceptable, which is better than explicitly checking for something being a Property. This makes your code more flexible, especially when unit testing.
We still have an explicit check for integer objects, but this kind of occasional special case is usually acceptable, especially when checking for built-in data types.
Duck typing is really just a nuanced version of polymorphism. In a statically typed language like Java you'd have to create an explicit interface that told the compiler all of the methods that a particular variable can accept. With a dynamic language like Ruby the interfaces still exist in an abstract sense, they're just implicit.
The problem is the fact that you're accepting two different data structures into one method. The way to make duck typing work is to require that all the objects that get passed to your method obey the same contract (i.e. it's always a hash of Integers to [Foo] objects.) The process of converting a hash with Property keys into the correct structure should be the job of the client code. That can be done very easily with a simple wrapper class or a conversion function consisting of just the body of your elseif clause.
Bottom line it's up to the guy calling the method to make sure his parameters all quack the way your method expects them to quack. If they don't, he's the one who need's to figure out how to make his turkey quack like a duck, not you.
What I want is to make sure that I end up with a hash where the keys are an integer representing the ID of an ActiveRecord object.
You should probably check for that when you're creating/inserting into the hash. You could try something like this:
h = {}
def h.put obj
self[obj.id]=obj
end
or maybe
h = {}
def h.[]= key, value
raise "hell" unless key == value.id
super
end

Resources