accessing mongodb document field names and its values through iteration - ruby

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.)

Related

ruby middleman hash traversal

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"

Outputting data with erb and middleman

I'm wanting to output some data and I'm not sure if it is possible or not without changing my data file. Basically I have a YAML file with the following structure
items:
- category: red
name: super fun times
note: likes fun
- category: red
name: sunshine
note: wear sunglasses
- category: blue
name: crazy face
note: avoid.
What I'm doing is looping through like so
<% data.options.items.each do |q| %>
<h2><%= q.category %></h2>
<p><%= q.name %></p>
<% end %>
I'd like to be able to do is group items by category when it outputs so it would be something like the following.
<h2>red</h2>
<p>super fun times</p>
<p>sunshine</p>
<h2>blue</h2>
<p>crazy face</p>
I pretty much just want to output the category once, list out the items under that category and then when a new category comes up output that one and any relevant data, without having to repeat chunks of code.
An approach you can take is using group_to to cluster the items by their group, resulting in sets of arrays for each category:
<% data.options.items.group_by(&:category).each do |group| %>
<h2><%= group.first %></h2>
<% group.last.each do |item| %>
<p><%= item.name %></p>
<% end %>
<% end %>
In this scenario, running group_by on the collection of items provides an object with the following format:
{"red"=>[{"category"=>"red", "name"=>"super fun times", "note"=>"likes fun"},
{"category"=>"red", "name"=>"sunshine", "note"=>"wear sunglasses"}],
"blue"=>[{"category"=>"blue", "name"=>"crazy face", "note"=>"avoid."}]}
This allows you to then iterate through the object, making it easier to keep the groups separate in the markup.
Hope it helps!

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 }]

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 / Rails - Advanced grouping with group_by

I have a model called event_recurrences it contains 2 important columns event_id and cached_schedule
cached_schedule contains an array of dates
event_id is used to reference the event
I need to
Get all the event_recurrence objects #something.event_recurrences - Done
Go through each recurrence object and get the event_id and all the
dates from cached_schedule
Iterate through each month, and spit out a list like the following
Jan
event_id date
event_id date
event_id date
Feb
event_id date
... and so on
To recap the event_id is located event_recurrence.event_id the dates that the event_id will happen on are located in an array inside event_recurrence.cached_schedule
Some I have some incomplete code to work with...
This code works successfully to show each event_recurrence object by month using the created_at field.
in my controller
#schedule_months = #something.event_recurrences.order("created_at DESC").group_by { |e| e.created_at.beginning_of_month }
in my view
<% #schedule_months.keys.sort.each do |month| %>
<div class="month">
<%= month.strftime("%B %Y") %>
</div>
<% for event in #schedule_months[month] %>
<li><%= event %></li>
<% end %>
<% end %>
Thanks in advance.
Sincerely, jBeas
There are some details missing from your question... for example, can the dates in cached_schedule span multiple months, or are they all guaranteed to be in the same month?
If you just want to use core Ruby:
dates = []
#something.event_recurrences.each do |er|
er.cached_schedule.each { |date| dates << [date, er.event_id] }
end
#event_dates = dates.group_by { |(date,event_id)| date.mon }
Then in the view:
<% #event_dates.keys.sort.each do |month| %>
<div class="month"> <%= month.strftime("%B %Y") %></div>
<% #event_dates[month].each do |(date,event_id)| %>
<li><%= date %> <%= event_id %></li>
<% end %>
<% end %>
You may have to adjust the code a little depending on the specifics, but this should give you the idea. Note the use of destructuring assignment: #event_dates[month].each do |(date,event_id)|. This saves a line of code and expresses what the code is doing more clearly.
If you don't mind adding your own extensions to the core Ruby classes, you could make this code even cleaner and more consise. I often use a method which I call mappend:
module Enumerable
def mappend
result = []
each { |a| enum = yield a; enum.each { |b| result << b } if enum }
result
end
end
The name is a mix of map and append -- it is like map, but it expects the return value of the mapping block to also be Enumerable, and it "appends" all the returned Enumerables into a single Array. With this, you could write:
#event_dates = #something.event_recurrences.mappend { |er| er.cached_schedule.map { |date| [date, er.event_id] }}.group_by { |(date,event_id)| date.mon }
OK, that might be a lot for one line, but you get the idea: it saves you from using an intermediate variable to accumulate results.
UPDATE: Something like mappend is now part of the Ruby core library! It's called flat_map.

Resources