Middleman variables visibility in config.rb and pages - ruby

I'm missing something about visibility of variables.
In my config.rb i'm using a data structure to generate dynamic pages:
#pages = [
{
id: "cookies",
title: "Happy Chocolate Chip Cookies",
quote: "These cute cookies are full of sweet chocolate and ready to give you energy!",
content: "Orecchini a monachella. Realizzati in fimo, dipinti a mano e rivestiti con vernice lucida."
},
....]
#pages.each do |p|
page "/creations/#{p[:id]}.html", :proxy => "item-template.html", :ignore => true do
#tile = p
end
end
The pages generation goes well, no problem with that. But..
How can i access this data structure also in order to provide dynamic links to the generated pages? I would like to be able to create an index page (let's call it creations.html) with the following code:
<ul>
<% #pages.each do |tile| %>
<li><a href="creations/<%= tile[:id]%>.html">
<%= tile[:title] %>
</a></li>
<% end %>
</ul>

No need to create a custom helper, you can use a yaml data file to populate your template and generate the list of links. Let me explain.
On the same level as source and build directories make sure you create a data directory.
ie:
build
source
data
Inside this create a file called "pages.yml" (for example).
This file needs to be specifically formatted so be careful (or use a yaml parser to make sure you don't have any errors - like a missing comma or escaped quote).
Using the data in your config.rb file, an example would be something like:
- id: "cookies"
title: "Happy Chocolate Chip Cookies"
quote: "These cute cookies are full of sweet chocolate and ready to give you energy!"
content: "Orecchini a monachella. Realizzati in fimo, dipinti a mano e rivestiti con vernice lucida."
- id: "bacon"
title: "Smoked bacon bits"
quote: "everything tastes better with bacon!"
content: "blah"
etc...
Now, in your config.rb file replace #pages.each do |p| with data.pages.each do |p|
data.pages.each loops through each item in the newly created yaml file
You can then simply reference the same file in your index file (creations.html) like so:
<ul>
<% data.pages.each do |tile| %>
<li><a href="creations/<%= tile[:id]%>.html">
<%= tile[:title] %>
</a></li>
<% end %>
</ul>
I had a similar problem around dynamic pages which you can refer to here
Hope this helps. Good luck!

Perhaps add a helper that returns the #pages data structure in your file creations.erb. I.e. in your config.rb file add:
helpers do
def dynamic_pages()
#pages
end
end
and then in your creations.erb have:
<ul>
<% dynamic_pages.each do |tile| %>
<li><a href="creations/<%= tile[:id]%>.html">
<%= tile[:title] %>
</a></li>
<% end %>
</ul>
And, if you want to reference dynamic pages in your dynamic pages(!), a helper could generate that html and you could call the ... nah, never mind!

Related

Linking to search results with Ruby

I'm a complete novice in Ruby and Nanoc, but a project has been put in my lap. Basically, the code for the page brings back individual URLs for each item linking them to the manual. I'm trying to create a URL that will list all of the manuals in one search. Any help is appreciated.
Here's the code:
<div>
<%
manuals = #items.find_all('/manuals/autos/*')
.select {|item| item[:tag] == 'suv' }
.sort_by {|item| item[:search] }
manuals.each_slice((manuals.size / 4.0).ceil).each do |manuals_column|
%>
<div>
<% manual_column.each do |manual| %>
<div>
<a href="<%= app_url "/SearchManual/\"#{manual[:search]}\"" %>">
<%= manual[:search] %>
</a>
</div>
<% end %>
</div>
<% end %>
</div>
As you didn't specify what items is returning, I did an general example:
require 'uri'
# let suppose that your items query has the follow output
manuals = ["Chevy", "GMC", "BMW"]
# build the url base
url = "www.mycars.com/search/?list_of_cars="
# build the parameter that will be passed by the url
manuals.each do |car|
url += car + ","
end
# remove the last added comma
url.slice!(-1)
your_new_url = URI::encode(url)
# www.mycars.com/?list_of_cars=Chevy,GMC,BMW
# In your controller, you will be able to get the parameter with
# URI::decode(params[:list_of_cars]) and it will be a string:
# "Chevy,GMC,BMW".split(',') method to get each value.
Some considerations:
I don't know if you are gonna use this on view or controller, if will be in view, than wrap the code with the <% %> syntax.
About the URL format, you can find more choices of how to build it in:
Passing array through URLs
When writing question on SO, please, put more work on that. You will help us find a quick answer to your question, and you, for wait less for an answer.
If you need something more specific, just ask and I can see if I can answer.

Capybara::Ambiguous match, found 2 elements matching xpath - Find 1st link

I'm having an index action where I list all blog posts
<% #posts.each do |post| %>
<div class="blog-post">
<h2 class="blog-post-title"><%= link_to post.title, post_path(post) %></h2>
<p><%= post.sort_description %></p>
<p class="blog-post-meta">
<%= link_to 'Read more', post_path(post) %>
</p>
</div>
<% end %>
In my test script, in order to access the show action and view a single post I have this
find(:xpath, "//a[#href='/posts/1']").click
# or click_link(href: post_path(post))
But when I try to run the test I get this error
Failure/Error: find(:xpath, "//a[#href='/posts/1']").click
Capybara::Ambiguous:
Ambiguous match, found 2 elements matching xpath "//a[#href='/posts/1']"
as capybara finds two different links which go to same page (one on title and the "read more" link). Is there a way to tell capybara to use the first link that finds?
Since one of the links is in the title h2 you can use that to scope the find and remove the ambiguity
find(".blog-post-title > a[href=`#{post_path(post)}`]").click # always better to use post_path than hardcode the id
You could also do first(:link, href: post_path(post)).click but first (like all) has the disadvantage of not having waiting/retrying behavior so unless you're sure the page is fully loaded when called it's best to avoid it (or enable waiting/retrying on it by specifying one of the count options first(:link, href: post_path(post), minimum: 1).click).
If you need to click blog title links a lot you could also create a custom selector with something like
Capybara.add_selector(:title_link) do
css do |post|
".blog-post-title > a[href=`#{post_path(post)}`]"
end
end
which would then allow you to do
find(:title_link, post).click
You don't have to use xpath.
In your example, you should be able to use:
first('.blog-post-title > a').click

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 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!

Rails 3.1.4 - Render :text

I'm updating my rails 2 apps to rails 3 and find that the use of 'render :text' does not behave the same anymore.
#results is an array. In my controller:
render :text => "<ul>#{#results}</ul>"
It's returning the whole array as a string rather than iterating through each value:
<ul>
["
<li>Steve</li>
", "
<li>John</li>
"]
</ul>
Worked fine in Rails 2.x but not in 3. How do I fix this?
I'm expecting a result of:
<ul>
<li>Steve</li>
<li>John</li>
</ul>
I know this question is for Rails 3.1.4 only.
But those who come here and are on a more recent version, starting with Rails 5.1 we'll do this:
render plain: "I'm like everyone else."
The string contains HTML tags so you will need to mark it as safe so that Rails doesn't escape the tags.
render :text => "<ul>#{#results}</ul>".html_safe
NOTE: Unless there is a valid reason to have HTML in your controller, I recommend moving the list items to a view.
6/23/2014 UPDATE: In retrospect, I don't like having this string parsing logic in the controller. The #results suggests there is HTML embedded in an object somewhere. I recommend using a presentation object and call a method like #results.list. The Draper gem is well-suited for this.
Cite
https://github.com/drapergem/draper
I would suggest doing the following instead of render :text
render :partial => "result", :collection => #results
and add the file: _result.html.erb with
<ul>
<%= result %>
</ul>
or even better if you can remove the li tags from #results
<ul>
<li><%= result %></li>
</ul>
The Rails 3 docs say render text should be used for NON HTML text, which does not fit your use case. Using render :partial :collection is a better and more rails 3 way to iterate through your list.

Resources