2

I'm currently working on a personal Rails 4 project, and in one of the controllers, I have an array of three different objects, which I'm trying to convert into JSON. I'm using the find_by_sql method to query the DB with a custom MySQL query. The code is as follows:

The controller:

class ActivitiesController < ApplicationController
  def index
    user = current_user.id # using devise
    limit = 100

    likes = Like.find_by_sql(...)
    shares = Share.find_by_sql(...)
    comments = Comment.find_by_sql(...)

    @activities = [likes, shares, comments]
  end
end

Each of the three objects contain different fields. For example, the likes object contains fields such as post_id, first_name, last_name etc. The shares object contains fields such as post_id, share_count, shared_time etc.

This is the JSON I want to output:

{
    "likes": [
      { "post_id": "7", "first_name": "Yss", "last_name": "Salas", "profile_pic": "345943754_o.png" },
      { "post_id": "34", "first_name": "Jessica", "last_name": "Nigri", "profile_pic": "pikachu.png" }
    ],
    "shares": [
      { "post_id": "43", "share_count": 54, "shared_time": "2014-05-04 15:14:45" },
      { "post_id": "54", "share_count": 17, "shared_time": "2014-05-24 03:43:45" }
    ],
    "comments": [
      { "post_id": "34", "first_name": "Yss", "last_name": "Salas", "comment": "¡Me gustas mucho!" },
      { "post_id": "12", "first_name": "Jenna", "last_name": "Marbles", "comment": "Blah blah blah look at my ugly dog awwwww!" }
    ]
}

The index.json.jbuilder:

json.array! @activities do |subactivities|
  json.array! subactivities do |activity|
    if activity.class == Like
      json.likes.post_id activity.post_id #exception raised in this line
      json.likes.title activity.title
      json.likes.first_name activity.first_name
      json.likes.last_name activity.last_name
      json.likes.profile_pic activity.profile_pic
    elsif activity.class == Share
      json.shares.post_id activity.post_id
      json.shares.share_count activity.share_count
      json.shares.shared_time activity.shared_time
    else
      json.comments.post_id activity.post_id
      json.comments.first_name activity.first_name
      json.comments.last_name activity.last_name
      json.comments.comment activity.comment
    end
  end
end

The above raises an exception NoMethodError in Activities#index, undefined method 'post_id' for #<Object:0x00000003064250>. I'm very new to Rails, and I'm guessing that this is happening because there is no json.likes property to assign the values to. How do I go about building the above JSON structure with JBuilder?

2 Answers 2

2

You can do it without JBuilder, easier and faster.

def index
  user = current_user.id # using devise
  limit = 100

  likes = Like.find_by_sql(...).map(&:attributes) # this will return an array of JSON objects
  shares = Share.find_by_sql(...).map(&:attributes)
  comments = Comment.find_by_sql(...).map(&:attributes)

  @activities = {"likes" => likes, "shares" => shares, "comments" => comments}
end

Like this you have a hash with all the information you need. It may also be better to extract the logic of looking for likes, shares and comments to a separate class, so that you would call InformationCollector.collect and it will give you the response you need.

Sign up to request clarification or add additional context in comments.

1 Comment

Although your example is convenient, I need to be using Jbuilder for this project, unfortunately. I have figured it out (I'll be answering my own question) from the Jbuilder wiki at the project's GitHub page. It seems I was over-thinking it, and the solution is so much more straightforward than I thought.
2

From Jbuilder's GitHub page, the solution is rather simple. All that needs to be done is pass the instance variables into a block, and assign the custom key/value pairs manually.

The below example would generate an array of key/value pairs for the @likes instance variable:

# activities/index.json.jbuilder

json.likes @likes do |like|
  json.post_id like.post_id
  json.first_name like.user.first_name
  json.last_name like.user.last_name
  json.profile_pic like.user.profile_pic
end

The above will output:

{
  "likes": [
    { "post_id": 7, "first_name": "Yss", "last_name": "Salas", "profile_pic": "345943754_o.png" },
    { "post_id": 34, "first_name": "Jessica", "last_name": "Nigri", "profile_pic": "pikachu.png" }
  ],
}

Comments

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.