Rails many to many relations with has many through relationships - ruby-on-rails

I have the following models using the has_many :through relationship.
A recipe can have many seasons.
A season can have many recipes.
Recipe
class Recipe < ApplicationRecord
attribute :name
has_many :recipe_seasons
has_many :seasons, through: :recipe_seasons
end
Season
class Season < ApplicationRecord
has_many :recipe_seasons
has_many :recipes, through: :recipe_seasons
end
Recipe Season
class RecipeSeason < ApplicationRecord
belongs_to :recipe
belongs_to :season
end
I'm currently displaying all recipes on the index page using the the following
Controller
def index
#recipes = Recipe.all
render index: #recipes, include: [:recipe_seasons, :seasons]
end
View
<% if #recipes.present? %>
<% #recipes.each do |recipe| %>
<%= link_to recipe.name,[recipe] %>
<% end %>
What I want to do is to have the seasons displayed with the each recipe. A recipe can have more than one season and so I added another for loop inside the existing one for recipes.
I have so far tried:
<% #recipes.each do |recipe| %>
<% recipe.seasons.each do |season| %>
<%= link_to recipe.name,[recipe] %>
<%= season.name %>
<% end %>
<% end %>
<% end %>
Current Behaviour
Recipe 1 - Season 1
Recipe 1 - Season 2
Expected Behaviour
Recipe 1 - Season 1, Season 2
Recipe 2 - Season 4

You must include the seasons in the body parameter of the link_to (the text displayed in the link)
<% #recipes.each do |recipe| %>
<%= link_to "#{recipe.name} - #{recipe.seasons.map(&:name).join(', ')}", [recipe] %>
<% end %>

Related

Rails loop showing duplicate results

I have three models with the following associations:
class Product < ApplicationRecord
belongs_to :store
has_many :variants, dependent: :destroy
end
class Store < ApplicationRecord
has_many :variants
belongs_to :user
has_many :products, dependent: :destroy
end
class Variant < ApplicationRecord
belongs_to :product
belongs_to :store, optional: true
end
And I'm counting the products & variants of each user with the following:
#products = current_user.store.products.group(:subcategory_id).count
#variants = current_user.store.variants.group(:subcategory_id).count
The above returns this #products => {181=>1, 185=>1}
and this #variants => {181=>2, 185=>1}
Finally when I try to loop through each of the above hashes the results show up correctly but they also show up two times(dublicate results). Any ideas on how to fix this??
<% #products.each do |product_key, product_value| %>
<% #variants.each do |variant_key, variant_value| %>
<%= #child_category.name %> - <%= #subcategory.name %><br>
Products: <%= product_value %><br>
Variants: <%= variant_value %><br>
Total Products: <%= product_value + variant_value %><br>
<% end %>
<% end %>
This is the result:
This is not duplicating anything, this is expected behavior. It shows each product with its variants.
You're looping through two hashes, which contains 2 pairs, so the outer loop executes 2 times and the inner loop executes 2 * 2 => 4 times.
This is the expected behavior.
And if you wanted to show only a single pair, you can add if condition over there for subcategory -
i.e. I wanted to show only results where subcategory is Boys then you can use following code -
<% #products.each do |product_key, product_value| %>
<% #variants.each do |variant_key, variant_value| %>
<% if #subcategory.name == 'Boys' %>
<%= #child_category.name %> - <%= #subcategory.name %><be>
Products: <%= product_value %><be>
Variants: <%= variant_value %><be>
Total Products: <%= product_value + variant_value %><be>
<% end %>
<% end %>
<% end %>

Can't display categories under category type

I have two different models category and category type i just want to display categories under category type but i don't know how.
Iā€™m using has_many and belongs_to association where the category has a foreign key 'categorytype_id'
I've tried but every time it displays the category type with just one category
Index.html.erb
<% #categories.each do |category| %>
<% =category.categorytype.label %>
<% =category.label %>
<% end %>
category.rb
class Category < ApplicationRecord
has_many :ads
belongs_to :categorytype
end
categorytype.rb
class Categorytype < ApplicationRecord
has_many :categories
end
i want to display all categories that belongs to that specified category type without repetition
Thank you!
CategoryType has many categories, so it should be
<% #category_types.each do |category_type| %>
<%= category_type.label
<% category_type.categories.map do |category| %>
<%= category.label %>
<% end %>
<% end %>
You'll loop through each CategoryType, display the label, then display associated categories

Displaying User Avatar (without duplicates) for each post in a Collection List with Rails 5

šŸ‘‹ all,
I want to display a list of collections with many posts.
So I call all collections in the controller as:
def index
#collections = Collection.order("RANDOM()")
end
Then in the View:
<% #collections.each do |collection| %>
<%= link_to collection.title, collection %>(<%= collection.posts.count %>)
<!-- Designers (Users) -->
<% collection.posts.each do |post_designer| %>
<!-- I want to display designer avatars in here, I have designer_id from the post, but how do I access Designer table to pull avatar? -->
<%= post_designer.designer_id %>
<% end %>
<!-- Images -->
<% collection.posts.each do |post| %>
<%= link_to image_tag(post.image.thumb.url.to_s, class: "fr"), collection %>
<% end %>
<% end %>
My question is that:
I want to display designer avatars in here instead of designer_id, I have designer_id from the post, but how do I access Designer table to pull avatar?
Thank you!!!! šŸ™
Relations:
models/collection.rb
class Collection < ApplicationRecord
belongs_to :designer
has_many :collectivizations
has_many :posts, through: :collectivizations
end
models/collectivization.rb
class Collectivization < ApplicationRecord
belongs_to :post
belongs_to :collection
end
models/post.rb
class Post < ApplicationRecord
belongs_to :category
belongs_to :designer
has_many :collectivizations
has_many :collections, through: :collectivizations
---------------
šŸ‘ SOLUTION
It looks like I just an obvious typo error! šŸ¤¦ā€ā™‚ļø The code below works, but it gives dublicates if there is more than 1 post for an user. How can I fix the duplicates?
<% collection.posts.each do |post_designer| %>
<%= link_to image_tag(post_designer.designer.avatar.url.to_s, class: "avatar-small ml1"), post_designer, class: "fl" %>
<% end %>
Try change your code like below. It will fetch first post for designer and you won't see any duplicates for designer.
<% collection.posts.select("DISTINCT ON (designer_id) *").each do |post_designer| %>
<%= link_to image_tag(post_designer.designer.avatar.url.to_s, class: "avatar-small ml1"), post_designer, class: "fl" %>
<% end %>

Iterate over has_many through relationship and include data from joining table

I have a very simple rails app with three models: Recipes, Ingredients, and a joining table Quantities that stores the amount of each ingredient in the recipe. For one recipe, I want to list all the associate ingredients and the amount found in the joining table. How do I iterate over the ingredients, but also include the data from the quantities table?
class Recipe < ActiveRecord::Base
has_many :quantities
has_many :ingredients, through: :quantities
accepts_nested_attributes_for :quantities, :reject_if => :all_blank, :allow_destroy => true
end
and:
class Ingredient < ActiveRecord::Base
has_many :quantities
has_many :recipes, through: :quantities
end
and finally joining table:
class Quantity < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
accepts_nested_attributes_for :ingredient, allow_destroy: true
end
It seems like it should be really easy to do this iteration but I am not sure how.
show.html.erb:
<% #recipe.ingredients.each do |ingredient| %>
<% #I know the line below is wrong, but not sure how
# to iterate over the ingredients for the recipe and
# include the amount field from the quantities table
# as well as the ingredient name. %>
<li><%= ingredient.amount ingredient.name %></li>
<% end %>
Thank you!
In your controller's action do something like this:
#recipe = Recipe.includes(:ingredients, :quantities).find(params[:id]) # avoid N+1
and then, in your view:
<% #recipe.quantities.each do |quantity| %>
<%= quantity.ingredient.name %> -
<%= quantity.amount %>
<% end %>
The join table quantities is likely to have one one row for a combination of recipe and ingredient, even though the has_many :through implementation allows for multiple rows.
This allows for accessing the ingredient quantity and name as follows:
<% #recipe.ingredients.each do |ingredient| %>
<li>
<%= ingredient.quantities.first.amount %>
<%= ingredient.name %>
</li>
<% end %>

Rails 3.1 :has_many, :through complex ordering

I have an orders model with line_items and vendors. When displaying an order, I want to group line_items by vendors.
class LineItem < ActiveRecord::Base
belongs_to :order
belongs_to :vendor
end
class Order < ActiveRecord::Base
has_many :line_items
has_many :vendors, :through => :line_items
end
class Vendor < ActiveRecord::Base
has_many :line_items
end
I want to display a sorted list of vendors and line items:
You have placed an order for the following items:
Vendor 1
Line item 1
Line item 2
Line item 3
Vendor 2
Line Item 4
Line Item 5
...
My current thought is
order.vendors.each do |a_vendor|
a_vendor.name
!!?? AND THEN WHAT GOES HERE ??!!
end
please help. I can't figure this out. maybe this could be done by sorting?
If the order only has one vendor, then I only want to show the one vendor.
How about this:
<% #order.line_items.all.group_by{|i| i.vendor}.each do |vendor, items| %>
<%= content_tag :h2, vendor.id %>
<ul>
<% items.each do |i| %>
<%= content_tag :li, i.id %>
<% end %>
</ul>
<% end %>
[edits]
sort_by(&:vendor) is the same as sort_by{|v| v.vendor}, but the block-style syntax gives you a little more flexibility. For example, you can sort by vendor name in the controller with:
#sorted = #order.line_items.all.group_by(&:vendor).sort_by{|vendor, items| vendor.name}
Then in the view:
<% #sorted.each do |vendor, items| %>
<%= content_tag :h2, vendor.name %>
<ul>
<% items.each do |i| %>
<%= content_tag :li, i.id %>
<% end %>
</ul>
<% end %>
Alternatively, can sort in the model by adding an SQL snippet
to the :order option of the has_many association.
(See: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many)
class Order < ActiveRecord::Base
has_many :line_items, :order => "item_number"
has_many :vendors, :through => :line_items, :order => "name"
end
Then your view is very simple:
<% #order.vendors.each do |vendor| %>
<h3><%= vendor.name %></h3>
<ul>
<% vendor.line_items.where(:order_id=>#order.id).each do |item| %>
<li><%= item.description %></li>
<% end -%>
</ul>
<% end -%>

Resources