Trouble with looping through array in Ruby on Rails? - ruby-on-rails

I'm learning Ruby and Rails, and the tutorials have been saying I should set everything up in the controller first for what my ERB file is going to need. I'm having some issues doing that.
I'm getting a product catalog from an API and I'm getting back an array. Here's the start of it:
[{"Name"=>"3x4 Vinyl Magnet", "Description"=>"Made of durable high-gloss vinyl. Measures 3x4 inches and has rounded corners. Waterproof and scratch resistant.", "UnitPrice"=>8.99, "ProductCode"=>"Gift65001"
There are more multiple products.
In my controller file I have:
#http_party_json = JSON.parse(#response.body)
#http_party_json.each do |i|
i.each do |x|
#just_products = x['Products']
end
end
#just_products.each do |grab|
#product_code = grab['ProductCode']; #product_code.delete! ';'
#just_names = grab['Name']
#just_prices = grab['UnitPrice']
#just_descriptions = grab['Description']
end
My ERB file is:
<div class="large-12 columns">
<div class="row">
<% #just_products.each do %>
<div class="large-3 columns panel radius" style="height: 600px"><h2><%= #just_names %></h2><br><h3><%= #just_prices %></h3><br>
<p><%= #just_descriptions %></p>
<button id="<%= #product_code %>">Add to Cart</button>
</div>
<% end %>
</div>
It's displaying the last item in the array for each result it's bringing back. If I transfer the grab loop from the controller to the ERB file, it works fine, but I want to learn how to do it correctly.

I should set everything up in the controller first for what my erb file is going to need
I see the trouble... it's a question of interpretation of what the book is trying to say. In your code, this block,
#just_products.each do |grab|
and all the assignments within it is actually not doing anything for you. After it's done spinning through #just_products.each, the final assignment it makes to #just_descriptions is merely the last value of 'Description' in #just_products, which is what you're seeing in your view.
The book merely says to prepare everything that the erb view is going to need. This does not translate to, "assign every possible variable explicitly in the controller". It is perfectly acceptable to pass #just_products to your view and spin through it (via .each) in there.
If you prefer not to do this, your alternate option would be to build arrays of codes, names, descriptions, etc. in the controller. Then spin through each of these in your view. In this case, this line:
#just_descriptions = grab['Description']
would look more like:
#just_descriptions << grab['Description']

There reason it's showing the last one is because you are looping through the array and overwriting the ivar every time. So when you get to the last item in the array you have overwritten each preceding one.
The main thing you want to avoid doing in your view is making SQL queries. Here, you've already loaded everything into an array and that's enough.
<div class="large-12 columns">
<div class="row">
<% #just_products.each do |product| %>
<div class="large-3 columns panel radius" style="height: 600px"><h2><%= product['Name'] %></h2><br><h3><%= product['UnitPrice'] %></h3><br>
<p><%= product['Description'] %></p>
<button id="<%= product['ProductCode'].delete!(';') %>">Add to Cart</button>
</div>
<% end %>
</div>

Related

Rails: Using debugger to change execution path of Rails application

I'm running Rails v4.x and Ruby v2.3. I'd like to use a debugging tool (e.g., debugger) to dynamically test different execution paths in a Rails view. Specifically I'm trying to test the two paths of an if statement (ie., "if" block and "else" block) within a Rails view. Here is the code withing the View I'd like to test:
<% if #categories.any? %>
<% #categories.each do |category| %>
<ul class="listing">
<div class="row">
<div class="well col-md-4 col-md-offset-4">
<li class="article-title">
<%= link_to "#{category.name}", category_path(category) %>
<li><small><%= pluralize(category.articles.count, "article") %></small></li>
</li>
</div>
</div>
</ul>
<% end %>
<% else %>
<div class="center">
<p>There are no categories currently defined at this time</p>
</div>
<% end %>
To do this I'd like to be able to dynamically change the return value of the #categories.any? method so as to force the desired execution path. Is there a tool that I could use to do this? Can I do with "debugger"? Pry?. If so could you provide some simple instructions of how it could be done?
NOTE: #categories is an instant variable containing values from a data model (Category). I'd prefer not delete the contents of the Category table just to test the else part of the aforementioned code.
Regards,
Jet
Well, as you will have to edit the file anyway, to add a debugger line, you can just as well add another variable, can't you?
<% if (#categories.any? && !#never_run) || #always_run %>

Rails partial for collection, only display certain things for first element

I have a collection of elements I'm rendering in a partial, but I only want to display a certain element with the very first element. My specific instance is displaying email addresses but I only want the email icon to show once next to the first instance (similar to how the Android Contacts app does).
I have a very "hacky" solution that uses instance variables in the view, which is not a good practice. But I'm struggling to find a cleaner way to implement what I want.
The controller:
#email_addresses = EmailAddress.order(:primary) # primary is a boolean value
The partial:
# views/email_addresses/_email_address.html.erb
<div class="email-address">
<% unless #email_icon_displayed
<% #email_icon_displayed = true %>
<div class="email-address-icon">
<span class="icon email"></span>
</div>
<% end %>
<div class="email-address-value">
<%= email_address.value %>
</div>
</div>
Calling partial in view:
<%= render partial: "email_addresses/email_address", collection: #email_addresses %>
This works properly and only displays the email icon for the first element, but instance variables in the view seems like a bad idea.
This may be a little late, but I had the same goal and I achieved it by using a "hidden" counter variable in Rails partial collections.
I called my partial collection like this:
<%= render partial: "questions/possible_answer",
collection: question.possible_answers, as: 'value' %>
And inside my partial I can access the variable value_counter, which increments for each partial. So to run something with the first element only, I did it like this:
if value_counter == 0
#do something
end
I think your case you would need to access it like this: email_address_counter
Found this solution here: https://coderwall.com/p/t0no0g/render-partial-with-collection-has-hidden-index

Application.html.erb template inheritance

I have a situation in rails (version 4.04, ruby version 2.1) where I've been using the standard application.html.erb to define the main framework for my site, header, footer, nav bar, etc. When I got to an inner div, call it, inner-content, thats where I put a <% yield %> statement so that the sub template can take over and place its content in the correct place (for example products#show or products#index have show.html.erb and index.html.erb respectively which just the content for those actions).
The problem is I realized I was duplicated some code in those sub templates. In ever one of them (except one) I always was starting off like this:
<div class="columns large-6 medium-6 center-small">
<div class="inner_wrapper">
And I was always ending like this:
</div>
</div>
So I was thinking, I shouldn't be repeating all this code. I should move this into application.html.erb so that every template automatically gets the inner-content set up correctly.
The problem is that one action I was talking about. There is one action that has a different setup. I don't want to have to type in those extra 2 divs for every sub-layout except one. Is there a better way to do this?
One way could be to check which controller your currently using this in your application.html.erb
<% if params[:controller] == "controller name" %>
<div>
<%= yield %>
</div>
<% else %>
<div class="different div">
<%= yield %>
</div>
<% end %>
Not sure if this the best way, but its one way to do it.
Create a different layout file and call it maybe products_layout.html.erb.
Then in the controller
class ProductsController < ApplicationController
layout: 'products_layout'
....
end
Or do it on a per action
def show
render 'show', layout: 'products_layout'
end
http://guides.rubyonrails.org/layouts_and_rendering.html

how to use database field as attribute value in rails template

I basically want to do this:
<% #videos.each do |vid| %>
<div id=vid.location>
...
<% end %>
how do I evaluate vid.locaion and use it as the id attribute?
i've tried the above, id="#{vid.location}" and id="<% vid.location %>" (the last one with and without quotes.
any help appreciated
Easy,
<div id="<%= vid.location %>">
Your first attempt was wrong as you're still in markup - not ruby. In the last one you used <% rather than <%=, so while it was evaluating the getter, it just didn't present it to your view.

Getting proper indentation using XMLBuilder in a helper

I'm attempting to use a view helper to create some dynamic links based on if you're logged in or not.
What I want returned, for sake of easy code readability, is:
<ul class="right">
<li>Login</li>
<li>Register</li>
</ul>
In the view helper I have this Ruby code:
def loginh
xm = Builder::XmlMarkup.new(:indent=>2, :margin=>4)
xm.ul("class" => "right") {
xm.li('class' => 'text') {
xm.text("test")
}
}
end
In the view, the line that calls login helper is already indented 4 levels. Because of this, the first line gets 'skewed', so in the view I have:
<%= loginh %>
Which results in:
<ul class="right">
<li class="text">
<text>test</text>
</li>
</ul>
You can see it works perfectly, except for the first line.
It would appear that the first line is affected by the indent before <%= loginh %> is called.
I can easily remedy this by removing the indentation prior to <%= loginh %> - but in essence I'd be sacrificing code readability for markup readability. Which isn't what I'm looking to do.
Is there any way I could remove the beginning whitespace?
<%= loginh -%> is almost what you want.
The trick is the minus sign in the closing part, which suppresses extra whitespace.
Alternatively, you could pipe the output through HTMLTidy using backticks (the ` character).

Resources