I am trying to rename columns once they come out of a database query so I can get them into the correct format for a d3.js graph. This requires the fields to be named source,target,value.
def self.including_relationships
User.select(:follower_id,:followed_id,:value)
#How do I rename the fields from the line above to the fields below
obj['links'] << a.slice('source', 'target', 'value')
end
end
User.select('follower_id, followed_id, value').map(&:attributes)
will give you an array of Hash like bellow.
[{"follower_id" => 1, "followed_id" => 2, "value" => 1},
{"follower_id" => 1, "followed_id" => 2, "value" => 1},
..........
{"follower_id" => 1, "followed_id" => 2, "value" => 1},]
which can be stored as a json casting it.
> [{"follower_id" => 1, "followed_id" => 2, "value" => 1}].to_json
=> "[{\"follower_id\":1,\"followed_id\":2,\"value\":1}]"
You could use ActiveModel::Serializers or JBuilder to customise the JSON output but you should instead consider manipulating the data in javascript.
By doing so you avoid any strong couplings between your server side API and whatever graphing library you use.
Your API output should not be controlled by how you are displaying the data.
A simplified example using jQuery:
var promise = $.getJSON('/users.json');
promise.then(function(data){
return jQuery.map(data, function(user){
return {
target: user.follower_id,
source: user.followed_id,
value: user.value
}
}).toArray();
});
promise.done(function(data){
// draw the graph.
});
Related
This question already has answers here:
How to get a specific output iterating a hash in Ruby?
(6 answers)
Closed 6 years ago.
I want to iterate over this data to extract the value of the ids:
[ {:id => 3, :quantity => 5 }, { :id => 4, :quantity => 3 } ]
You can use Array's map method like below:
arr =[ {:id => 3, :quantity => 5 }, { :id => 4, :quantity => 3 } ]
ids = arr.map { |k| k[:id] }
#=> [3,4]
[ {:id => 3, :quantity => 5 }, { :id => 4, :quantity => 3 } ].each do |hash|
puts hash[:id]
end
This will puts each id value on the screen. You can do what you need to do from there.
Ruby: Mapping Over an Array with Hash#values_at
There's more than one way to do this in Ruby. A lot depends on what you're trying to express. If you're not trying to play code golf, one way to do this is with Hash#values_at. For example:
[{id: 3, quantity: 5}, {id: 4, quantity: 3}].flat_map { |h| h.values_at :id }
#=> [3, 4]
Rails: Extracting Data with Pluck
A more Rails-like way would be to just ActiveRecord::Calculations#pluck the attributes you want in the query itself. For example:
Stuff.where(quantity: [3, 5]).pluck :id
There are certainly other ways to get the same result. Your mileage may vary, depending on your real use case.
See Also
Active Record Query Interface
I am writing integration tests for rails and I want to compare the object created with the JSON object sent. The object returned is not exactly the same as the one sent, (i.e.) it has keys that the object sent doesn't have because I am using active model serializers to pull associations in the returned object. Basically, I just want to compare all the same keys between both objects to see if its the same. Let me know if there is a clean efficient code snippet that does this for me!
TL;DR
"Clever" test code is rarely useful. Each test should be as simple as possible, and it should be testing the behavior of some object rather than its composition. There are always ways to be clever, though.
Using Array Intersection
One unreadably-clever way to do this is to use Array#& to find the intersection of the keys, and then look for equality between the values. This will work on a relatively flat hash. For example:
hash1 = {:key1=>"value1", :key2=>"value2", :key3=>"value3", :key4=>"value4"}
hash2 = {:key1=>"value1", :key2=>"value2", :key5=>"value5"}
Array(hash1.keys & hash2.keys).map { |k| hash1[k] == hash2[k] }.uniq
#=> [true]
If you're using RSpec to test, you could say something like:
it 'has some matching key/value pairs' do
# ... populate hash1
# ... populate hash2
Array(hash1.keys & hash2.keys).
map { |k| hash1[k] == hash2[k] }.uniq.should == [true]
end
Of course, if the expectation is false, then you won't really know why, or which key/value pair was wrong. This is just one of the many reasons that you should always use fixed inputs and outputs for testing, rather than trying to do dynamic comparisons.
You could use Hash#slice, which is an Active Support core extension.
For example, if the keys you want to check are :a, :b, :c, but the result contains :a, :b, :c, :d, slice will reduce the result to just contain the keys you care about:
expected = { :a => 1, :b => 2, :c => 3 }
result = { :a => 1, :b => 2, :c => 3, :d => 4 }
result.slice(:a, :b, :c) == expected
# => true
If you get a NoMethodError: undefined method 'slice' exception, you need to require active_support/core_ext/hash/slice
First, find the keys that both hashes contain, and then compare the value for those keys:
hash1 = {:key1 => "value1", :key2 => "value2", :key3 => "value3", :key4 => "value4"}
hash2 = {:key1 => "value1", :key2 => "value2", :key5 => "value5"}
hash1_keys = hash1.keys
hash2_keys = hash2.keys
comparable_keys = hash1_keys.select{|key| hash2_keys.include?(key)}
comparable_keys.each do |key|
hash1[key].should == hash2[key]
end
Is there a way to compare two instances of model like
Model.compare_by_name("model1", "model2") which would list the differing column fields
You can use ActiveRecord::Diff if you want a mapping of all the fields that differ and their values.
alice = User.create(:name => 'alice', :email_address => 'alice#example.org')
bob = User.create(:name => 'bob', :email_address => 'bob#example.org')
alice.diff?(bob) # => true
alice.diff(bob) # => {:name => ['alice', 'bob'], :email_address => ['alice#example.org', 'bob#example.org']}
alice.diff({:name => 'eve'}) # => {:name => ['alice', 'eve']}
There is no standard comparator for this. The standard ActiveModel comparator:
Returns true if comparison_object is the same exact object, or comparison_object is of the same type and self has an ID and it is equal to comparison_object.id.
You can write your own by using Hash#diff from activesupport. Something like the following should hopefully get you started:
def Model.compare_by_name(model1, model2)
find_by_name(model1).attributes.diff(find_by_name(model2).attributes)
end
Without using a library or defining a custom method, you can easily get a diff between two models.
For instance,
a = Foo.first
b = Foo.second
a.attributes = b.attributes
a.changes #=> {"id" => [1,2] }
I am using Ruby on Rails 3.0.7 and I would like to know how to initialize\build "custom" data structures responding to the where method as like it works, for example, for common RoR AssociationCollection objects.
For example:
# The following code should work after build the 'test_data' as well...
# but how to build that?
test_data.where(:test_attribute => 'test_value')
I'm not entirely clear on what you're after, but you could create a wrapper around (for example) an array of hashes that used where to do searching.
class Search
def initialize(data)
#data = data
end
def where(filters={})
#data.select do |item|
filters.all?{|key, value| item[key] == value }
end
end
end
data = [
{ :name => 'Sam', :age => 27, :gender => 'M' },
{ :name => 'Sue', :age => 27, :gender => 'F' },
{ :name => 'Bob', :age => 32, :gender => 'M' }
]
search = Search.new(data)
search.where(:age => 27) # returns array containing Sam and Sue hashes
search.where(:gender => 'M') # returns array containing Sam and Bob hashes
search.where(:age => 27, :gender => 'M') # returns array containing just Sam
I need to transform active record JSON to something like this:
{
cols: [{id: 'task', label: 'Task', type: 'string'},
{id: 'hours', label: 'Hours per Day', type: 'number'}],
rows: [{c:[{v: 'Work'}, {v: 11}]},
{c:[{v: 'Eat'}, {v: 2}]},
{c:[{v: 'Commute'}, {v: 2}]},
{c:[{v: 'Watch TV'}, {v:2}]},
{c:[{v: 'Sleep'}, {v:7, f:'7.000'}]}
]
}
That is totally different from what to_json returns from activerecord. What is the most ruby way to transform JSON?
Override the to_json method in your model
# your_model.rb, implement an instance method to_json
def to_json(options = {})
{
'cols' => [{'id' => 'whateveryoulike'}],
'rows' => [{'id' => 'whateveryoulike'}]
}.to_json(options)
end
Remember, it is important to accept options as parameter to this method and pass it on to to_json of the hash (or any other to_json call you make inside this method, for that matter). Otherwise, the method may not behave as expected on collection JSON serialization. And of course since you haven't given any details as to what your model is and how it maps to the desired JSON response, you will have to implement the representation of cols and rows as you like.
This also applies to to_xml.