我需要一种更好的方法来查询数组

时间:2016-02-02 14:56:52

标签: ruby-on-rails arrays ruby json httparty

我有一个T恤应用程序,它与可扩展的新闻api链接。我有一个有效的解决方案,但必须有一个更好的方法。 api的产品有一系列颜色,颜色有一系列图像。我想显示“Front”的图像,但是数组中的第一个图像并不总是在前面。我的视力很差,因为我无法想到一个解决方案来查询数组中的标签“Front”比这更好....

查看:

<% if @product['colors'][0]['images'][0]['label'] =='Front' %>
  <%= image_tag @product['colors'][0]['images'][0]['url'] %>
<% elsif @product['colors'][0]['images'][1]['label'] =='Front' %>
  <%= image_tag @product['colors'][0]['images'][1]['url'] %>
<% elsif @product['colors'][0]['images'][2]['label'] =='Front' %>
  <%= image_tag @product['colors'][0]['images'][2]['url'] %>
<% elsif @product['colors'][0]['images'][3]['label'] =='Front' %>
  <%= image_tag @product['colors'][0]['images'][3]['url'] %>
<% end %>

控制器:

def show_product
  @product = scalable_press.show_product(params[:product])
end

有更好的方法吗?

3 个答案:

答案 0 :(得分:4)

使用find

<% item = @product['colors'][0]['images'].find{|i| i['label'] == 'Front'} %>
<%= image_tag item['url'] if item.present? %>

答案 1 :(得分:1)

每次我必须处理数据结构时,我都无法控制我创建一个类来将数据结构包装成我自己的喜好。我在上面看到的最大问题是您将API结构与您的视图相关联,只需想象一旦API更改就重构它。

module <ExternalAPIName>
  IMAGE_TYPES = {
    front: "Front"
    ...
  }
  class Product
    attr_reader :colors

    def self.get(product)
      # Depending on what scalable_press is you can either call it directly or declare module attribute
      new scalable_press.show_product(product)
    end

    def initialize(data_hash)
      parse_colors(data_hash['colors'])
    end

    private

    def parse_colors(colors)
      @colors = colors.map {|color_hash| Color.new(color_hash) }
    end
  end

  class Color

    def initialize(color_hash)
      parse_images color_hash['images']
    end

    IMAGE_TYPES.each do |name, label|
      define_method "#{name}_image" do
        @images.find {|image| image.type == name }
      end
    end 

    private

    def parse_images(images)
      @images = images.map {|image_hash| Image.new(image_hash) }
    end
  end

  class Image
    attr_reader :url, :type

    def initialize(data_hash)
      @url = data_hash['url']
      @type = IMAGE_TYPES.key(data_hash['label'])
    end
  end
end

我同意相当多的代码,但它大大简化了代码的其余部分:

控制器:

@product = ExternalAPIName.get(params[:product])

查看:

<%= image_tag(@product.colors.first.front_image.url) %>

它为您提供了对收到的数据的完全自定义功能以及最重要的内容,您将嵌套的哈希结构转换为属于您的应用程序域的对象。您现在可以将任何过滤,搜索和数据操作方法挂钩到这些对象中。

答案 2 :(得分:0)

您可以创建方便的地图:

image_map = @product['colors'][0]['images'].each_with_object({}) do |h,obj| 
  obj[h["label"]] = h["url"]
ebd

现在,您可以访问各种图片网址:

image_map["Right"]
#=> "http://i1.ooshirts.com/images/lab_shirts/Kiwi-5-R.jpg"

image_map["Left"]
#=> "http://i1.ooshirts.com/images/lab_shirts/Kiwi-5-L.jpg"

我正在使用here中的示例JSON,理想情况下,您应该添加相关链接。