How to map Amazon Products API to Rails? - ruby-on-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)

Related

How to fix the error "undefined method" in my Rails Geocoder?

My code is working in console but not in App
➜ Meet-and-Eat git:(master) ✗ rails c
Running via Spring preloader in process 15789
Loading development environment (Rails 5.2.2)
2.5.3 :001 > i = ["10 Palmerston Street", "DERBY"]
=> ["10 Palmerston Street", "DERBY"]
2.5.3 :002 > result = Geocoder.search("#{i[0]}, #{i[1]}").first.coordinates
=> [52.9063415, -1.4937474]
My code :
<% #places = [] %>
<% #placesCoordinations = [] %>
<% #information.each do |i| %>
<% #places.push([i.address1, i.town, i.postcode, information_path(i)]) %>
<% end %>
<% #places.each do |i| %>
<% result = Geocoder.search("#{i[0]}, #{i[1]}").first.coordinates %>
<% #placesCoordinations.push(result) %>
<% end %>
Error :
NoMethodError in Information#full_map_adresses.
Showing /Users/mateuszstacel/Desktop/Meet-and-Eat/app/views/information/full_map_adresses.html.erb where line #10 raised:
undefined method `coordinates' for nil:NilClass
<% #places.each do |i| %>
<% result = Geocoder.search("#{i[0]}, #{i[1]}").first.coordinates%> //this line is breaking my app
<% #placesCoordinations.push(result) %>
<% end %>
But if I use only single location or postcode or street address that work but i need to use both of them to be more precision.
<% #places = [] %>
<% #placesCoordinations = [] %>
<% #information.each do |i| %>
<% #places.push([i.address1, i.town, i.postcode, information_path(i)]) %>
<% end %>
<% #places.each do |i| %>
<% result = Geocoder.search("#{i[2]}").first.coordinates %>
<% #placesCoordinations.push(result) %>
<% end %>
The error message undefined methodcoordinates' for nil:NilClassindicates that theGeocoder.search("#{i[0]}, #{i[1]}")itself is successful, butGeocoder.search("#{i[0]}, #{i[1]}").firstsimply returnsnil`.
It seems like your #information array contains at least one address that cannot be resolved. There might be many reasons: Perhaps there is just a typo in the address or it is a very small village or an address in a country which is not supported by the service you are using.
Tip to debug: Change your code to show what it passes to the method and if there were any results. Something like this might help:
<% #places.each do |i| %>
Address string: <%= "#{i[0]}, #{i[1]}" %>
<% result = Geocoder.search("#{i[0]}, #{i[1]}").first %>
Result: <%= result.present? %>
<% #placesCoordinations.push(result.coordinates) if result.present? %>
<% end %>
Furthermore: I suggest moving code like this to a model, the controller or a helper. It feels like this doesn't belong in an ERB view.
Finally that work !
Inside of the model :
class Information < ApplicationRecord
geocoded_by :address
after_validation :geocode
def address
[address1, address2, town, postcode].compact.join(", ")
end
end
then in terminal run command :
rake geocode:all CLASS=Information SLEEP=0.25 BATCH=100

(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 4 retrieve nested attributes for display in an index.html.erb

Just looking to find out how to retrieve nested images for display on my front page. I have no problems with a standard model but have been unable to find how to bring has_many nested attribute through. All my nested Forms work fine just have neglected the front end.
eg. product has nested product_images. This doesn't look like a clever way of doing it as the last five images uploaded wont necessarily be related to the last five products added.
Could someone please share an example.
cheers
app/controller/home_controller.rb
class HomeController < ApplicationController
def index
#products = Product.last(5)
#product_images = ProductImage.last(5)
end
end
app/views/home/index.html.erb
<% #products.each do |pd| %>
<div><%= pd.product_name %>
<% end %>
<% #product_images.each do |pd| %>
<%= image_tag (pd.product_image(:medium)) %>
<% end %>
</div>
You can try this:
app/controller/home_controller.rb
class HomeController < ApplicationController
def index
#products = Product.last(5)
#product_ids = #products.collect(:id)
#product_images = ProductImage.where(:id => #product_ids).last(5)
end
end
app/views/home/index.html.erb
<% #products.each do |pd| %>
<div><%= pd.product_name %>
<% end %>
<% #product_images.each do |pd| %>
<%= image_tag (pd.product_image(:medium)) %>
<% end %>

Display products from ShopSense API

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.

Refactoring acts_as_taggable suggestions?

I have an application with a list of majors and each one is tagged with categories using the acts-as-taggable-on gem. I have a page where you can explore majors by category. So, you see the categories and grouped under the category is a list of the majors.
My categories_controller.rb file:
def index
#creative = Major.tagged_with("creative arts")
#engineering = Major.tagged_with("engineering and technology")
#mechanics = Major.tagged_with("mechanics and construction")
#transportation = Major.tagged_with("transportation")
#science = Major.tagged_with("science")
#math = Major.tagged_with("math")
#resources = Major.tagged_with("natural resources")
#healthcare = Major.tagged_with("health care")
#social_sciences = Major.tagged_with("social sciences")
#education = Major.tagged_with("education")
#law = Major.tagged_with("law")
#management = Major.tagged_with("management and marketing")
#administrative = Major.tagged_with("administrative and clerical")
#services = Major.tagged_with("services")
#tags = Major.tag_counts
end
You can see the duplication. This is compounded on the view template.
Here's part of the index.html.erb page:
<!-- Creative Arts -->
<h2 class="major-categories-landing">Creative Arts</h2>
<% #creative.sample(10).each do |creative| %>
<%= link_to creative, class: 'span2 category-landing' do %>
<%= image_tag creative.image(:similar), class: 'img-polaroid', id: 'category-landing-list' %>
<p class="category-landing-list-name"><%= creative.name %></p>
<% end %>
<% end %>
<%= link_to "View all #{#creative.count} majors in this category.", category_path("creative arts"), class: "view-category-show-page" %>
<!-- Social Sciences -->
<h2 class="major-categories-landing">Social Sciences</h2>
<% #social_sciences.sample(10).each do |ss| %>
<%= link_to ss, class: 'span2 category-landing' do %>
<%= image_tag ss.image(:similar), class: 'img-polaroid', id: 'category-landing-list' %>
<p class="category-landing-list-name"><%= ss.name %></p>
<% end %>
<% end %>
<%= link_to "View all #{#social_sciences.count} majors in this category.", category_path("social sciences"), class: "view-category-show-page" %>
and so on for each category. I have tried #category = Major.tagged_with(params[:tag]) and many variations to that to no avail. This is my first time working with acts_as_taggable_on and although I've read the documentation over and over I can't quite figure this out.
I hope to extend this out throughout the application and so I want to figure it out now before I get a lot duplicate code. Thanks for sharing any ideas or suggestions!!
I am running a rails 3.2.11 app.
UPDATE
Here's how much better this is now:
My categories_controller.rb file:
def index
#major_categories = ["creative arts", "social sciences", "science", ....]
end
My index.html.erb page:
<% #major_categories.each do |c| %>
<!-- Title and blue strip -->
<div class="category-strip">
<div class="container">
<h2 class="major-categories-landing"><%= c %></h2>
</div>
</div>
<!-- Show Each Major in this Category -->
<div class="container">
<div class="row-fluid">
<% Major.tagged_with(c).order('RANDOM()').limit(10).each do |major| %>
<%= link_to major, class: 'span2 category-landing' do %>
<%= image_tag major.image(:similar), class: 'img-polaroid' %>
<p class="category-landing-list-name"><%= major.name %></p>
<% end %>
<% end %>
</div>
<!-- Link to View All Majors -->
<div class="row-fluid">
<div class="view-all-category">
<%= link_to "View all #{Major.tagged_with(c).count} majors in this category.", category_path(c), class: "view-category-show-page" %>
</div>
</div>
</div>
<% end %>
I would do something like this:
# in categories_controller.rb
def index
#categories = ["creative arts", "engineering and technology",
"mechanics and construction", ...]
end
# in index.html.erb
<%= render partial: "category", collection: #categories %>
# in _category.html.erb
<h2 class="major-categories-landing"><%= category.titleize %></h2>
<% Major.tagged_with(category).order('rand()').limit(10).each do |major| %>
<%= link_to major, class: 'span2 category-landing' do %>
<%= image_tag major.image(:similar), class: 'img-polaroid',
id: 'category-landing-list' %>
<p class="category-landing-list-name"><%= major.name %></p>
<% end %>
<% end %>
<%= link_to "View all #{Major.tagged_with(category).count} majors in this category.",
category_path(category), class: "view-category-show-page" %>
Btw: The link to each major is invalid html. A link (because a it is an inline element) should not contain a paragraph (because p is a box element). Furthermore each link for each category would have the same id, but ids must be unique in each html document.

Resources