Ruby: showing one subarray per page - ruby

I am using Ruby (+ Sinatra) to work on one of my web projects.
I have an array with quite a bit of content and only want to display 10 of the array elements per page.
So what I did so far is:
creating an array with all of the content
ary = ["ex1", "ex2", "ex3", … ,"ex60" ] // all elements
splitting the array into subarrays
ary.each_slice(10).to_a // subarrays with fewer content
Now, I need a way to split the subarrays into single arrays and give them a name,
for example:
#subAry1 # ex1, ex2, ex3, … ex10
#subAry2 # ex11, ex12, ex13, … ex20
#subAry3 # ex21, ex22, ex23, … ex30
I stuck on creating these arrays with a continuing number in the array name.
When I would have my arrays split, I would use this in my .erb file:
<% currentAry = #subAry1 %>
<% currentAry.each do |element| %><%= element %><% end %>
and this to change the content, if the "next" button gets pressed:
currentAry = #subAry + '1'
Can somebody help me, or is it even an effective way, to split/display array elments on my page?

How about an array of arrays? Here's something to help you get started.
all = ary.each_slice(10).to_a
current_page = 0
In the ERB file:
<% all[current_page].each do |element| %><%= element %><% end %>
and after the "next" button gets pressed
current_page += 1

Related

Can I use sort and uniq on an array of chef node attributes?

We have a template that generates a bash script, that includes a list of patches to check for based on node attributes - specifically the role assigned to the node.
patchlist=( <%= node['oracledb']['install']['oneoff']['db_oo_apply'] rescue nil %> <%= node['oracledb']['install']['oneoff']['db_psu_num'] rescue nil %> )
I've snipped the actual list a bit, but you get the point.
The issue is that there are potentially duplicate entries between these attributes, so we want to sort them and get a unique list.
Also, complicating matters, not all nodes in every environment have those attributes - which is why we have the rescue nil sprinkled in there.
I can build the array as
patchlist=( <%= ( node['oracledb']['install']['oneoff']['db_oo_apply'] + ' ' + node['oracledb']['install']['oneoff']['db_psu_num'] rescue nil).split(' ').uniq.sort.join(' ') %> )
which works, if all the attributes have values.
But what seems to happen is that if any single attribute in the list is empty, the rescue nil kicks in and the entire array comes back as nil.
I think that in the first variant, the scope of the rescue nil is limited to the specific attribute, but in the second it applies to the entire string.
So, can I somehow build this array, have it sorted and unique, and still control for cases where individual elements in the array might be null?
just use pure ruby for that, for instance:
irb(main):001:0> ([nil] + [2,1]).compact.uniq.sort
=> [1, 2]
in short, concatenate arrays into a new array, compact it to get a copy of the concatenated array with all nil elements removed, then apply uniq and sort.
One way to achieve this is to create an actual array of node attributes. In your current implementation, it is not an array, just attributes separated by space.
This is a little bit of logic overload on the template, but it should work.
Example template:
<% p_list = %W( #{node['oracledb']['install']['oneoff']['db_oo_apply']} #{node['oracledb']['install']['oneoff']['db_psu_num']} )
<% p_list_fin = p_list.uniq.sort %>
patchlist=( <% p_list_fin.each do |p| %><% next if p.nil? %><%= p %> <% end %>)
Of course the creation of array p_list of node attributes can be done from within recipe and passed in variables of the template resource as well.

Retrieve database record + another option value using options_for_select in Ruby on Rails

I am studying creating a form on Ruby on Rails but I cannot seem to know how to return the values I wanted using options_for_select.
I wanted to retrieve all position numbers + add 1 to the last number as a select option every time a user creates a new "subject".
e.g. user creates a new Subject
in the Form field, Position. The options will be 1,2,3(numbers retrieve in the database) and 4(being the new number not yet in the database)
I successfully tried retrieving the database values and the "other" value separately but I could not join them to return together in the same option field.
However, I can add them together but the instance variables are manually added one by one.
Here's the code…
In views and controller
<%= f.select(:position, options_for_select([#position, #positionTwo.position, #position.last, #additional])) %>
#position = Subject.pluck(:position)
#positionTwo = Subject.find(2)
#additional = Subject.pluck(:position).size + 1
generates
options 1,2,3,4 but results are added manually
I successfully tried retrieving the database values using:
<%= f.select(:position, options_for_select(#position)) %>
#position = Subject.pluck(:position)
this generates options 1,2,3
for the "other" value
<%= f.select(:position, options_for_select(#additional)) %>
#additional = Subject.pluck(:position).size + 1
it generates option 4
What my expected behavior and result should be
options 1,2,3,4 generated dynamically
the 1,2,3 is retrieve from the database while 4 is a dynamic number depending on the last position number in the database+1 (3+1 = 4)
If I get the point, fetching from Subject as #position = Subject.pluck(:position) you end up, for example, with:
#position = [1,2,3]
Then you need to append one element which value is the last incremented by one.
For Ruby 2.6 you could try using Object#then:
[1,2,3].then { |ary| ary << ary.last + 1 } #=> [1, 2, 3, 4]
So, in your case this should work:
#position = Subject.pluck(:position).then { |positions| positions << positions.last + 1 }
For Ruby 2.5 use Object#yield_self.
I think the solution of iGian above is nice. But he introduced some new methods from new versions of Ruby. If you need a solution that can be used with lower versions too (and the new as well), then try this:
Proc.new { |arr| arr << arr.last + 1 }.call(Subject.pluck(:position))
# or
lambda { |arr| arr << arr.last + 1 }.call(Subject.pluck(:position))
Hope this helps
Update: This is the correct answer, or the right way to do what I wanted.
The codes where just complicated when in fact we can simply do like this…
In the form view:
<%= f.select :position, 1..#subject_count %>
Then in the controller:
#subject_count = Subject.count + 1
This generates the DB count + 1 without retrieving any duplicate (numbers)positions…
That's all! Quite amazing how simple it should be.

Why is my recursive function printing just once in my template?

I want to dynamically build similar components in my templates, so I created this recursive function in my page_view.ex:
defmodule MyProject.PageView do
use FabricaASA.Web, :view
defmodule Recursion do
def buildElements(element,n) when n <= 1 do
element
end
def buildElements(element, n) do
element
buildElements(element, n - 1)
end
end
end
Then, in my template I call it using:
<%= MyProject.PageView.Recursion.buildElements("LOL", 4) %>
The problem is that I'm getting just one LOL instead of 4 ...
The recursive version of buildElement has a "no operation" on the first line when you put element alone, resulting in just one item returned and the others lost. They should be collected together in an accumulator, e.g a list. Something like:
def buildElements(element,n) when n <= 1 do
[element] # EDIT: Must be a list too
end
def buildElements(element, n) do
[element | buildElements(element, n - 1)]
end
And even better (IMHO) than doing the formatting/concatenation of the list in the computation, you can iterate over it in the template.
<%= for element <- MyProject.PageView.Recursion.buildElements("LOL", 4) do %>
<%= element %>
<% end %>

How does form_for generate paths in rails?

Can anyone explain me on how the paths are generated using form_for?. The below code generates a path article_comments_path.
<%= form_for [#article, #comment] do |f| %>
<% end %>
I mean how does it exactly generate article_comments_path and not articles_comment_path
It is using polymorphic_path method to determine the path. It is basicaly a wrpaper around polymorphic_url: http://apidock.com/rails/v4.0.2/ActionDispatch/Routing/PolymorphicRoutes/polymorphic_url
Update:
polymorphic_path is using internally method called build_named_route_call. When it gets an array, it pull the last record out of the array (with pop) and then iterates over the remaining array, changing all the objects to
if it is a model it takes it class and calls `model_name.singular_route_key'
if it is a symbol or string, leaves it as it is
Then we are left with the last element. It can be singular or plural, this is resolved in polymorphic_url method with this case statement:
inflection = if options[:action] && options[:action].to_s == "new"
args.pop
:singular
elsif (record.respond_to?(:persisted?) && !record.persisted?)
args.pop
:plural
elsif record.is_a?(Class)
args.pop
:plural
else
:singular
end
where record is a first element of the array (if array is passed). inlection var is then passed to build_named_route_call so it can build correct helper name. As you can see this form will generate different paths depending on whether the first element is already persisted or not.

Array with each_by_index [duplicate]

This question already has answers here:
Start a loop from 1
(5 answers)
Closed 9 years ago.
I'm using a loop that will access the value of an array. I'm using with_index to correctly display the results, however, arrays start at 0, but my DB values start at 1. So, when the array is iterated, and it reaches, index #6 (position 7 in the array) it stops and, therefore, the value stored at the seventh field is not displayed. I could be wrong, but that's what I think is happening.
I read that it's possible to pass arguments to the each_with_index method, in case the starting value should be other than 0, but I can't find how to do it.
I'm relatively new to working with arrays, and relatively new to Ruby as a whole.
EDIT
<% #by_ticket.each_with_index do |ticketshead, id| %>
<% #tickets[id].id %>
<% end %>
The #by_ticket is a group_by statement at the controller. When i loop through it, it brings back all but the last record that meets the parameters. My question is how to start the loop at 1, instead of 0. I'll check the provided link by Hitham S. AlQadheeb.
EDIT to correct a typo in code's line 2. Thanks.
The simplest solution I think is just incrementing the index in the block like the following:
['a', 'b', 'c'].each_with_index { |item, index| puts "#{item} #{index + 1}" }

Resources