t56k
t56k

Reputation: 7001

Efficient way to convert collection to array of hashes for render json

Is there a more efficient way to map a collection of objects to an array of hashes?

def list
  @photos = []
  current_user.photos.each do |p|
    @photos << {
      id: p.id, label: p.name, url: p.uploaded_image.url(:small),
      size: p.uploaded_image_file_size
    }
  end
  render json: { results: @photos }.to_json
end

This seems a bit verbose but the structure it returns is required by the frontend.

Update

So .map is the preferred method then?

Upvotes: 0

Views: 1256

Answers (4)

user9255572
user9255572

Reputation:

You can also do that like this

def array_list
  @photos = current_user.photos.map { |p| { id: 
  p.id, label: p.name, url: p.uploaded_image.url(:small), size: p.uploaded_image_file_size } }
  render json: { results: @photos }
end

Upvotes: 0

jvillian
jvillian

Reputation: 20263

As a starting point, it should be closer to:

def list
  @photos = current_user.photos.map do |p|
    {
      id: p.id, label: p.name, url: p.uploaded_image.url(:small),
      size: p.uploaded_image_file_size
    }
  end
  render json: { results: @photos }
end

Just for fun, you could do something like:

class PhotoDecorator < SimpleDelegator

    def attributes
      %w(id label url size).each_with_object({}) do |attr, hsh|
        hsh[attr.to_sym] = send(attr)
      end
    end

    def label
      name 
    end

    def url
      uploaded_image.url(:small)
    end

    def size
      uploaded_image_file_size
    end

end

And then:

> @photos = current_user.photos.map{ |photo| PhotoDecorator.new(photo).attributes }
 => [{:id=>1, :label=>"some name", :url=>"http://www.my_photos.com/123", :size=>"256x256"}, {:id=>2, :label=>"some other name", :url=>"http://www.my_photos/243", :size=>"256x256"}]

Upvotes: 1

Roman Kiselenko
Roman Kiselenko

Reputation: 44370

  1. Don't do it in the contoller
  2. Don't generate the json response with map, let's as_json(*) method do that for you.
  3. Don't use @ variable in the json render.
  4. Don't use {}.to_json the render json: {} do it under the hood.

in the photo model.

def as_json(*)
  super(only: [:id], methods: [:label, :url, :size])
end
alias label name

def size
  uploaded_image_file_size
end    

def url
  uploaded_image.url(:small)
end

controller code.

def list
  render json: { results: current_user.photos }
end

Upvotes: 3

Nimish Gupta
Nimish Gupta

Reputation: 3175

Please try

def list
  @photos = current_user.photos.map { |p| { id: p.id, label: p.name, url: p.uploaded_image.url(:small), size: p.uploaded_image_file_size } }
  render json: { results: @photos }
end

Upvotes: 1

Related Questions