Display products from ShopSense API - ruby-on-rails

How do I display products from the ShopSense API in Rails using shopsense-ruby?
JSON.parse(response)["products"] is returning nil:
NoMethodError in Main#index
Showing /home/dev/demo-shopsense/app/views/shared/_shopsense.html.erb where line #3 raised:
undefined method `any?' for nil:NilClass
Extracted source (around line #2):
<div class="custom_widget">
<% if #products.any %>
<% #products.each do |product| %>
<div class="product">
<%= image_tag product['image']['url'] %>
<p><%= product['name'] %></p>
main_controller.rb:
class MainController < ApplicationController
def index
client = Shopsense::API.new('partner_id' => 'uid0000-0000000-00')
response = client.get_looks("New")
#products = JSON.parse(response)["products"]
end
end
shared/_shopsense.html.erb:
<div class="custom_widget">
<% if #products.any? %>
<% #products.each do |product| %>
<div class="product">
<%= image_tag product['image']['url'] %>
<p><%= product['name'] %></p>
</div>
<% end %>
<% end %>
</div>
I've set up a simple demo app demo-shopsense that should be easy to get up and running.

The parsed response of your request looks like this:
{"totalCount"=>"536121",
"looks"=>
[{"id"=>"12328367",
"title"=>"black",
...
As you can see instead of 'products' we have 'looks'.
#products = JSON.parse(response)["looks"]
When you are working with external services, it's very important to find out the exact format of the response.
EDIT:
I think in this case you actually need to use 'search' method on the client instead of 'get_looks', if you want to get products.

Related

(Ruby on Rails) Displaying Posts Into Groups of 3

I'm using the following code to display posts to my users.
_feed.html.erb partial:
<% #posts_by_month.each do |monthname, posts| %>
<%= monthname %>
<ul>
<% posts.each do |post| %>
<li><%= post.created_at %></li>
<% end %>
</ul>
<% end %>
Controller:
def home
if logged_in?
#post = current_user.posts.build
#posts_by_month = current_user.feed.group_by { |post| post.created_at.strftime("%B") }
This renders my posts as follows:
Post 1
Post 2
Post 3
Post 4
I want to change it so that the posts are displayed like:
Post 1 Post 2 Post 3
Post 4 etc etc
etc
I've tried several approaches to this, including the in_groups_of(3) method however the way it is currently setup means nothing works. I feel like there is an obvious solution I'm missing - can anyone help?
[Edit to expand on the in_groups_of(3) error]
If I change line 4 in the _feed partial to:
<% posts.in_groups_of(3, false).each do |post| %>
It gives the error: undefined method `created_at' for #< Array:0xbb8f258 >
The #in_groups_of method returns an Array of Arrays each containing 3 Post objects.
So you now also need to iterate over the returned array that contains your three Posts, something like:
<% posts.in_groups_of(3, false).each do |post_group| %>
<% post_group.each do |post| %>
<li><%= post.created_at %></li>
<% end %>
<% end %>
You can use facets gem. This provides and each_by method. You can use each_by to create groups and iterate further on these groups.
Here is code snippet on how to use each_by
<div class = "small-9 columns vertical-border-left">
<%- #client.contact_details.each_by(3) do |contact_details| %>
<div class="row">
<%- contact_details.each do |contact| %>
<div class="small-3 columns small">
<div> <%= contact.contact_detail_type %> contact </div>
<div> <%= contact.contact_email %> </div>
<div> <%= contact.contact_phone %> </div>
</div>
<% end %>
</div>
<% end %>
</div>

Rails retrieving all records in show controller

In my rails category show controller for categories I have it setup like this
def show
#categories = Category.find_by(params[:name])
end
But when I visit this controller it returns all records of products found in the category instead of single category.
Here is the code in my view controller for category
<div class="grid">
<% #categories.products.each do |product| %>
<%= link_to product_path(id: product.slug, category_name: product.category.name), class: "card" do %>
<div class="product-image">
<%= image_tag product.productpic.url if product.productpic? %>
</div>
<div class="product-text">
<h2 class="product-title"> <%= product.name %></h2>
<h3 class="product-price">£<%= product.price %></h3>
</div>
<% end %>
<% end %>
</div>
What am i doing wrong here?
First of all, for security purposes, you should never trust the params hash to retrieve records. Rails will "make the data safe" if you use a hash as your arguments. Use this code below:
def show
#category = Category.find_by(name: params[:name])
end
Second, usually on a show page, you only want to retrieve one record and therefore the variable should be named as singular. I corrected that above.
Third, it helps if you use proper indenting when posting examples. It makes it easier for us to help you.
Fourth, the line below (I changed #categories to #category) is basically saying: "Now that I have this single category, find all the products associated with it in the products table and put them into the |product| variable for iteration"
<% #category.products.each do |product| %>
I'm not sure what you want to do with the category, but if you keep this line of code, it will always show you all the products. Maybe you only want to show the most recent 3, in which case you could do something like this:
In your controller:
def show
#category = Category.find_by(name: params[:name])
#recent_products = #category.products.order(created_at: :desc).limit(3)
end
In your view:
<div class="grid">
<% #recent_products.each do |product| %>
<%= link_to product_path(id: product.slug, category_name: product.category.name), class: "card" do %>
<div class="product-image">
<%= image_tag product.productpic.url if product.productpic? %>
</div>
<div class="product-text">
<h2 class="product-title"> <%= product.name %></h2>
<h3 class="product-price">£<%= product.price %></h3>
</div>
<% end %>
<% end %>
</div>
You can do this way
in your controller you can write this code
def show
#category = Category.find_by_name(params[:name])
end
and in your view it will work
<div class="grid">
<% #category.products.each do |product|%>
// place your code what you want to display
<% end %>
</div>
I hope it would help you and still if you have any concern please let me know.

How to map Amazon Products API to Rails?

I'm trying to fetch products from the Amazon Products API (using https://github.com/hakanensari/vacuum/) and display them in my Rails app. But how do I bring the product names and photos into my views?
Currently getting:
ActionView::Template::Error (undefined method `image' for #<Array:0x88486aec>):
2: <% if #products.any? %>
3: <% #products.each do |product| %>
4: <div class="product">
5: <%= link_to image_tag(product.image.url), product.url %>
6: <%= link_to product.name, product.url %>
7: </div>
8: <% end %>
main_controller.rb:
class MainController < ApplicationController
def index
request = Vacuum.new('GB')
request.configure(
aws_access_key_id: 'ABCDEFGHIJKLMNOPQRST',
aws_secret_access_key: '<long messy key>',
associate_tag: 'lipsum-20'
)
params = {
'SearchIndex' => 'Books',
'Keywords'=> 'Ruby on Rails'
}
#
# NOT SURE WHERE TO TAKE IT FROM HERE
#
raw_products = request.item_search(query: params)
#products = raw_products.to_h
product = OpenStruct.new(#products)
end
end
index.html.erb:
<% if #products.any? %>
<% #products.each do |product| %>
<div class="product">
<%= link_to image_tag(product.image.url), product.url %>
<%= link_to product.name, product.url %>
</div>
<% end %>
<% end %>
You are getting the error because raw_products isn't an array. AS par vacuum documentation, you will either have to convert it to hash by raw_products.to_h or You can also pass the response body into your own parser for some custom XML heavy-lifting:
MyParser.new(raw_products.body)
So you have to first parse the the response properly before consuming it.
You can just do following:
#products = raw_products.to_h
product = OpenStruct.new(#products)

Need to group shows by day in a rails Application

I am trying to get shows on a certain day to show up just for that day and I would like to be able to see what shows are going on in the next couple of days as well.
The View:
<% t = Time.new %>
<h2 class="center" style="color:#2A2C2B"><u><%= t.strftime("%A, %B %e") %></u></h2>
<% #clubs.each do |club| %>
<!-- # <% club.shows.future.present? %> -->
<h1 class="club"><%= link_to club.name, club.website %> </h1>
<% club.shows.future.each do |show| %>
<h3 class="center"><%= show.pretty_start_time %></h3>
<% show.comedians.each do |comedian| %>
<div>
<ol>
<h4 class="comedian"><%= link_to simple_format(comedian.name),comedian_path(comedian) %></h4>
<p class="bio"><u><%= comedian.bio %></u></p>
</ol>
</div>
<% end %>
<% end %>
<%- end -%>
The Comedy Hub Controller:
class ComedyHubsController < ApplicationController
def show
#clubs = ComedyClub.all
end
end
This might work:
<% shows.goup_by{|show| show.date}.each do |dategroup| %>
<# do something to indicated the group up here? %>
<%= dategroup.each do |show| %>
<li> <%# put details here %> </li>
<% end %>
<% end %>
Assuming, there is a DateTime column on Show called start and the ComedyClub model has a a has_many :shows and the Show model has the belongs_to :comedy_club association defined
In your ComedayHubsController#show method, do the following query
#clubs = ComedyClub.join(:shows).where("shows.start >=?", DateTime.now).order("shows.start ASC")
Now only clubs with shows in the future will be sent to the view and already ordered by start.

kaminari and order_by

So Im listing out all the members of my site and grouping them by name so that the list will be organized better. So in my view all my members are grouped by the first letter of their member name like:
B
Bakedfish
Beercan Dan
Bigmike33x
C
Cynicalassassin
ect..
Anyway, I also want to paginate this list but I cant add Kaminari's pagination arguments to my controller if Im using order because I get an undefined method error.
so this doesnt work:
#members = Member.all.group_by{|u| u.fullname[0].titleize}.page(params[:page]).per(18)
my view looks like this:
<div class="content">
<%= paginate #members %>
</div>
<% #members.keys.sort.each do |starting_letter| %>
<h3>
<%= link_to starting_letter, {:action => :browse, :controller =>:members, :letter => starting_letter } %>
</h3>
<ol>
<% #members[starting_letter].each do |member| %>
<li>
<% if member.is_artist? %>
<%= link_to member.full_name, member_path(member), :class=>"artist" %>
<% else %>
<%= link_to member.full_name, member_path(member) %>
<% end %>
</li>
<% end %>
</ol>
<% end %>
Here is my error message:
NoMethodError (undefined method `page' for #<Hash:0x007f78d4bf48f8>):
app/controllers/members_controller.rb:10:in `index'
Kaminari adds page method to ActiveRecord::Relation but Member.all.group_by returns hash. That is why you get this exception.
I'd suggest to perform grouping after pagination, e.g.:
#members = Member.order(:full_name).page(params[:page]).per(18).to_a.group_by { |u| u.fullname[0].upcase }
UPDATE
In order to use paginate helper you could assign 2 variables, e.g.:
#paginated_members = Member.order(:full_name).page(params[:page]).per(18)
#members = #paginated_members.to_a.group_by { |u| u.fullname[0].upcase }
And pass #paginated_members to the paginate helper.

Resources