Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making tables from JSON in Ruby on Rails?

I have some JSON that I pull in and read into an object @items:

[
 {
  {
    "id": "A",
    "description": "a_description_one"
    "value": some_alphanumeric_string
  }, 
  {
    "id": "B",
    "description": "b_description_one"
    "value": some_alphanumeric_string
  }, 
  {
    "id": "C",
    "description": "c_description_one"
    "value": some_alphanumeric_string
  }
 }, 
 {
  {
    "id": "C",
    "description": "c_description_3"
    "value": some_alphanumeric_string
  }, 
  {
    "id": "A",
    "description": "a_description_3"
    "value": some_alphanumeric_string
  }, 
  {
    "id": "B",
    "description": "b_description_3"
    "value": some_alphanumeric_string
  }
 }, 
 ...
] 

My goal is to output two tables, as follows, in HTML:

 -----------------------------------------------------
|        A        |        B        |        C        |
|-----------------------------------------------------|
|a_description_one|b_description_one|c_description_one|
|-----------------------------------------------------|
|a_description_two|b_description_two|c_description_two|
|-----------------------------------------------------|
|a_description_3  |b_description_3  |c_description_3  |
 -----------------------------------------------------

And a second table:

 ----------------------------------------------------
|  C value  | C description  |  Count       | Change |
|----------------------------------------------------|
|some string|it's description|times appeared| change |
 ----------------------------------------------------

While the first table is fairly straightforward, I wasn't able to find a good way to code it because I didn't know the order of the descriptors. As such, I have:

<table> 
  <thead> 
    <tr>
      <th>a</th>
      ...
    </tr>
  </thead>
  <tbody> 
    <% for item in @items %>
      <% for portion in item %> 
        <% if portion[0]["id"] == "A" %> 
           <% a = portion[0] %>
        <% end %>
      ...
      <% end %> 
      <tr> 
        <td><%= a["description"].to_s %></td>
        ...
      </tr> 
    <% end %>
  </tbody>
</table> 

Which seems awful.

As for the second table, all I'm trying to do is look at all the C values, and if there are multiples with the same C value concatenate them. I also want to load yesterdays data, which I can get from the server and have as @items_old, and compare the counts of items with the same values to yesterdays ones. I have no idea where to go with this.

like image 730
rapidash Avatar asked Mar 02 '26 16:03

rapidash


1 Answers

It sounds like the description arrays are out of order, but you need them in order. So just sort the arrays before you iterate through them.

<% for item in @items %>
  <% for portion in item.sort_by { |obj| obj['id'] } %> 
    <tr>
      <td><%= obj["description"].to_s %></td>
      ...
    </tr>
  <% end %>
<% end %>

Alternatively, ruby arrays do have a Array#find method that takes a block and returns an item when the block returns true. So if you want to be real explicit about it you can do:

<% for item in @items %>
  <% for portion in item %> 
    <tr>
      <td><%= item.find { |obj| obj['id'] == 'A' }["description"].to_s %></td>
      <td><%= item.find { |obj| obj['id'] == 'B' }["description"].to_s %></td>
      <td><%= item.find { |obj| obj['id'] == 'C' }["description"].to_s %></td>
    </tr>
  <% end %>
<% end %>

But that starts to get pretty hairy for a view. I would strongly suggest refactoring that logic to some helper methods. The downside here is that you ever have a D in in there you suddenly have a lot of code to change. Simply iterating through sorted arrays you dont have to really care how many are in there, which can be good or bad depending on what you are doing.


Lastly you could transform this data in ruby into a format that is more how you want. Build new arrays and hashes from this data and presented the processed @items object to the view. Or even better wrap all that in a class that would have methods to parse this data and then provide a simple interface to its guts.

If this data is reasonably complex, and used in a lot of different ways, this is likely the most "correct" approach as it encapsulates the data logic far away from the presentation logic.

class Descriptions
  def initialize(json)
    @data = JSON.parse(json)
  end

  def get_description(index, id)
    description_obj = @data[index].find do |obj|
      obj['id'] == id
    end

    description_obj['description'].to_s
  end
end

my_model = Descriptions.new(json)
my_model.get_description(0, 'A')
like image 55
Alex Wayne Avatar answered Mar 04 '26 04:03

Alex Wayne



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!