I have a Ruby app with Products and Categories.
I would like to have a category index page that displays 1 product photo for each category.
Right now, it shows the last product photo for all categories. (So, with 16 categories, it shows the product photo for category 16 on every category.)
I think I need to fix how I store or call the Products array. How do I do that?
Code --
in categories_controller.rb
def index
#categories = Category.all.order('name ASC')
#products = []
#categories.each do |category|
#products = Product.where(category_id: category.id).take(1)
end
end
in categories/index.html.erb
<% #categories.each do |category| %>
<% #products.each do |product| %>
<%= link_to image_tag(product.image), category %>
<% end %>
<%= link_to category.name, category %>
<%= category.description %>
In your index action, change the line:
#products = Product.where(category_id: category.id).take(1)
To:
#products << Product.where(category_id: category.id).take(1)
UPDATE:
Since take(1) will return an object in array, you need to simply change it to:
#products << Product.where(category_id: category.id).take
Related
I want to categorise Companies by letters in my listing page.
But there are multiple records that start with the same letter. I can get the first letters of Company names with the .first method.
But my code shows duplicate letters.
Controller:
#brand = Brand.where(slug: params[:brand]).first
#companies = Company.where(brand_id: #brand.id)....
View:
<% #companies.each do |c| %>
<li>
<%= link_to company_path(c.brand.name,c.id) do %>
<%= c.name.first %>
<% end %>
</li>
<% end %>
How would I show only unique letters?
New code (with some changes, assuming company belongs_to brand and brand has_many companies)
#brand = Brand.where(slug: params[:brand]).first
#companies = #brand.companies
##list is a hash with letters as keys and an array of companies starting with this letter
#list = Hash.new { |h,k| h[k]=[] }
#companies.each { |comp| #list[comp.name[0]] << comp }
#As “engineersmnky” suggested on a comment the last two sentences can be simplified:
#list = #companies.group_by { |c| c.name[0] }
View:
<% #list.each do |letter, companies| %>
<h2><%= letter %><h2>
<% companies.each do |c| %>
<li>
<%= link_to c.name, c %>
</li>
<% end %>
<% end %>
You're iterating through all companies so if you have companies like, Facebook and Foxtel, a link with F tag is going to be duplicated. You can do something like
categories = #companies.where(brand_id: #brand.id).pluck(:name).map(&:first).uniq
In the above code all it is doing is getting a list of company names and extracting out the first letter and removing the duplicates.
Now you can iterate through the categories and create a link for the category and inside the category page you can get companies starting from that letter
Company.where('name LIKE ?', "%#{starting_character}%")
starting_character gets sent from the list of categories page.
I need to paginate an array. When I click the other pages, I see the same 25 items as displayed on the first page. The URL is http://localhost:3000/?page=2 but it's the same 25 items. There are about 100 total.
Here's my controller method:
def index
#items = Array.new
API.items.all! do |i|
#items << i
end
#paginated_items = #items.paginate(per_page: 25)
end
Here is my html file:
<%= will_paginate #paginated_items %>
<ul class="items">
<% #paginated_items.each do |i| %>
<li>Subject: <%= i.subject %>, ID: <%= i.id %></li>
<% end %>
</ul>
<%= will_paginate #paginated_items %>
I also added require 'will_paginate/array' to an initializer.
I think you missing page: params[:page] in index controller, this is how will_paginate know what page you currently now
def index
#items = Array.new
API.items.all! do |i|
#items << i
end
#paginated_items = #items.paginate(page:params[:page],per_page:25)
end
I am new in RoR.
The problem is, I created fully functional product categorization with Ancesrty. But now I want to be able to retrieve products that is under these subcategories.
This is my categories show controller
#category = Category.find(params[:id])
Here is categories#show view.
<b>Name of the category:</b>
<%= #category.name %>
<div class="product"
</div>
</p>
<% unless #category.children.empty? %>
<ul id="sub-menu">
<% #category.children.each do |sub1| %>
<%= link_to (sub1.name), sub1 %>
<%end%>
<%end%>
It all works fine. but now I want to add in view categories/show function that shows all products that is under that category.
I added such code.
In category/show controller
#cat_id = #category.id
#product = Product.where("category_id = ?",#cat_id)
In the categories show view I added
<td><%= #product.name %></td>
Then clicking on some subcategory where should appear few products, there just shows up Product
To check if the code is right I put in the console. There it works fine and retrieve products related to this category.
I dont understand why then code not working in webserver when I launch application ?
Could it be because of some erorr in Associations ?
Thanks !
in your controller, a more readable way is to use the plural form to indicate that you are expecting more than 1 object
#products = Product.where("category_id = ?", #cat_id)
Then in the view, just loop through these products
<% #products.each do |product| %>
<%= product.name %>
<% end %>
#product = Product.where("category_id = ?",#cat_id)
will return an array if there are any products. So you will need to loop through the array.
<% #product.each do |product| %>
<%= product.name %>
<% end %>
I accept both of the answers, But I want to suggest to use Active Record Association for this type of problems. This makes your solution easier.
If you want to fetch only one product, you can use the find_by_ helper method of the model:
#product = Product.find_by_category_id(#cat_id)
With this it will fetch the first matching product which has category_id equal to #cat_id.
If you want to fetch all the products which belong to a category, you need to fetch all the products as others suggested:
#products = Product.where(:category_id => #cat_id)
And then in the view:
<% #products.each do |product| %>
<%= product.name %>
<% end -%>
For about a week now I have been trying to get a view to render. I have an application that needs to be able to export collections so I decided to use a line partial that renders as a .txt and .csv in the web browser. So far so good in terms of getting the entire collection to render (line by line). However, I am having trouble getting certain collection objects (in this case products) to duplicate themselves based on a certain attribute (size element).
The code below is kind of where I am stuck at now
Controller
class PexportController < ApplicationController
layout 'csv'
def index
end
def show
#feed_template = params[:id]
#products = Product.find :all
#products.each do |product|
unless product.size.nil? || product.size.empty? || product.size.kind_of?(Fixnum)
#products << new_products_for(product)
end
end
respond_to do |format|
format.html
format.text
end
end
private
def new_products_for(product = {})
products = Array.new
product.size.each do |p|
products << Product.new(p.attributes)
end
products
end
end
View
<%= render partial: 'pexport/p', collection: #products %>
Partial
<%= p.sku %> <%= p.name %> <%= p.price %> ......
I basically just need to get the controller method to work. The attribute :size that I am using for the line duplicator is simply an array like so [1,2,3]. And I would like products that contain this size attribute to duplicate themselves based on the number of sizes in their size array. I am not even sure if I am going about it the right away but it has gotten to that point where I am going in circles so I figured I would post it.
Alternative answer: is there some reason you need to duplicate the entire object in the controller? You could simplify things by just doing something like this in your view:
<% if p.size.is_a?(Array) %>
<% p.size.each do |s| %>
<%= p.sku %> <%= p.name %> <%= p.price %> <%= s %>
<% end %>
<% else %>
<%= p.sku %> <%= p.name %> <%= p.price %> <%= p.size %>
<% end %>
Or something to that effect.
If I understand what you're doing, you have a list of products, but some of those product entries should be displayed as more than one product if they have more than one size. Assuming that's correct, your logic is a bit off: new_products_for is returning an array which is being added as a single element at the end of your #products array. So your partial won't know how to deal with it. You could try something like this:
#my_products = Product.find :all
#products = []
#my_products.each do |p|
if p.size.blank? || p.size.kind_of?(Fixnum)
#products << p
else
#products += new_products_for(p)
end
end
Also, I suggest you make the Product.new line more explicit:
products << Product.new(:sku => p.sku, :name => p.name, ...)
p.attributes will give you all the attributes of the model, including id, created_at, updated_at which may interfere with what you're doing.
How can I show recent added #post and #photos in one list? For example:
post - LAlala (10.10.2011)
photos - [] [] [] [] (1.1.2011)
post - Bbbdsfbs (2.12.2010)
post - Lasdasdf2 (2.10.2009)
#posts = Post.limit(20).order('created_at desc')
#photos = Photo.limit(20).order('created_at desc')
#recent_items = (#posts + #photos).sort_by(&:created_at)
<% #recent_items.each do |item| %>
<% if item.class == "Photo" %>
<%= image_tag item.url %>
<% else %>
<%= item.title %>
<% end %>
<% end %>
Alternatively, use group_by to do it like this:
#recent_items = (#posts + #photos).group_by(&:created_at)
<% #recent_items.each do |date, items| %>
Date: <%= date %>
<% items.each do |item| %>
Show information here.
<% end %>
<% end >
I would move the view logic into a helper if I were you for DRYer code.
It is much better to do this is the database.
I just say this: polymorphism + database views.
Create a database view which contains the columns you need from both Post and Photo, including the column "type" containing a the name of the model (you need it for the polymorphism). Call this view for example "list_items". Then create a model called "ListItem". Then you can use this model like any other, paginate it and whatever you need to do.
ListItem.order("created_at > ?", Date.yesterday).page(params[:page])
And don't forget to configure the polymorphic association
However, all this is much easier to accomplish with the listable gem. Check it out!