How to unfreeze the Hash? - ruby-on-rails

I have an object from GraphQL. I need to process one field and then return a Hash.
To do this I initially tried using the to_h method. But when I tried to change the value in the field, I got this error:
FrozenError - can't modify frozen Hash
Then I came up with the idea of using the dup method. This method seems to "unfreeze" the original object:
object.to_h.dup
But this doesn't help for "deep" fields. For "deep" fields I had to use the local dup method.
Please tell me if there is a more correct solution to the problem?

Rails (or ActiveSupport if you want to be pedantic) patches a deep_dup method into Hash which does a deep copy. So you should be able to say:
object.to_h.deep_dup
to get a fully mutable version of your Hash.

Related

Ruby on Rails - using a block parameter as a method call

I'm having trouble with a little Ruby on Rails I'm building and need some help.
I have a Table with 20+ Columns and a corresponding XML File which can be parsed as some sort of hash with a gem. Every key would be mapped to a column and every value would be a data record in said column.
The way I access a specific value in the already parsed XML file is:
filename["crs","inputkeyhere"]
which returns the value, for example "52" or whatever.
What I am trying to do is upload the file, parse it with the gem and give each column the corresponding value.
My table (or model) is called "Attributeset" and I already know how I can access every column:
#attributeset = Attributeset.new
#attributeset.attributes.keys
So my thought process was:
Iterate over all the keys
Pass every key into a block called |a|
Use the rails possibilty to set attributes by calling the corresponding #attributeset.
Set colum attribute to the corresponding xml key
So my code would go something like this:
#attributeset.attributes.keys.each do |a|
#attributeset.a=filename["crs",a]
end
But my problem is, that ruby thinks ".a" is a method and apparently does not evaluate "a" to the block parameter.
I've read through lambdas and procs and whatnot but didn't really understand how they could work for my specific situation.
Coming from bash scripting maybe my thinking might be wrong but I thought that the .a might get evaluated.
I know I can run the block with yield, but this only works in methods as far as I know..
Any help is appreciated.
Thanks and stay healthy,
Alex
Thanks for the input!
I wanted to make it as clean as possible, and not using any temporary hashes to pass arguments.
I've found the method
write_attribute
which can be used like this:
#attributeset.write_attribute(a, xmp["crs",a])
worked perfectly for me.
You can use []= method to set values dynamically:
#attributeset.attribute_names.each do |attribute|
#attributeset[attribute] = filename["crs", attribute]
end

Mongoid returning object as array

I am using tire/elasticsearch for searching with mongoid, when I update the index of my documents I am getting the error undefined method 'as_document':
#document.tire.update_index
undefined method `as_document' for #<Array:0x10a40f870>
I have researched the mongoid method 'as_document' and found out that it only accepts single objects. When my document objects do not have comments, "#document.as_document" returns a single object and there is no error, however when the document has comments, "#document.as_document" seems to return an array and returns the error "undefined method `as_document' for #".
It seems that when #document has comments, it returns an array of hashes.
Is there any way that I can return the array (Array:0x10a40f870) so I can see where it is coming from?
How can I convert #document (which seems to be an array) back into a single object so that it can pass through as_document?
Why am I getting an 'undefined method as_document'
I have a Document model with a has_many relationship to comments
Rails: 3.2.12,
Mongoid: 3.1.4
1. Logger is your homie. I would recommend printing this wherever your logic exists so you can see exactly what array you are returning.
Something like this:
# your logic here
#your_array = ..set
logger.debug "MY ARRAY: #{#your_array}"
This will give you at least a good look at what you are dealing with if you can take a look at Webrick or whatever setup you have.
2+3. Mongoid stores Documents as an array of hashes so that is what you are probably looking at (but I haven't seen the exact code).
I dont believe there is anything wrong with your document definitions but I would take a better look at the [Relations Sections] of the Mongoid docs1
More specifically to question 2: take a look at the operations section.

rails using .send( ) with a serialized column to add element to hash

I'm serializing many attributes on a model Page as hashes.
Because of the high number of attributes, I've taken a meta-programming approach and want to use .send() to iterate through a collection of attributes (such that I don't have to type out an update action for each attribute.
I've done something like this:
insights.each do |ins|
self.send("#{ins.name}=", {(Time.now) => ins.values[1]['value'].to_f})
self.save
end
The problem is that this obviously overwrites the whole serialized column, whereas I wish to add this as an element to the serialized hash.
Tried something like this:
insights.each do |ins|
self.send("#{ins.name}[#{Time.now}]=", ins.values[1]['value'].to_f)
self.save
end
But get a NoMethodError: undefined method page_fan_adds_unique[Mon Aug 13 13:31:58 -0400 2012]=
In the console I'm able to do Page.find(5).page_fan_adds_unique[Time.now]= 12345 and save it as an additional element to the hash as expected.
So how can I use .send() to save an additional element to a serialized hash? Or is there some other approach? Such as using update_attribute or another method? Writing my own? Any help is appreciated, even if the advice is that I shouldn't be using serialization for this.
I'd do :
self.ins.name.send(:[]=, key, value)

Is there some method or an easy way so that I can return a hash that includes only the given keys?

I am using Ruby on Rails 3.2.2 and I am looking for a method which is the opposite of except for hashes (except documentation), probably an only method. Is there some method or an easy way so that I can return a hash that includes only the given keys?
# Example, 'only' method as opposite to the 'except'
#person.update_attributes(params[:person].only(:name, :surname))
I think what you are looking for is slice, which will return a hash with only the given keys.

Nested to_xml issue?

This may be a basic question but it has been causing me some problems. I am trying to dump an ActiveRecord Object to an XML file using the to_xml function. For whatever reason, this does not work for me if I try to nest it into an element.
Basically I have a hash of ActiveRecord objects that I want to iterate over, and then dump into my XML file like this:
#hash_of_activerecord.each do |key, value|
xml.object do
value.to_xml
end
end
For whatever reason this does not seem to work. What can I do to fix it? Obviously I could just print out each aspect of the object individually but that is not the best solution because I would have to remember to change what is in that loop if I later made a change to the contents of that ActiveRecord object.
Use :include. See http://apidock.com/rails/ActiveRecord/Serialization/to_xml

Resources