How to convert a ruby hash object to JSON? - ruby-on-rails

How to convert a ruby hash object to JSON? So I am trying this example below & it doesn't work?
I was looking at the RubyDoc and obviously Hash object doesn't have a to_json method. But I am reading on blogs that Rails supports active_record.to_json and also supports hash#to_json. I can understand ActiveRecord is a Rails object, but Hash is not native to Rails, it's a pure Ruby object. So in Rails you can do a hash.to_json, but not in pure Ruby??
car = {:make => "bmw", :year => "2003"}
car.to_json

One of the numerous niceties of Ruby is the possibility to extend existing classes with your own methods. That's called "class reopening" or monkey-patching (the meaning of the latter can vary, though).
So, take a look here:
car = {:make => "bmw", :year => "2003"}
# => {:make=>"bmw", :year=>"2003"}
car.to_json
# NoMethodError: undefined method `to_json' for {:make=>"bmw", :year=>"2003"}:Hash
# from (irb):11
# from /usr/bin/irb:12:in `<main>'
require 'json'
# => true
car.to_json
# => "{"make":"bmw","year":"2003"}"
As you can see, requiring json has magically brought method to_json to our Hash.

require 'json/ext' # to use the C based extension instead of json/pure
puts {hash: 123}.to_json

You can also use JSON.generate:
require 'json'
JSON.generate({ foo: "bar" })
=> "{\"foo\":\"bar\"}"
Or its alias, JSON.unparse:
require 'json'
JSON.unparse({ foo: "bar" })
=> "{\"foo\":\"bar\"}"

Add the following line on the top of your file
require 'json'
Then you can use:
car = {:make => "bmw", :year => "2003"}
car.to_json
Alternatively, you can use:
JSON.generate({:make => "bmw", :year => "2003"})

Related

How does Ruby Mocha stub a nested hash?

I have a method here that needs to be mocked using Mocha, but currently i have no clue how to mock the nested hash here.
Products.new(:A => "aa", :B => "bb").containers['container_A'].elements['element_b']
So far, i know how to stub Products.new(:A => "aa", :B => "bb"), but have no idea with the hash part after it.
Thanks in advance.
What about a hash/OpenStruct?
require 'ostruct'
product.expects(:containers).
returns('container_A' => OpenStruct.new(:elements => {'element_b' => 'expected_value'}))
puts product.containers['container_A'].elements['element_b']
# => expected_value

Rails - How to define setter/getter dynamically for list of methods inside a class

I have a Notifications module which have classes like 1)car 2)bike 3)Aeroplane. I have a serialized column in UserFeature model.And I have a module 'Notifications' which has list of 11 classes in it.
Notifications
1)car
2)bike
3)Aeroplane
The hash structure of the column notifications in UserFeature model must be
{:car => {:mirror => :true, :door => :true}
:bike => {:x=> :true, :x => :true}
:Aeroplane => {:p => :true, :q => :true}
}
I can access user_object.Notifications
But so as to access user_object.car and also user_object.mirror I need to write getter/setter methods { Defining getter/setter dynamically because I dont want to write getter/setter for every method and also I am unsure about the number of methods I have -> which in future may extend }
Notifications.constants.each do |notification_class|
class_methods = "Notifications::#{notification_class}".constantize.methods(false)
class_methods.each do |method|
method_name = method[0..-4].split('(')[0]
setter_getter_name = "#{notification_class.to_s.underscore}_#{method_name}"
define_method("#{setter_getter_name}=") do |value|
self.notifications = GlobalUtils.form_hash(self.notifications, "#{notification_class}".to_sym, "#{method_name}".to_sym)
self[:notifications]["#{notification_class}".to_sym][ "#{method_name}".to_sym] = value
end
define_method("#{setter_getter_name}") do
self.notifications.fetch("#{notification_class_name}".to_sym, {}).fetch("#{method_name}".to_sym)
end
end
end
But still when i try to access user_object.mirror,
undefined method for #<UserFeature000043645345>
What I am doing wrong?
I need to do this using getter/setter method only
An OpenStruct is a data structure, similar to a Hash, that allows the definition of arbitrary attributes with their accompanying values. This is accomplished by using Ruby’s metaprogramming to define methods on the class itself.
example:
require 'ostruct'
hash = { "country" => "Australia", :population => 20_000_000 }
data = OpenStruct.new(hash)
p data # -> <OpenStruct country="Australia" population=20000000>
Use Ruby OpenStruct class. It will fulfill your requirements without defining such bunch of code.
Edit1, example:
require 'ostruct'
class Aeroplane < OpenStruct; end
a = Aeroplane.new(:p => :true, :q => :true)
a.p # => true

rspec assigns converts hash keys to string

I have a controller action where i am assigning a hash to an instance variable. In my rspec test file, i am using assigns to test it the instance variable is assigned to the value i expect. For some reason, assigns gives me a hash with string keys. If i print the instance variable in the controller, i has symbol keys
Please find the code below. It is simplified.
class TestController < ApplicationController
def test
#test_object = {:id => 1, :value => 2, :name => "name"}
end
end
My test file:
describe TestController do
it "should assign test_object" do
get :test
assigns(:test_object).should == {:id => 1, :value => 2, :name => "name"}
end
end
The above test fails with the error message
expected: {:id=>1, :value=>2, :name=>"name"}
got: {"id"=>1, "value"=>2, "name"=>"name"}
Please help me understand why it is doing that.
RSpec borrows assigns from the regular Rails test/unit helpers and it's using with_indifferent_access to return the requested instance variable as in assigns(:my_var).
Hash#with_indifferent_access returns a key-stringified version of the hash (a deep copy), which has the side effect of stringfiying the keys of instance variables that are hashes.
If you try to match the entire hash, it will fail, but it works if you are checking the values of specific keys, whether they're a symbol or a string.
Maybe an example will help clarify:
{:a => {:b => "bravo"}}.with_indifferent_access => {"a"=>{"b"=>"bravo"}}
{:a => {:b => "bravo"}}.with_indifferent_access[:a][:b] => "bravo"

How do you call "contains?" on a MongoMapper Array in Rails 3?

I want to know how to check if an array element exists inside of a MongoMapper Array. This question is the closest I could find, but it addresses queries rather than simply using a document you already have.
My User model contains the line
key :roles, Array
The 'roles' array contains strings such as 'admin' or 'user.' For authorization, I need to call something like the following method on an instance of User:
if user.roles.contains?('admin')
# Do administrative stuff.
end
But when I try to call 'contains?' Ruby complains that there is no such method:
NoMethodError (undefined method `contains?' for #<Array:0x007fc845cd8948>):
app/models/ability.rb:11:in `initialize'
app/controllers/settings_controller.rb:5:in `index'
If there's no way to do this, then how do I convert the Array into a Ruby array to call 'contains?'? Calling to_a isn't doing it:
if user.roles.to_a.contains?('admin') # etc...
I'm using Rails 3.2.13, Ruby-1.9.3-p392, and MongoMapper 0.12.0 on Mountain Lion.
the function you are looking for is include?, so the expression would be: user.roles.include?('admin')
However since you mentioned mongomapper, if you were preforming a query on the roles array you would do the fallowing:
User.where( :roles => 'admin' )
You can also search an array with an array
User.where( :roles.in => ['admin'] )
for a query with admin or user you can do:
User.where( :$or => [{:roles => 'admin'},{:roles => 'user'}] )
and you can do and just the same:
User.where( :$and => [{:roles => 'admin'},{:roles => 'user'}] )

Is there find_or_create_by_ that takes a hash in Rails?

Here's some of my production code (I had to force line breaks):
task = Task.find_or_create_by_username_and_timestamp_and_des \
cription_and_driver_spec_and_driver_spec_origin(username,tim \
estamp,description,driver_spec,driver_spec_origin)
Yes, I'm trying to find or create a unique ActiveRecord::Base object. But in current form it's very ugly. Instead, I'd like to use something like this:
task = Task.SOME_METHOD :username => username, :timestamp => timestamp ...
I know about find_by_something key=>value, but it's not an option here. I need all values to be unique. Is there a method that'll do the same as find_or_create_by, but take a hash as an input? Or something else with similat semantics?
Rails 3.2 first introduced first_or_create to ActiveRecord. Not only does it have the requested functionality, but it also fits in the rest of the ActiveRecord relations:
Task.where(attributes).first_or_create
In Rails 3.0 and 3.1:
Task.where(attributes).first || Task.create(attributes)
In Rails 2.1 - 2.3:
Task.first(:conditions => attributes) || Task.create(attributes)
In the older versions, you could always write a method called find_or_create to encapsulate this if you'd like. Definitely done it myself in the past:
class Task
def self.find_or_create(attributes)
# add one of the implementations above
end
end
I also extend the #wuputah's method to take in an array of hashes, which is very useful when used inside db/seeds.rb
class ActiveRecord::Base
def self.find_or_create(attributes)
if attributes.is_a?(Array)
attributes.each do |attr|
self.find_or_create(attr)
end
else
self.first(:conditions => attributes) || self.create(attributes)
end
end
end
# Example
Country.find_or_create({:name => 'Aland Islands', :iso_code => 'AX'})
# take array of hashes
Country.find_or_create([
{:name => 'Aland Islands', :iso_code => 'AX'},
{:name => 'Albania', :iso_code => 'AL'},
{:name => 'Algeria', :iso_code => 'DZ'}
])

Resources