Trying to fetch some products from this API - but I can't seem to access my ActiveModel::Serialized attribute product.name
from my views. Where did I go wrong?
Model:
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
Controller:
class MainController < ApplicationController
def index
@products = ThirdPartyProducts.fetch
end
end
View:
<% if @products.any? %>
<% @products.each do |product| %>
<div class="product">
<%= product.name %>
</div>
<% end %>
<% end %>
Error:
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'
Assuming third party products to be an array of products you might want to redefine your class in something like:
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
And:
class Product
def new(args)
hash.each do |key, value|
self.class.send(:attr_accessor, "#{key}") }
send("#{key}=", value)
end
end
end
With this the line:
@products = ThirdPartyProducts.fetch
Is returning an array of Product
instances each with the response of the api.
As the array exists you don't need anymore:
<% if @products.any? %>
@products.any
is always and array, and if empty the iteration will not render the next lines so you don't have any logic in the view.
Updated answer:
Other option is using a hash in the view for each element.
@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
And in the views:
<% @products.each do |product| %>
<%= product["name"] %>
<%= product["price"] %>
<% end %>