initializing and incrementing a variable in one line of code - ruby-on-rails

Is this the DRYest way to do it in ruby?
<% for item in #items %>
<%= n = n + 1 rescue n = 1 %>
<% end %>
which initializes "n" to '1" and increments it as the loop progresses (and prints it out) since this is in one my app's views

You can use a ternary operator:
<% for item in #items %>
<%= n = n ? n+1 : 1 %>
<% end %>
But, depending on what you're trying to do, I'm guessing an each_with_index would be more appropriate
<% #items.each_with_index do |item, n| %>
<%= n %>
<% end %>

You could also rely on ruby's nil coercion to an integer which results in zero.
<% for item in #items %>
<%= n = n.to_i + 1 %>
<% end %>

Um.
n = #items.size

Related

Handling previous and successive records within a collection relative to an item in the view of the collection

A collection is defined in a view, where links for each element's successive and previous items need to be generated. (a css-only lightbox. While the index of those items is accessible,
<% #gallery.each_with_index do |article_gallery, index| %>
<%= succ = #gallery[index + 1] %><%= succ.inspect %>
<%= prev = #gallery[index - 1] %>
<% end %>
The inspection of the object returns the expected object
#<ArticleGallery id: 1, article_id: 16, image: "Screen_Shot_2022-11-17_at_07.46.05.png", position: 2, [...]>
But it's id cannot be accessed. if succ.id in lieu of succ.inspect is called it is deemed to now be a nil object.
undefined method `id' for nil:NilClass
#output_buffer.safe_append=' '.freeze;#output_buffer.append=( succ = #gallery[index + 1] );#output_buffer.append=( succ.id );#output_buffer.safe_append='
What is the proper way to access an attribute for the relative previous or successive object?
On the last iteration #gallery[index + 1] will return nil
Try to use https://apidock.com/ruby/Enumerable/each_cons instead of each_with_index
It will be smth like:
<% #gallery.each_cons(2) do |article_gallery| %>
<%= succ = article_gallery[1] %>
<%= prev = article_gallery[0] %>
<% end %>
The answer by Voltan is a partial answer, where it creates a useful array, but as the docs state, the return is nil & that is failing the requirement.
But that was a bit of a lead-in ot the actual solution. The solution was around, but buried a bit deep using ruby's zip method on array.
Given that the impact is on the view, we show the prev and succ id OR (to make the loop continuous) return the last or first element of the array in case the calculated index returns nil
<% #gallery.zip((0 .. (#gallery.size - 1)).to_a).each do |a, i| %>
<%= a.image_url %>
<% prev = #gallery[i-1] %>
<% if prev.nil? %>
<%= #gallery[-1].id %>
<% else %>
<%= prev.id %>
<% end %>
<% succ = #gallery[i+1] %>
<% if succ.nil? %>
<%= #gallery[0].id %>
<% else %>
<%= succ.id %>
<% end %>
<% end %>

How can I loop through and Save values into an array

The following loop goes through the sales column and lists all 4 existing product values, like 19.99 19.99 3.99 3.99 to the corresponding user id.
<% #sales.each_with_index do |sale, index| %>
<% if current_user.id == sale.user_id %>
<% price = Warehouse.where(:product => sale.product).pluck(:mrr) %>
<%= value = price.split(',').join('.').to_f %>
<% else %>
<% end %>
Now I want to save the results/values into a new global variable and add up each out of "value". So the result of 19.99 19.99 3.99 3.99 should be 47.96.
I'm completely lost. Any Ideas?
You could do something like this:
<% total = 0 %>
<% #sales.each_with_index do |sale, index| %>
<% if current_user.id == sale.user_id %>
<% price = Warehouse.where(:product => sale.product).pluck(:mrr) %>
<%= value = price.split(',').join('.').to_f %>
<% total += value %>
<% end %>
<% end %>
<%= "Total is #{total}" %>
It is highly questionable to have code like this in the view though. You could get prices and calculate totals in your controller instead.
Also note that you are missing an end. I changed the unneeded else to an end.
In your controller you can create a instant variable prefixed by # so it can be used throughout your view
For example in your controller
#total_value = 0
And in your view
<%#sales.each_with_index do |sale, index| %>
<% if current_user.id == sale.user_id %>
<% price = Warehouse.where(:product => sale.product).pluck(:mrr) %>
<%= value = price.split(',').join('.').to_f %>
<% #total_value += value %>
<% else %>
<% end %>
You shouldn't add that kind of logic in your view. Create a view object class (that the controller instantiates) too handle all of this. You also probably can do something like:
user.sales.each do |sale|
total += find_price(sale)
# do more stuff
end
If you are asking 'if current_user.id == sale.user_id' then you most likely doing it wrong.
In that view object you could have a hash that has all the prices you want to show and iterate over that in your view.

auto increment value in each loop

In code:
<% #offers.each do |offer|%>
<%= offer.percentageOff%> <b>% OFF on order of</b>
<%= image_tag('1407951522',:size=>'10x10',:alt=>'Rs.')%>
<%= offer.amountforDiscount%>
<%= button_to 'Delete',{:action=>'destroy',:id=>offer.id},class: "" %>
<% end %>
I am new in rails. I want to show all the offers in a numbered list, I can't use database table because id is not in order. For example:
30 % OFF on order of Rs.2000
13 % OFF on order of Rs.1000
How do i achieve this?
Easiest way if you don't want to use each_with_index then You can define variable #count=0 and display, as loop occur it will be increment by 1
<% #count = 0 %>
<% #offers.each do |offer|%>
<%= #count += 1 %> #I guess you want this to show Sr.No
...... # your code
<% end %>
each_with_index way :
<% #offers.each_with_index do |offer, index|%>
<%= index + 1 %> # index starts from 0, so added 1 to start numbering from 1
...... # your code
<% end %>

How to sum up a list of counts

Apologies if I am going about the wring way for this. But I have the following code and want to have a sum of it rather than two separate numbers:
<% #all_users.each do |i| %>
<%= i.liked_recipes.count %>
<% end %>
The output for this code is as follows:
12 4
What I would like the output to be would be the sum:
16
Also:
<%= #all_users.sum { |u| u.liked_recipes.count } %>
You need some way to keep track of the count:
<% total = 0 %>
<% #all_users.each do |i| %>
<% total += i.liked_recipes.count %>
<% end %>
<%= total %>
A shorter way of doing this would be to use inject
#all_users.inject(0) { |result, i| result + i.liked_recipes.count }
If #all_users is not loaded other than for these recipe counts then it is probably best to let the database do the counting:
LikedRecipe.where(:user_id => #all_users.select(:id)).count

rails - when using Group_by - How to get an Index?

I have the following:
sets = DataSet.all.group_by{ |data| [data.project_id, "-", data.thread_id].join(" ") }
<% sets.each do |range, datas| %>
<p><%= range %>:</p>
<% datas.each do |data| %>
<%=data%>
<p>Last Post<%= data.last.created_at %></p>
<% end %>
<% end %>
Problem is that I need an index. So i updated the above with:
<% sets.each_with_index do |range, datas, i| %>
<p><%= range %>:</p>
<% datas.each do |data| %>
<%= i %>
<%=data%>
<p>Last Post<%= data.last.created_at %></p>
<% end %>
<% end %>
That then breaks, with the error: undefined method `last' for 0:Fixnum
Ideas? thank you
The issue you observe is because of the way parameters are assigned to the block. In your second example, you will observe that range contains an array containing a single range and the matching datas, the datas variable contains the index and i is always nil.
This is because ruby "unsplats" arrays if it is the only parameter to the block. If you have more than one type (in this case an array and an integer), you must hint ruby on what it should do. The simplest way is to use parentheses.
<% sets.each_with_index do |(range, datas), i| %>
...
<% end %>
That way, ruby will know what you mean and split the array up into range and datas. This is actually a feature of ruby's assignment operator in conjunction with the comma operator. It works like this
my_array = [1, 2]
(x, y) = my_array
p x # prints 1
p y # prints 2

Resources