How to store the result when iterating? - ruby-on-rails

I am a Rails newbie so I don't have a clear idea on how to approach this problem.
I have an ActiveRecord::Associations::CollectionProxy object stored in #electives. Specifically, I have
#electives = #degree.electives
Degree and Elective are models with tables degrees and electives. I have defined a has_and_belongs_to_many association between Degree and Elective models.
Additionally, I also have a Course model with a corresponding courses table. I have also defined another has_and_belongs_to_many association between Course and Elective models.
In addition to the above listed tables, I also have degrees_electives and courses_electives join tables.
Now, I want to display on a page, a list of Electives in a Degree, and all the Courses associated to an Elective. So, I want something like:
- Software Engineering Elective A
- COMP SCI 3008 Computer Networks & Applications
- COMP SCI 1234 Object Oriented Programming
- COMP SCI 4567 Algorithm Design & Data Structure Analysis
- Software Engineering Elective B
- MATHS 1012 Mathematics IA
- CIVIL 2000 Civil Engineering Introduction
- Software Engineering Elective C
- COMP SCI 1012 Introduction to Programming
I am able to display the list:
- Software Engineering Elective A
- Software Engineering Elective B
- Software Engineering Elective C
But I don't know how to display the sub-list.
Currently, I have in my controller:
#degree = #student.degrees.first
#electives = #degree.electives
#degree contains a Degree object.
And, my view contains:
<ul>
<% #electives.each do |elective| %>
<li>
<%= elective.name %>
</li>
<% end %>
</ul>
The webpage looks like this:
I would like help with displaying the sub-list.
What I am stuck at is, how should I store the list and make it available to the view, when I call .courses on each element of #electives. For example, I could do:
#electives.each do |elective|
#courses = elective.courses
end
But then, #courses will contain courses that correspond with the last element of #electives, if and when I use #courses in the view.
Is there like a vector data structure available in Ruby that I can push values to? I don't know how to do this. Any help will be very much appreciated. Thank you.

You can iterate over courses that are associated with an elective in the same way as you already iterate over the courses with the only difference to do it nested within the other iteration:
<ul>
<% #electives.each do |elective| %>
<li><%= elective.name %>
<ul>
<% elective.courses.each do |course| %>
<li><%= course.name %></li>
<% end %>
</ul>
</li>
<% end %>
</ul>
To avoid a N + 1 queries problem I suggest eager loading all courses that are associated with the electives in one query by changing your controller to:
#degree = #student.degrees.first
#electives = #degree.electives.includes(:courses)

You don't even need variable
<ul>
<% #electives.each do |elective| %>
<li>
<%= elective.name %>
<ul>
<% #elective.courses.each do |course|%>
<li>
<%= course.name %>
</li>
<% end %>
</li>
<% end %>
</ul>
In controller you better include elective with course to have it initialized, to not have n*m calls to database
#electives = Elective.includes(:courses)

Related

Rails - Use a Helper or a Partial [duplicate]

This question already has answers here:
When to use Helpers instead of Partials
(6 answers)
Closed 7 years ago.
In my Article model, I have 4 different columns: short_effects, long_effects, benefits, and alternatives. They are all text columns.
In my view, I am calling each one in the same basic format:
<% unless #article.short_effects.blank? %>
<hr id="effects">
<h2><span class="glyphicon glyphicon-hourglass"></span>Short-term side effects</h2>
<ul>
<% #article.short_effects.split(';').each do |effect| %>
<li><%= effect.downcase %></li>
<% end %>
</ul>
<% end %>
<% unless #article.long_effects.blank? %>
<hr id="effects2">
<h2><span class="glyphicon glyphicon-time"></span>Long-term side effects</h2>
<ul>
<% #article.long_effects.split(';').each do |effect| %>
<li><%= effect.downcase %></li>
<% end %>
</ul>
<% end %>
.
.
.
to eliminate repetition, I would like to create a helper or a partial... however, I do not know which is better for this situation. I know some people frown upon HTML inside of helpers, but since helpers are used to reduce code from views, I feel that may be the best way. Any advice is greatly appreciated.
There are some existing discussions about this one here. In particular, this question has a variety of (mostly short) answers with some good rules-of-thumb you might consider. I would personally be of the "minimize HTML in a helper" school of thought, however I also like the description of helpers being for specific elements while using partials for larger chunks of code.

Ruby grouping/sorting by attribute and count

I have been struggling with this and after some searching, I haven't been able to find anything online. Users choose from several study session dates (their first choice is the one that is the most convenient for them) and I store their choices as Id's that correspond to the chosen dates. The Id's are stored as an array for each user (ex: [1,3,2,4]). Each study session has a capacity, so what I need to do is sort it by their first choice but if their first choice is over the capacity, I need to place them into their second choice. So far, I have the grouping by first choice done but I don't know how to place all users who are over the capacity into their second choice. Here is my code so far:
<% #choices.all.group_by { |choice| choice.choice.first}.each do |date, choices| %>
<%= #options.where(:id => "#{date}").first.date.strftime('%B %d, %Y') %>
at
<%= #options.where(:id => "#{date}").first.time.strftime('%l:%M %P') %>
<ul>
<% choices.each do |sort| %>
<li><%= sort.name %></li>
<% end %>
</ul>
<% end %>
Thanks for your help!

Access parent through child in view using rails

I have a model Field with children Topics. Topics are given to posts and I want to display the Fields which topics are children of (e.g If a post has the topics 'rofl', 'lol' and 'lmao' and all of these topics belonged to the parent 'Internet abbreviations').
I want to display something like this:
INTERNET ABBREVIATION rofl lol lmao
Here is the code from the view.
<div class="fields">
<% reading.topics.each do |topic| %>
<span class="indivfields">
<%= link_to topic.field.name, field_path(topic.field) %>
</span>
</div>
<div class="subjects">
<% reading.topics.each do |topic| %>
<span class="indivsubjects"> <%= link_to topic.name,field_topic_path(topic.field,topic) %></span>
<% end %>
</div>
<% end %>
The problem is because the first reading.topic.each do is topic and not field so, continuing the example above, the output I end up with is this:
INTERNET ABBREVIATION rofl lol lmao
INTERNET ABBREVIATION rofl lol lmao
INTERNET ABBREVIATION rofl lol lmao
It prints based on the number of children and I want this to display once. Thanks!
Reading has_many field has_many topics it seems. I would structure the models like this:
class Reading
has_many :fields
has_many :topics
end
class Field
belongs_to :reading
has_many :topics
end
class Topic
belongs_to :reading
belongs_to :field
end
That way you can do reading.fields.each:
<%= reading.fields.each do |field| %>
<h1><%= field %>
<%= field.topics.each do |topic| %>
<p><%= topic %></p>
Why? Because you want to have your software to map the domain model (or how things are in the real world) as much as possible. It just seems intuitive, even from an outsider perspective, that a post have the option to be categorized by Field and Topic.
For our application we do the same thing. We have Questions, which have Subjects and Topics, and Topics belong to Subject. Same database schema as the one I have above (just different names).
However if that didn't make sense (hehe) the other ways to solve this are to do a group to move up the models from Topic to Field. Involves SQL (check this out: http://guides.rubyonrails.org/active_record_querying.html#group), and grouping via a hash (Group Hash by values in ruby). Sorry if I am not as helpful as I can, I am a bit tired now.
By the way I suggest don't do random abbreviations like indiv. I know it is in your best intention, and it sounds intuitive to abbreviate individual to indiv, but it's just best coding practice to not have random abbreviations, maybe someone else will join you in the coding and they might think about what indiv is. (I don't have the article to Clean Code but check this out: http://agileinaflash.blogspot.com/2009/07/abbreviations.html)
So I have an answer for you all. One of my classes is still poorly named using the 'indiv' abbreviation so please forgive me for that. I needed to use the group_by method. Here is the code:
<% reading.topics.group_by(&:field).each do |fields, topics| %>
<%= link_to fields.name, field_path(fields), class: "individualfields" %>
<div class="subjects">
<%= topics.collect { |t| link_to t.name, field_topic_path(fields, t), class: "indivsubjects" }.join.html_safe %>
</div>
<% end %>
And thats it. Thanks for getting to this answer must go to various people on the Rails IRC channel. It worked out very nicely because this code is actually smaller than my previous code for rending topics alone, and this renders fields and topics.

combining 2 tables, looping through the results and displaying items from each

So I'm trying to combine two tables and show the results in order of the start_date.
I've tried a few things but because its technically a nested loop its giving me double results for each item.
The code i currently have is as follows
<% #subcategory = Subcategory.all %>
<% #product = Product.all %>
<% (#product + #subcategory).each do |product, subcategory|%>
<% if product.display_on_home_page and !product.is_highlight_product and !(product == '..') or subcategory.
display_on_home_page and !subcategory.is_highlight_product and !(subcategory == '..')%>
<div class="column_entry">
<%= link_to image_tag(subcategory.image_attachment.url(:normal_page_size)), subcategories_content_url(subcategory.id), :controller=>'subcategories' %>
</div>
<% end %>
<% if product.price_from %>
<div class="column_entry">
<div class="product_special">
<span class="a">From Only</span>
<span class="b"><%= number_to_currency(product.price,:unit=>'€') %></span>
</div>
<%= link_to image_tag(product.product_image.url(:normal_page_size)), products_content_url(product.id), :controller=>'products' %>
</div>
<% else %>
<div class="column_entry">
<div class="product_special">
<span class="a">Only</span>
<span class="b"><%= number_to_currency(product.price,:unit=>'€') %></span>
</div>
<%= link_to image_tag(product.product_image.url(:normal_page_size)), products_content_url(product.id), :controller=>'products' %>
</div>
<% end %>
<% end %>
I know this is quite a long an complex statement, its supposed to loop through all of the subcategories and all of the products and display the images, there are also two different ways of displaying the price based on a boolean that says whether the price is a specific amount or it starts from a given price.
at the moment its reading through the loop but its giving me the error
undefined method `is_highlight_product' for nil:NilClass
since this is the first column in the table that is referenced and its breaking here I think that there must be some conflict in its ability to see the information stored in the table.
I'm still quite new to ruby on rails so any help or even just a nudge in the right direction would be very much appreciated.
If you would like more information just ask in the comments and I'll put it up as fast as I can.
The problem here is, when you do something like this:
(#product + #subcategory).each do |product, subcategory|
The local variable product will iterate firstly through products, then through subcategories, and the local variable subcategory will always be nil.
What you can do, a dirty way - check
if product.is_a?(Product)
# do your things
elsif product.is_a?(Subcategory)
# do other things
end

RoR View: List results grouped under categories

I am trying to group a set of products (obtained typing a query) based on taxonomy(on of the attributes of a product)
My desired output is
Taxonomy 1
prod1 prod2 prod3 prod4
prod 5 ...
Taxonomy 2
pod6 prod7
Taxonomy 3
prod8 prod9..
I am using the following code in the view:
<% taxonomies.each do |taxonomy|%> #"taxomonies" is a set of unique taxonomies for retrieved products
<h1><%= taxonomy%></h1>
<ul>
<% collection.each_with_index do |product,i| %> #"collection" is the list of products retrieved
<li>
<%#ptaxon = product.get_taxonomy%>
<%if #ptaxon == taxonomy%>
<%code for listing product%>
<%end%>
</li>
<%end%>
</ul>
<%end%>
This groups the products based on taxonomies but the format is not what I desire. Could someone please point out my mistake.
EDIT: also tried using < br > , but doesn't help!
This is the output I'm getting. I want the taxonomies earrings, bracelets and necklaces to start from a new line.
Thanks
If you have your associations setup correctly, you can do it like this:
<% taxonomies.each do |taxonomy| %>
<%= taxonomy.name %>
<% taxonomy.products.each do |product| %>
<%= product.name %>
<% end %>
<% end %>
Models should be something like:
class Taxonomy
has_many :products
end
class Product
belongs_to :taxonomy
end

Resources