-1

I'd like to turn a response from the following query:

sites = Site.find(request.review_sites).pluck(:id, :location_id, :site_name, :review_url,:created_at)

which provided output like below,

[
  [
    50,
    2,
    "google",
    "https://search.google.com/local/writereview?placeid=000000001flMRNRVr8YpJWuY",
    Thu, 06 Dec 2018 20:18:29 UTC +00:00
  ],
  [
    51,
    2,
    "facebook",
    "https://www.facebook.com/biz/reviews/?ref=page_internal",
    Thu, 06 Dec 2018 20:18:35 UTC +00:00
  ]
]

into a nested hash like the following (which I'll be working with as JSON quite a bit later):

{
  :google => {
    :id => 50,
    :create_at => "2018-12-06T20:18:29.651Z",
    :site_name => "google",
    :review_url => "https://search.google.com/local/writereview?placeid=00000000001flMRNRVr8YpJWuY",
    :location_id => 2
  },
  :facebook => {
    :id => 51,
    :create_at => "2018-12-06T20:18:35.639Z",
    :site_name => "facebook",
    :review_url => "https://www.facebook.com/biz/reviews/?ref=page_internal",
    :location_id => 2
  }
}

I realize this is a duplicate, but I'm struggling to implement some answers given. I'm struggling to do this programmatically, so any help would be appreciated.

5
  • 1
    It seems your example doesn't have a valid syntax. Could you clarify that? Commented Dec 7, 2018 at 10:51
  • I updated the question to show what I wanted (is that where you meant it was invalid syntax?), but I believe I solved the issue below. Commented Dec 7, 2018 at 10:53
  • @Rich You have displayed your array in a format that is output by some libraries, but neverthess non-standard, and not liked by so many people. It is better to use the standard inspection form, as I changed into. Commented Dec 7, 2018 at 11:20
  • What is Site, what is pluck? Ruby does not have such things. Commented Dec 7, 2018 at 11:22
  • Check answer I posted, which will better one for you to render data Commented Dec 7, 2018 at 11:40

4 Answers 4

2

Let your array be array. In Ruby < 2.6, you can get the hash by:

array.map do
  |id, location_id, site_name, review_url, create_at|
  [site_name.to_i, {
    id: id,
    create_at: create_at,
    site_name: site_name,
    review_url: review_url,
    location_id: location_id,
  }].to_h
end

In Ruby 2.6, you can get it by:

array.to_h do
  |id, location_id, site_name, review_url, create_at|
  [site_name.to_i, {
    id: id,
    create_at: create_at,
    site_name: site_name,
    review_url: review_url,
    location_id: location_id,
  }]
end
Sign up to request clarification or add additional context in comments.

1 Comment

Whoa! That's a really nice feature coming with Ruby 2.6! While I was trying to sort this out, I was wondering what the reason was Ruby didn't have some way to do array.to_h Thanks for sharing this! Unfortunately, I'm still running 2.5.3, but will keep this in mind!
1

I got what you are looking for,

Try folowing,

sites = Site.find(request.review_sites)
          .as_json(only: [:id, :location_id, :site_name, :review_url,:created_at])
          .group_by { |x| x['site_name'] }

Output look likes,

{
  'google' => [
    {
      'id' => 50,
      'create_at' => "2018-12-06T20:18:29.651Z",
      'site_name' => "google",
      'review_url' => "https://search.google.com/local/writereview",
      'location_id' => 2
    },
    {
      'id' => 52,
      'create_at' => "2018-14-06T20:18:29.651Z",
      'site_name' => "google",
      'review_url' => "https://search.google.com/local/readerview",
      'location_id' => 3
    }
  ],
  'facebook' => [
    {
      'id' => 51,
      'create_at' => "2018-12-06T20:18:35.639Z",
      'site_name' => "facebook",
      'review_url' => "https://www.facebook.com/biz/reviews/?ref=page_internal",
      'location_id' => 2
    }
  ]
}

Comments

1

In your case pluck might not be the right tool for the job.

If you have control over it, I would change it to something like the below (separated to several logical lines just for convenience).

collection = Site.find(request.review_sites)
columns = [:id, :location_id, :site_name, :review_url, :created_at]
sites = collection.select(columns).map { |v| [v.id, v.attributes] }.to_h

Using select returns the attributes you need as a hash, and then you can map it however you like. Converting to json would then be a matter of sites.to_json.

3 Comments

I was under the impression using find + pluck is more efficient than mapping? Either way, this is more readable. Thanks for your answer!
Note that the map is only performed after we already selected only the specific columns, and not the entire object - so I think performance wise, we did not sacrifice much, if at all. I might be wrong, but in any case, accessing the response by its array index (like in your original answer) seems like something I would want to avoid.
Ah, I understand - that makes sense to avoid accessing via array index. Thank you.
0

I solved it thanks to this response by @dcarneiro

Here is how I created nested hashes out of nested arrays for anyone who finds this.

      review_sites = Site.find(request.review_sites).pluck(:id, :location_id, :site_name, :review_url,:created_at)
      sites_hash = Hash[review_sites.map do |site| 
        [site[2], Hash['id', site[0], 'location_id', site[1], 'site_name', site[2], 'review_url', site[3], 'create_at', site[4] ]]
      end]

3 Comments

But this is not a very robust way to handle it. If the part of the code that uses pluck is under your control, then I would replace it with select([:id, :location_id, :site_name, :review_url,:created_at]) - which will give you an array of hashes that is easier to process to the structure you need using map.
@Rich I'd recommend moving keys to a constant (if they're stable of course) and use zip. sites_hash = KEYS.zip(review_sites).to_h . (ruby-doc.org/core-2.5.3/Enumerable.html#method-i-zip)
@mbuechmann I answered my own question before anyone else answered. Their answers were helpful and appreciated because I have now learnt a better way to implement something like this than how I did it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.