AlchemyCMS: Get all elements from a subtree - alchemy-cms

There is probably an easy way to do this, but I couldn't find anything about it in the guides:
I have a page called "Logic" and this page has 20 subpages.
Now, in the page "Logic", I'd like to render the title of all those 20 subpages. How can I do that?
Example:
#all-pages-under-logic.each do |page|
= page.title
end
First, I thought that the method render_subnavigation might be useful. But it seems that it only returns elements, that are visible in the navigation.

Answered by tvdeyen from the alchemy cms slack channel:
#children = Alchemy::Page.find_by(page_layout: 'logic').children
titles = #children.pluck(:title)

Related

How to iterate with more than one element on the page

I have several buttons to click on the same page. How do I iterate and click on each of them?
def btnConectar()
elements = all("button[data-control-name='srp_profile_actions']").count
puts elements
first("button[data-control-name='srp_profile_actions']").click
find("section[class=modal]")
find("button[class='button-primary-large ml1']").click
end
all returns an Array like Capybara::Result object. You can iterate through that using the standard ruby enumerable methods.
all("button[data-control-name='srp_profile_actions']").each do |el|
el.click
find("section[class=modal]") # Not sure what this is for - if it's an expectation/assertion it should be written as such
click_button(class: %w(button-primary-large ml1)
end
That will work as long as clicking on the button doesn't cause the browser to move to another page.
If clicking does cause the browser to move to another page then all the rest of the elements in the Capybara::Result object will become stale (resulting in a stale element reference error on the next iteration) and you won't be able to iterate any more. If that is your case then details on what exactly you're doing will be necessary. Questions like does the original button still exist on the page after clicking the button-primary-large button, or can you iterate by just clicking the first matching button over and over? If it does still exist is it changed in any way to indicate it's already been clicked, or is the number/order of buttons on the page guaranteed to be stable? It would probably help to understand if you posted a fragment of the HTML for the first and second iteration.
def btnConectar()
page.all("button[data-control-name='srp_profile_actions']").each do |el|
while page.has_css?("button[data-control-name='srp_profile_actions']")
el.click #Click the button
find("section[class=modal]") #Modal mapping
click_button(class: %w(button-primary-large ml1)) #Click the button
sleep 3
end
end
end

Ruby Watir -- Trying to loop through links in cnn.com and click each one of them

I have created this method to loop through the links in a certain div in the web site. My porpose of the method Is to collect the links insert them in an array then click each one of them.
require 'watir-webdriver'
require 'watir-webdriver/wait'
site = Watir::Browser.new :chrome
url = "http://www.cnn.com/"
site.goto url
box = Array.new
container = site.div(class: "column zn__column--idx-1")
wanted_links = container.links
box << wanted_links
wanted_links.each do |link|
link.click
site.goto url
site.div(id: "nav__plain-header").wait_until_present
end
site.close
So far it seems like I am only able to click on the first link then I get an error message stating this:
unable to locate element, using {:element=>#<Selenium::WebDriver::Element:0x634e0a5400fdfade id="0.06177683611003881-3">} (Watir::Exception::UnknownObjectException)
I am very new to ruby. I appreciate any help. Thank you.
The problem is that once you navigate to another page, all of the element references (ie those in wanted_links) become stale. Even if you return to the same page, Watir/Selenium does not know it is the same page and does not know where the stored elements are.
If you are going to navigate away, you need to collect all of the data you need first. In this case, you just need the href values.
# Collect the href of each link
wanted_links = container.links.map(&:href)
# You have each page URL, so you can navigate directly without returning to the homepage
wanted_links.each do |link|
site.goto url
end
In the event that the links do not directly navigate to a page (eg they execute JavaScript when clicked), you will need to collect enough data to re-locate the elements later. What you use as the locator will depend on what is known to be static/unique. As an example, I will assume that the link text is a good locator.
# Collect the text of each link
wanted_links = container.links.map(&:text)
# Iterate through the links
wanted_links.each do |link_text|
container = site.div(class: "column zn__column--idx-1")
container.link(text: link_text).click
site.back
end

Clicking only on links within a specific menu?

I am trying to scrape a page, and need to click on some links within a menu. If I use the search method, I am then stuck with a Nokogiri object, and therefore can not use the click method.
agent.page.search('.right-menu').links_with(href: /^\/blabla\//).each do |link|
region = link.click
end
The following would tell me that links_with is not defined. How can I make a select links from a specific menu? Is there a way I can parse the object back to a Mechanize object?
You can try something like this:
agent.page.search('.youarehere > a').each do |a|
link = Mechanize::Page::Link.new(a.attr('href'), agent, agent.page)
region = link.click
end
not the cleanest way to do it I guess, but Mechanize is doing almost the same in its source code: http://mechanize.rubyforge.org/Mechanize/Page.html#method-i-links
Would be a nice addition though, instead of going through this.

Selenium 2.0 Webdriver & Ruby, link element methods other than .text? Navigate.to links in array?

I'm a bit further along in converting some sample test/specs from Watir to Selenium. After my last question here and suggested response, I began using Selenium 2.0 with WebDriver instead of Selenium 1.
The example in question deals with gathering all links within a table into an array -- that part is complete. However, once the links are in the array, the only meaningful way that I can interact with them appears to be .text. Using #driver.navigate.to Array[1] gives a URL format error in the browser, and link.href or .src are not valid options.
The Watir implementation gathered these links (pages added by users via CMS), stored them in an array and then visited each page one by one, submitting a lead form. I believe I could get this to work using Selenium and revisiting the "home" page that contains all of the links between lead form submissions, but that could mean hundreds of extra page loads, cached or not.
The code so far:
' #countries = Array.new
#browser.navigate.to "http://www.testingdomain{$env}.com/global"
#browser.find_elements(:xpath, "//table[#class='global-list']//a").each do |link|
#countries << [link.text, link.href] ## The original WATIR line that needs an update
end #links
#countries.uniq! #DEBUG for false CMS content'
The closest item I could find in the selenium-webdriver documentation was the (string).attribute method, but again, am unsure of what attributes
I was not sure of the format for use with the attribute method, but after some experimenting I was able to move past this step.
#countries = Array.new
#browser.navigate.to "http://www.testingdomain{$env}.com/global"
#browser.find_elements(:xpath, "//table[#class='global-list']//a").each do |link|
text = link.attribute("text")
href = link.attribute("href")
#countries << [text, href]
end #links
`#countries.uniq! #DEBUG for false CMS content
Looks like you found your answer to your question on your own.
Indeed, element.attribute allows you to pull any HTML attribute a tag could possibly have. Thus, since you were wanting to pull the URL of the element, you used element.attribute('href') to return the element's href="" attribute. The same can be done for any other attributes, including class, id, style, etc.

parse 'page 1 of x' - the best method (ruby/mechanize/nokogiri)

what is the best method using ruby/mechanize/nokogiri to go/click through all pages in case there is more than 1 page I need to access/click on? For example here Page 1 of 34 Should I click the page number or next? Or is out there any better solution?
It looks like the link ">" takes you to the next page, and it does not appear if you are on the last page. So:
page = ... # fetch the first page
loop do
# process the page
break unless link = page.link_with(:text=>'>')
page = link.click
end
You should try out scrubyt. It's described as "mechanize on steroids". It has dedicated method for clicking through pages.

Resources