Looping through passed parameters in Capybara - capybara

I would like to create a Capybara method for reading the contents of a table, that takes a variable number of parameters and iterates through the parameters.
Here is the method I have:
Then /^I should see a table record with "(.*?)", "(.*?)", "(.*?)"$/ do |invisible, name, address, phone|
rows = page.all(".table-bordered tr")
expect(rows.any? { |record| record.has_content? name }).to be_true
rows.each do |record|
if record.has_content? name
expect(record.has_content? address).to be_true
expect(record.has_content? phone).to be_true
end
end
end
I'm using the same CSS table structure to create tables with much larger numbers of columns elsewhere in the program. So whether the table has 3 columns or 12, I'd like to be able to use the same method so I don't write awkward code.
How can I assign a variable number of parameters and loop through each parameter in Capybara?

def assert_my_table(name, *row_data)
# It will be much faster than looping through all rows
row = page.find(:xpath, "//*[#class='table-bordered']//tr[./td='#{name}']")
# retrive row contents only once (again, it will be faster than retrieving it again for each of the columns you want to assert)
row_text = row.text
row_data.each do |text|
expect(row_text).to include(text)
end
end
assert_my_table(name, address, phone)

Related

Block is not entered on a ActiveRecord_Relation

I am new to Ruby and RoR.
I have a class method that looks like this:
def self.show_all_expired
puts "\r\n COUNT: #{self.expired.all.count}\r\n"
self.expired.all do |s|
puts "\r\n COUNT: #{s}\r\n"
end
puts "\r\nEND\r\n"
end
When I run it from the console I get this output:
As you can see the subscriptions collection is not iterated and the block body is not entered at all. But the count of the query is 31, so there must be records. Why do block is not executed?
Looking at the docs you can see that all doesn't expect a block. It just returns the ActiveRecord::Relation scope object.
Instead, you want to use each which calls the given block once for each element in row collection:
self.expired.each do |s|
puts "\r\n Subscription: #{s.inspect}\r\n"
end
Or find_each if you are dealing with a larger number of records.

Passing Parameters to Active Admin Table_for columns

I'm trying to set up a table_for in my active admin project which displays information based on methods I pass to it. I'm setting it up so that in the model, there is an array of arrays. The arrays within the array contain first the label, then the method meant to be run in the column. I'm trying to set it up this way:
panel "Acquired Shares" do
table_for shareholder.acquired_shares_transactions do
shareholder.acquired_shares_info.each do |section|
column (section[0]) { |transaction| section[1] }
end
end
end
Here is the code of the method which returns the array of arrays:
def acquired_shares_info
data = [[:label, transaction.event.to_s], [:amount_of_shares, transaction.amount_of_shares],
[:share_price, transaction.event.share_price],
[:total_price, (transaction.amount_of_shares * transaction.event.share_price)],
[:occurred_on, transaction.event.occurred_on],
[:from_shareholder, transaction.event.from_shareholder],
[:share_transaction_action, transaction.event.share_transaction_action.name],
[:share_transaction_type, transaction.event.share_transaction_type.name]]
return data
end
This is all is meant to create a column for each label and method I specify in the array. However, I am stuck on how to pass the labels and methods from the array into the column for the table. The way that I try here keeps throwing the error "No block given" on the array. Anyone have ideas on how to set this up?
Thank you!
Defer evaluation of the method by wrapping it in a proc. Pass the proc as the last parameter instead of specifying a block, Ruby will substitute it for you.
data = [[:label, proc { |transaction| transaction.event.to_s }], ...
...
column section[0], section[1]
...

Nested each do loops printing unexpectedly in Ruby

I have two arrays containing strings. I'm trying to iterate through both arrays with nested .each do loops to see if any elements in the first array have a substring of any of the elements in the second array. I'm using .include? within the nested loops to check this. I want the result to be the string printed the number of times it matches an element in partials.
This is the method that isn't working
def orphanCheck(partials, partials1, duplicatesArray)
partials1.each do |i|
partials.each do |j|
if i.include?(j)
duplicatesArray.push(i)
end
end
end
end
I'm using this as a helper method to define partials and partials1
def manipulate(monthEmails, todayEmails, partials, partials1)
monthEmails.each do |i|
email = EmailAddress.new(i.to_s)
partials.push(email.host_name.to_s)
end
todayEmails.each do |j|
todaySignup = j.to_s.slice(11, 100)
partials1.push(todaySignup)
end
end
And then I'm calling the two with the following
manipulate(allUnique, todayEmails, partials, partials1)
orphanCheck(partials, partials1, duplicatesArray)
#puts duplicatesArray
duplicatesArray is printing some strings that shouldn't be matches and it's printing some strings more times than I want. For example, gmail.com isn't in partials at all but me#gmail.com, which is in partials1 once, is being pushed to duplicatesArray three times. If yahoo.com is in partials three times, then I would want me#yahoo.com (from partials1) to be pushed to duplicatesArray three times, for example.
To be sure you could be doing:
partials1.each do |i|
i_ups=i.split('#')[-1]
partials.each do |j|
if i_ups===j
duplicatesArray.push(i)
break
end
end
end
If I understood correctly (partials is only the host part of the email provider and partials1 is the full email address)
A better solution that should give you a correct duplicatesArray would be:
partials1.each do |email_address|
email_host = email_address.split("#").last
duplicatesArray.push(email_address) if partials.include?(email_host)
end

What is the most elegant Ruby expression for comparing and selecting values from a 2D Array?

I have some code that is chugging through a set of Rails Active Record models, and setting an attribute based on a related value from a 2D Array.
I am essentially setting a US State abbreviation code in a table of US States which was previously only storing the full names. A library of state names is being used to derive the abbreviations, and it contains a 2D Array with each sub-array having a full name, and an abbreviation (i.e., [['New York', 'NY']['Pennsylvania', 'PA'][etc]]). I compare the state name from each record in the database to each full text name in this Array, then grab the corresponding sibling Array cell when there is a match.
This code works fine, and produces the correct results, but its frumpy looking and not easily understood without reading many lines:
# For the following code, StatesWithNames is an Active Record model, which is
# having a new column :code added to its table.
# Sates::USA represents a 2D Array as: [['StateName', 'NY']], and is used to
# populate the codes for StatesWithNames.
# A comparison is made between StatesWithNames.name and the text name found in
# States::USA, and if there is a match, the abbreviation from States::USA is
# used
if StatesWithNames.any?
StatesWithNames.all.each do |named_state|
if named_state.code.blank?
States::USA.each do |s|
if s[0] == named_state.name
named_state.update_column(:code, s[1])
break
end
end
end
end
end
What is the most Ruby style way of expressing assignments with logic like this? I experimented with a few different procs / blocks, but arrived at even cludgier expressions, or incorrect results. Is there a more simple way to express this in fewer lines and/or if-end conditionals?
Yea, there is a few ifs and checks, that are not needed.
Since it is Rails even though it does not state so in question's tags, you might want to use find_each, which is one of the most efficient way to iterate over a AR collection:
StatesWithNames.find_each do |named_state|
next unless named_state.code.blank?
States::USA.each do |s|
named_state.update_column(:code, s[1]) if s[0] == named_state.name
end
end
Also be aware, that update_column bypasses any validations, and if you wish to keep your objects valid, stick to update!.
And last thing - wrap it all in transaction, so if anything goes wrong all the way - it would rollback any changes.
StatesWithNames.transaction do
StatesWithNames.find_each do |named_state|
next unless named_state.code.blank?
States::USA.each do |s|
named_state.update!(:code, s[1]) if s[0] == named_state.name
end
end
end
You might use a different data structure for this.
With your existing 2D array, you can call to_h on it to get a Hash where
a = [['California', 'CA'], ['Oregon', 'OR']].to_h
=> { 'California' => 'CA', 'Oregon' => 'OR' }
Then in your code you can do
state_hash = States::USA.to_h
if StatesWithNames.any?
StatesWithNames.all.each do |named_state|
if named_state.code.blank?
abbreviation = state_hash[named_state.name]
if !abbreviation.nil?
named_state.update_column(:code, abbreviation)
end
end
end
end
the first thing you want to do is convert the lookup from an array of arrays to a hash.
state_hash = States::USA.to_h
if StatesWithNames.any?
StatesWithNames.all.select{|state| state.code.blank?}.each do |named_state|
named_state.update_column(:code, state_hash[named_state.name]) if state_hash[named_state.name]
end
end

How to generically get the value of a column from ActiveRecord columns array?

I'm trying to write a generic dumper / outputter of arbitrary table data, without having to individually specify each attribute. So it would be OK to specify an object (table) but the attributes should take care of themselves (some one-time formatting by datatype may be required).
class ArbitraryRecordObject < ActiveRecord::Base
# let ArbitraryRecordObject have an arbitrary list of attributes (mapping to db columns)
# of type int, float, strings, dates and timestamps
end
I'm trying to do the following, without explicitly specifying attribute (ie column) names
for all instances of ArbitraryRecordObject (ie for each row in the arbitrary_record_objects table)
for each column in each instance (ie each row)
puts column.name + row.column.value.to_s # column.name works but don't know how to get the value
end
end
Is there a way to achieve that? Thanks.
ArbitraryRecordObject.all.each do |o|
o.attributes.each do |key, value|
puts "#{key}: #{value}"
end
end
Another way...
column_names = ArbitraryRecordObject.column_names
ArbitraryRecordObject.all.each do |row|
column_names.each do |col_name|
puts "#{col_name} #{row.send(col_name)}"
end
end

Resources