ruby middleman hash traversal - ruby

New to hashes. I've got a hash from middleman data file which is automatically generated by contentful_middleman. Basically
data.space.homepage = {
"PCWLCTeTCKsaoGGSQOc6i"=>{
"id"=>"PCWLCTeTCKsaoGGSQOc6i",
"pageTitle"=>"Page Title",
"pageContent"=>"page content",
}
}
Because PCWLCTeTCKsaoGGSQOc6i is automatically generated I have to be able to reference it without using this key.
I don't know why exactly but the underscore here gets me where I need to be:
<% data.space.homepage.each do |_, item| %>
<h1 class="tag"><%= item.pageTitle %></h1>
<% end %>
I'd like to be able to access pageTitle and pageContent without looping over the data but I can't figure out if that's possible without explicitly using the key PCWLCTeTCKsaoGGSQOc6i

If homepage is a hash with a single pair of key/value, you can use :
title, content = data.space.homepage.values.first.values_at('pageTitle', 'pageContent')
title #=> "Page Title"
content #=> "page content"
The id is :
homepage.keys.first #=> "PCWLCTeTCKsaoGGSQOc6i"

Related

How to convert a hash into a string in ruby

I'm trying to do an wolfram api using Ruby. I found that you can create a hash from text you put to find an answer on wolfram page. I managed to do something like this in my controller:
class CountController < ApplicationController
def index
#result = Wolfram.fetch('6*7')
#hash = Wolfram::HashPresenter.new(#result).to_hash
#pods = #hash[:pods]
end
end
When I want to show this on my site I do something like this in my view:
<p>
<b>Result:</b>
<%= #result %>
<br>
<b>Hash:</b>
<%= #hash %>
<br>
<b>Hash.pods</b>
<%= #pods["Input"]%>
<br>
</p>
And I have something like this on my page:
Result: #<Wolfram::Result:0x00000004758b78>
Hash: {:pods=>{"Input"=>["6×7"], "Result"=>["42"], "Number name"=>["forty-two"], "Number line"=>[""], "Illustration"=>["6 | \n | 7"]}, :assumptions=>{}}
Hash.pods ["6×7"]
I'd like to have just 6x7 instead of ["6x7"]. Is there a solution to change this hash into a string?
The reason why it is being displayed like [6x7] is that your hash stores it within an array. Displaying it any other way will be misleading. However you can do it with:
Hash[#hash.map {|key, value| [key, (value.kind_of?(Array) && value.size == 1) ? value.first : value }]

accessing mongodb document field names and its values through iteration

Let's say I have a mongodb document in the products collection:
{
"_id" : ObjectId("51b1eac0311b6dd93a000001"),
"name" : "Apple",
"price" : "34.45"
}
products_controller.rb for def show part:
def show
#product = Product.find(params[:id])
end
I imagine the code would seem like below in the show.html.erb:
<% #product.each do |f|%>
<p>f.label</p> # this is only an image code
<p>f.value</p> # this is only an image code
<% end %>
How the code at the lines 2 and 3 on Rails 3 should look like in a generic way so it would show like? :
name: Apple
price: 34.45
Number of fields can be 20, so I don't want to write the same code for 20 fields.
I'm using Rails 3 with Mongoid. I think it's not a mongodb-specific question.
Try this:
foreach (var item in YourcollectionName)
{
var name = item.name;
var price = item.price;
}
Mongoid models have an attributes method that returns a hash of the attributes. If you iterate over that hash you'll be yielded the name and value of each entry.
For example
<% #product.attributes.each do |name, value| %>
<p>
<%= name%> : <%= value %>
</p>
<% end %>
You'd need some more sophisticated formatting code for pretty output for all the kinds of values you might get (dates, arrays, hashes etc.)

Parsing XML and how to handle nested Arrays and Hashes

I'm using this instance variable:
#response = HTTParty.get("http://www.bart.gov/dev/eta/bart_eta.xml")
I'm trying to parse the xml using rails 3.2:
<% #response.each do |r| %>
<% r.each do |root| %>
<%= root.class %>
<% end %>
<% end %>
The output is
String Hash
I get "String Hash" for "root.class". I don't understand how it can be "String Hash," I would like to implement another "each" method to go deeper in the xml layers.
What does "String Hash" mean?
Your #response object is of the type HTTParty::Response.
It looks like it's wrapping an array with two values in it: the first value is a String, "root", and the second value is a Hash.
Since you have no line breaks in your ERB code, as you iterate through the array it is printing out String and Hash on the same line.
Try using root.inspect to dig deeper into what values you're actually iterating through.

How to generate pages for each tag in nanoc

I am new to nanoc and I am still finding my around it. I am able to get my site ready, it looks good and functions good, too. But I need to have a tags area. I am able to achieve that with
<%= tags_for(post, params = {:base_url => "http://example.com/tag/"}) %>
But how do I generate pages for tag? So for instance there is a tag called "NFL", so every time a user clicks on it, he/she should be directed to http://example.com/tag/nfl with a list of articles that correspond with NFL.
I can setup a layout which will do that. But then what kind of logic should be I using? And also do I need to have a helper for this?
You can use a preprocess block in your Rules file in order to generate new items dynamically. Here’s an example of a preprocess block where a single new item is added:
preprocess do
items << Nanoc::Item.new(
"some content here",
{ :attributes => 'here', :awesomeness => 5000 },
"/identifier/of/this/item")
end
If you want pages for each tag, you need to collect all tags first. I’m doing this with a set because I do not want duplicates:
require 'set'
tags = Set.new
items.each do |item|
item[:tags].each { |t| tags.add(t.downcase) }
end
Lastly, loop over all tags and generate items for them:
tags.each do |tag|
items << Nanoc::Item.new(
"",
{ :tag => tag },
"/tags/#{tag}/")
end
Now, you can create a specific compilation rule for /tags/*/, so that it is rendered using a "tags" layout, which will take the value of the :tag attribute, find all items with this tag and show them in a list. That layout will look somewhat like this:
<h1><%= #item[:tag] %></h1>
<ul>
<% items_with_tag(#item[:tag]).each do |i| %>
<li><%= link_to i[:title], i %></li>
<% end %>
</ul>
And that, in broad strokes, should be what you want!

Ruby, better way to implement conditional iteration than this?

I have an array #cities = ["Vienna", "Barcelona", "Paris"];
and I am trying to display the individual items with a spacer in between. However it is possible that there is only 1 element in the array, in which case I do not want to display the spacer. And also the array could be empty, in which case I want to display nothing.
For the above array I want the following output:
Vienna
-----
Barcelona
-----
Paris
I use an erb template cityview to apply formatting, css, etc before actually printing the city names. Simplified, it looks like this:
<p><%= #cities[#city_id] %></p>
I have implemented it as follows...
unless #array.empty?
#city_id = 0;
erb :cityview
end
unless #array[1..-1].nil?
#array[1..-1].each_index do |i|
#city_id = i+1;
puts "<p>-------</p>";
erb :cityview
end
end
Is there a better way?
#cities.join("<p>--------</p>")
Edit to address the template
Here I'm assuming that there's an erbs method that returns the rendered template without doing a puts. Returning the string allows easier manipulation and reuse.
#cities.map { |c| #city = c; erb :cityview }.join("<p>--------</p>")
I'd prefer:
erb:
<p><%= #city %></p>
and loop
#array.each_with_index do |e, i|
#city = e
erb :cityview
puts "<p>-------</p>" if i < #array.length - 1
end
I assume you have split the erb, bit because you want to customize it.
If you want to mix HTML with your city names then you'll need to worry about HTML encoding things before you mix in your HTML. Using just the standard library:
require 'cgi'
html = #cities.map { |c| CGI.escapeHTML(c) }.join('<p>-----</p>')
If you're in Rails, then you can use html_escape from ERB::Util and mark the result as safe-for-HTML with html_safe to avoid having to worry about the encoding in your view:
include ERB::Util
html = #cities.map { |c| html_escape(c) }.join('<p>-----</p>').html_safe
The simpler solution would be to use a spacer template.
http://guides.rubyonrails.org/layouts_and_rendering.html#spacer-templates

Resources