get specific element from ruby block, rails app - ruby-on-rails

When performing a block like:
<% #user.favoured_user.each do |user| %>
<li><%= user.name %></li>
<% end %>
With the favoured_user method returning a limit of 5 users, how would I manipulate the block so that even when there are only 3 users available, I could still return 5 li elements?
I'm guessing a helper would come in to play, and maybe the 'first, second, third, etc.' array methods, but I can't think how to write it.
Any help?

You can try this,
<% 5.times do |i| %>
<li> <%= #user.favoured_user[i].try(:name) %> </li>
<% end %>

You can use in_groups_of
Like:
<% #user.favoured_user.in_groups_of(5).each do |favored_user| %>
<% favored_user.each do |user| %>
<li><%= user.try(:name) %></li>
<% end %>
<% end %>
The first 3 users will come through, and the last two entries will be nil

Related

Conditionals and overriding

I'm using a conditional to check if two values exists. I want to override the first conditional with the second one. Most likely if the second one exists then the first will, if that makes sense. Not the issue i'm having is using two different call methods.
What I have so far:
<% #data.each do |i| %>
<% if i.stock.present? %>
In Stock
<% elsif i.sold.present? %>
Sold
<% else %>
n/a
<% end %>
<% end %>
So, if in stock display 'In Stock', if sold display 'Sold'.
I think I have a solution, but feel free to let me know if there is a better way. This is using the unless statement and seems to display what I need.
<% #data.each do |i| %>
<% unless i.stock.present? %>
In Stock
<% else if i.sold.present? %>
Sold
<% else %>
n/a
<% end %>
<% end %>
<% end %>

Instagram gem returns full hash after iterating through it

I am using the instagram gem with rails. My problem is I am iterating over all of the data in the response with code like this:
<div>
<ul>
<%= #instagram.each do |pic| %>
<li><%= pic.name %></li>
<li><%= pic.latitude%></li>
<li><%= pic.longitude%></li>
<% end %>
</ul>
</div>
I am getting the desired results except for the end, where this gets printed in the browser:
[#<Hashie::Mash id="152201866" latitude=45.89172 longitude=-64.370013 name="Marshview Middle School">, ... etc...]
Any help trying to figure out how to ignore that last bit would be greatly appreciated.
Change
<%= #instagram.each do |pic| %>
to
<% #instagram.each do |pic| %>
= expects a return and prints the collection it iterates over.

How do I get this case statement to work?

In my view, I am doing this:
<% case #post
when #post.has_children? %>
<% #post.children.each do |child| %>
<li><%= link_to child.title, post_path(child)%></li>
<% end %>
<% when #post.has_siblings? %>
<% #post.siblings.where.not(id: #post.id).each do |sibling| %>
<li><%= link_to sibling.title, post_path(sibling)%></li>
<% end %>
<% when !#post.parent.nil? %>
<li><%= link_to #post.parent.title, post_path(#post.parent) %></li>
<% else %>
</ul>
</p>
<p>
There are no related posts.
</p>
<% end %>
Basically what I want to do is I want to check #post for a variety of conditions. If it has_children?, if it has_siblings?, etc.
I don't want the statement to exit if any of the above is true or false.
Once the view loads, it should automatically check for all of these statements. If it finds any of the above true, it should execute the command right below the check.
The issue is when I do this, it always defaults to the else. i.e. the case statement doesn't work.
I know I could simply just do a bunch of disjointed if statements, but then the HTML around it gets a bit weird.
Is there a way I can do this with a CASE statement?
Edit 1
The reason the if statement doesn't work properly, is if I have 3 if statements back to back - none of which that interact with each other (that's the only way to cycle through all of the conditions properly), is that the else doesn't trigger properly.
E.g. if the first two conditions are true, but the third is not...it will print out "there are no related posts"...when that's not the case. It is the case that there are no parent posts.
Basically I just want to have a catch-all related posts, so I am simply iterating through all of the various options and checking to see if those relations exist. If they do, I am pulling them out and if they don't then they move on. If none exist, then I don't print "there are no related posts".
The fact that the view is already looking looking complex is a sign that it may be a good idea to refactor the logic out of the view and place it into the Post model where it belongs. Ideally the view(s) should end up looking like this:
<%# posts/show.html.erb %>
<% if #post.has_related_posts? %>
<%= render partial: 'children', collection: #post.children, as: :child %>
<%= render partial: 'siblings', collection: #post.other_siblings, as: :sibling %>
<%= render partial: 'parent', locals: {parent: #post.parent}%>
<% else %>
<p>There are no related posts</p>
<% end %>
The paritals:
<%# posts/_children.html.erb %>
<li><%= link_to child.title, post_path(child)%></li>
<%# posts/_sibling.html.erb %>
<li><%= link_to sibling.title, post_path(sibling)%></li>
<%# posts/_parent.html.erb %>
<% unless parent.nil? %>
<li><%= link_to parent.title, post_path(parent) %></li>
<% end %>
Then the Post model can organize the logic:
class Post < ActiveRecord::Base
def has_related_posts?
!children.to_a.empty? || !other_siblings.to_a.empty? || !parent.nil?
end
def children
self.children || [] # Rails does this automatically, but just for the example
end
def other_siblings
self.siblings.where.not(id: self.id)
end
#...
end
I know this doesn't directly answer your question, however IMHO I think it's a better solution.
You have two options here.
Use IF ELSIF
<% if #post.has_children? %>
<% #post.children.each do |child| %>
<li><%= link_to child.title, post_path(child)%></li>
<% end %>
<% elsif #post.has_siblings? %>
<% #post.siblings.where.not(id: #post.id).each do |sibling| %>
<li><%= link_to sibling.title, post_path(sibling)%></li>
<% end %>
<% elsif !#post.parent.nil? %>
<li><%= link_to #post.parent.title, post_path(#post.parent) %></li>
<% else %>
</ul>
</p>
<p>
There are no related posts.
</p>
<% end %>
Use only case as doz mentioned
<% case
when #post.has_children? %>
<% #post.children.each do |child| %>
<li><%= link_to child.title, post_path(child)%></li>
<% end %>
<% when #post.has_siblings? %>
<% #post.siblings.where.not(id: #post.id).each do |sibling| %>
<li><%= link_to sibling.title, post_path(sibling)%></li>
<% end %>
<% when !#post.parent.nil? %>
<li><%= link_to #post.parent.title, post_path(#post.parent) %></li>
<% else %>
</ul>
</p>
<p>
There are no related posts.
</p>
<% end %>
You can do it with a case statement. Just give case no parameter. Eg instead of case #post just use case
This is the equivalent of an if statement. And should work for what your trying to achieve
Check out ruby case statements for some examples

How can I display hash data?

<% #user.dids.each_with_index{ |did, i| %>
<li><%=h #user.dids %></li>
<% } %>
result to display
#<Did:0x7fc4c55f4bf0>#<Did:0x7fc4c55f4ba0>#
<Did:0x7fc4c55f4b50>#<Did:0x7fc4c55f4b00>#
<Did:0x7fc4c55f4a88>#<Did:0x7fc4c55f4a10>#
<Did:0x7fc4c55f49c0>#<Did:0x7fc4c55f4970>
I almost sleep and did not think, tell me somebody how to display the hash data
You could just use the debug function in rails
<%= debug #user %>
First off, your loop is a bit strange. It seems to me that you should have
<% #user.dids.each_with_index{ |did, i| %>
<li><%=h did %></li>
<% } %>
In your version, you are printing the entire #user.dids with each iteration.
Also, how is the class Did defined? If you are in Rails and Did is an ActiveRecord model, you should have the .to_json method available to you (options and info here):
<% #user.dids.each_with_index{ |did, i| %>
<li><%=h did.to_json %></li>
<% } %>
OK I sleep so correctly
<% #user.dids.each_with_index{ |did, i| %>
<li><%= did.did %></li>
<% } %>
Thank you for helping colleagues

For the first x in array?

I imagine this has a rather simple answer
<% for user in #users %>
<li>
<%= link_to user.username, user %>
</li>
<% end %>
Taking my simple example above, how would I apply a class to my <li> to the first three instances returned?
Secondly, how could I just have the the second two items have a different class from the first one? as in 1..2
Either you could count manually (which is kinda ugly):
<% i = 0 %>
<% for user in #users %>
<li class=<%= (i < 3 ? "foo" : "bar") %>>
<%= link_to user.username, user %>
</li>
<% i = i.next %>
<% end %>
or use each_with_index
<% #users.each_with_index do |user, i| %>
<li class=<%= (i < 3 ? "foo" : "bar") %>>
<%= link_to user.username, user %>
</li>
<% end %>
Once you get to more complex things than i < 3 (like your 1..2 issue) you should think about a helper_method (in helpers) like class_by_position(pos) so that you can write
<li class=<%= class_by_position(i) %>>
The :first-child pseudoselector might be a better way to go, but you'll need to have a counter variable that keeps track of the iterations to do it your way.
Your question is a little vague. I can't tell if you want to stop processing the array after the first x, or not.
If you're just looking to stop after the first x items, or just looking for the 2nd and 3rd items the solution is to use a slice.
Example: just the first 3:
#user[0,3].each do |user|
... # only executed for user = #user[0],user = #user[1] and user = #user[3]
end
Example: just the second and third:
#user[1,2].each do |user|
... #only only executed for user = #user[1] and user = #user[3]
end
And here's a more specific answer to your question using these new concepts and the content_tag to programatically decide the class of the list item. If you're going to be doing this often, makes a great candidate for a function.
<% first = true %>
<% #user[0,2].each do |user| %>
<% content_tag :li,
:class => first ? "class-for-first-item" : "class-for-2nd-&-3rd" do %>
<%= link_to user.username, user %>
<% end %>
<% first = false %>
<% end %>
<!-- Now to do the rest of them:-->
<% #user[3,-1].each do |user| %>
<% content_tag :li, :class => "class-for-rest" do %>
<%= link_to user.username, user %>
<% end %>
<% end %>

Resources