【问题标题】:Can't access ActiveModel::Serialized attribute from views无法从视图访问 ActiveModel::Serialized 属性
【发布时间】:2014-08-04 15:31:02
【问题描述】:

尝试从此 API 获取一些产品 - 但我似乎无法从我的视图中访问我的 ActiveModel::Serialized 属性 product.name。我哪里做错了?

型号:

require 'rest_client'

class ThirdPartyProducts
    include ActiveModel::Serializers::JSON

    # Not setting attributes here as there's just too many in the JSON response
    # attr_accessor :lorem, :ipsum, :dolor, :sit, :amet

    def attributes=(hash)
      hash.each do |key, value|

        # Set attributes here instead
        # http://stackoverflow.com/questions/1734984/why-cant-i-use-attr-accessor-inside-initialize

        self.class.send(:attr_accessor, "#{key}")
        send("#{key}=", value)
      end
    end

    def self.fetch
      response = RestClient.get "http://api.shopstyle.com/api/v2/products?pid=uid7849-6112293-28&format=json&fts=women"
      raw_products = JSON.parse(response)["products"]

      raw_products.map do |product|
        what_to_name_this ||= self.new
        product = what_to_name_this.from_json(product.to_json)

        name = product.name
        # url = ...
        # image = ...
      end
    end
end

控制器:

class MainController < ApplicationController
  def index
    @products = ThirdPartyProducts.fetch
  end
end

查看:

<% if @products.any? %>
  <% @products.each do |product| %>
    <div class="product">
      <%= product.name %>
    </div>
  <% end %>
<% end %>

错误:

NoMethodError in Main#index
Showing /root/rails-repo/app/views/main/index.html.erb where line #5 raised:

undefined method `name' for "McQ Alexander McQueen Mesh-paneled stretch-jersey top":String
Extracted source (around line #5):
  <% if @products.any? %>
    <% @products.each do |product| %>
      <div class="product">
        <%= product.name %>
      </div>
    <% end %>
  <% end %> 

Rails.root: /root/rails-repo

app/views/main/index.html.erb:5:in `block in _app_views_main_index_html_erb__1422808888741532498_21926060'
app/views/main/index.html.erb:3:in `each'
app/views/main/index.html.erb:3:in `_app_views_main_index_html_erb__1422808888741532498_21926060'

【问题讨论】:

    标签: ruby-on-rails json active-model-serializers


    【解决方案1】:

    假设第三方产品是一系列产品,您可能希望通过以下方式重新定义您的类:

    class ThirdPartyProducts
      require 'rest_client'
    
      def self.fetch
        response = RestClient.get "http://api.shopstyle.com/api/v2/products?pid=uid7849-6112293-28&format=json&fts=women"
        raw_products = JSON.parse(response)["products"]
        products = []
        raw_products.map { |pro| Product.new(pro) }
      end
    end
    

    还有:

    class Product
       def new(args)
         hash.each do |key, value| 
           self.class.send(:attr_accessor, "#{key}") }
           send("#{key}=", value)
         end
       end
    end
    

    这行:

    @products = ThirdPartyProducts.fetch
    

    正在返回一个 Product 实例数组,每个实例都带有 api 的响应。

    由于数组存在,您不再需要:

    <% if @products.any? %>
    

    @products.any 始终是数组,如果为空,则迭代不会呈现下一行,因此视图中没有任何逻辑。

    更新答案:

    其他选项是在视图中为每个元素使用哈希。

    @products = Products.fetch
    
    class Products
      def self.fetch
        response = RestClient.get "http://api.shopstyle.com/api/v2/products?pid=uid7849-6112293-28&format=json&fts=women"
        JSON.parse(response)["products"]
      end
    end
    

    在视图中:

    <% @products.each do |product| %>
       <%= product["name"] %>
       <%= product["price"] %>
    <% end %>
    

    【讨论】:

    • 酷,谢谢!快速提问:1) ShopSense JSON 响应是数组和哈希的混合体,我在gist.github.com/frankie-loves-jesus/11058955 中添加了一个示例 - 这会改变什么吗? 2) 基本上我正在尝试解析产品名称、URL 和图像 3) 我不再需要include ActiveModel::Serializers::JSON 了吗?
    • 不会改变任何东西。 JSON.parse 将返回散列和数组的散列。您只需要请求包含产品的哈希数组,然后遍历每个 elemento 创建一个新的产品对象。这样您就可以使用#attribute 从视图中访问它。无论如何,如果您不想为每个元素创建对象,您也可以重用相同的哈希。查看更新的答案。
    • ActiveModel::Serializers::JSON 用于将模型中先前解析的哈希转换为 json。所以不,我猜你不需要它。
    • 太棒了!请稍等我实施。
    • 我在定义属性中有一个错字。之后,我可运行的应用程序无法正常工作。无论如何,如果您只需要 3 个属性。不要使用动态定义器,而是在产品类中使用 attr_accesor 设置属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-05
    • 2019-08-14
    相关资源
    最近更新 更多