Refactor if-else with a logic of exists condition check - ruby-on-rails

I have this two methods I want to refactor
def construct_discount_hash(product_adjustments)
discounts = {
events: {},
subjects: {},
products: {}
}
# product_adjustments is a model
# This is a problem from legacy database structure where event_id, subject_id, product_id is in their own column
product_adjustments.each do |adjustment|
if (adjustment.event_id.present?)
discounts[:events][adjustment.event_id] = {'$' => adjustment.amount, '%' => adjustment.percentage}
end
if (adjustment.subject_id.present?)
discounts[:subjects][adjustment.subject_id] = {'$' => adjustment.amount, '%' => adjustment.percentage}
end
if (adjustment.product_id.present?)
discounts[:products][adjustment.product_id] = {'$' => adjustment.amount, '%' => adjustment.percentage}
end
end
discounts
end
and I will use above method results within below method
# discounts is a hash generated from above code, item is a rails model
def calculate_order_content_price(discounts, item)
product = item.product
if (item.product_variant.present?)
price = item.product_variant.price
else
price = product.price
end
price_adjustments = {}
popped_from = []
if (discounts[:products][item.product_id])
price_adjustments = discounts[:products][item.product_id]
discounts[:products].delete(item.product_id)
popped_from = [:products, item.product_id]
elsif (discounts[:subjects][product.subject_id])
price_adjustments = discounts[:subjects][product.subject_id]
discounts[:subjects].delete(product.subject_id)
popped_from = [:subjects, product.subject_id]
elsif (discounts[:events][product.event_id])
price_adjustments = discounts[:events][product.event_id]
discounts[:events].delete(product.event_id)
popped_from = [:events, product.event_id]
end
if (adjustment = price_adjustments['$'])
adjusted_price = price + adjustment
elsif (adjustment = price_adjustments['%'])
adjusted_price = price + price * (adjustment / 100.0)
discounts[popped_from[0]][popped_from[1]] = price_adjustments
else
adjusted_price = price
end
{ price: adjusted_price, discount: (price - adjusted_price) }
end
I know from above code there's a lot of code-smell there. Firstly I'm thinking that the if-else logic can be refactored somehow. Can someone give an advice a technique that I can use to refactor that if-else condition? I'm confused because of the if-condition is checking for the existences of the value.
Any suggestions will be helpful.

I've tried to simplify a little bit your construct_discount_hash with two helpers:
def amount_and_percentage(adjustment, model)
{ adjustment.attributes["#{model}_id"] => { '$': adjustment.amount, '%': adjustment.percentage } }
end
def construct_discount_hash(product_adjustments)
product_adjustments.each_with_object({}) do |adjustment, hash|
case
when adjustment.event_id.present?
hash[:event] = amount_and_percentage(adjustment, 'event')
when adjustment.subject_id.present?
hash[:subject] = amount_and_percentage(adjustment, 'subject')
when adjustment.product_id.present?
hash[:product] = amount_and_percentage(adjustment, 'product')
end
end
end

A refacto for you.
def construct_discount_hash(product_adjustments)
# product_adjustments is a model
# This is a problem from legacy database structure where event_id, subject_id, product_id is in their own column
product_adjustments.each do |adjustment|
adjustement_hash = {'$' => adjustment.amount, '%' => adjustment.percentage} if adjustement
(discounts ||= {})[:events][adjustment.event_id] = adjustement_hash if adjustment.event_id.present?
(discounts ||= {})[:subjects][adjustment.subject_id] = adjustement_hash if adjustment.subject_id.present?
(discounts ||= {})[:products][adjustment.product_id] = adjustement_hash if adjustment.product_id.present?
end
discounts
end
I hope it will help you. Have fun.

Related

Ruby how to force output 0 when count has no rows

#counseling = Counseling.ransack(params[:q])
#counselings = #counseling.result.joins('RIGHT JOIN "subjects" ON "subjects"."id" = "counselings"."subject_id"')
#result = {}
#result[:data] = #counselings.group(row_condition).count
Blockquote
def self.create_case_sql_for_nested_tree2(foreign_key)
modelClass = foreign_key.sub(/_id3$/, '').camelize.constantize
#when_then_conditions = modelClass.roots.map do |o|
o.children.map do |c|
c.children.map do |g|
idlist = g.self_and_descendants.pluck(:id)
"WHEN subject_id IN(#{idlist.join(',')}) THEN #{g.id}"
end
end
end
"CASE #{#when_then_conditions.join(' ')} ELSE null END"
end
According to your comment, You want to join Counseling and Subject model and count the subject_id. I think you can do it like this,
Counseling.joins(:subject).count(:subject_id)
If you want to put any where condition you can do it like this,
Counseling.joins(:subject).where("some condition").count(:subject_id)

How to construct where clause in ruby using if

I am finding something like below. Constructing a where clause using condition. Is it possible in ruby? or I need to separate it into two where clause?
Post
.where(tag: "A") if condition A
.where(tag: "B") if condition B
.where(user_id: 1)
.order(....)
Actually, my case is like this. Is there any way to handle?
def this_function
#questions = Question.joins(:comment_threads)
.tagged_with(tag_variable, wild: true, any: true) if tag_variable.present?
.where(index_where_clause)
.where("questions.created_at < ?", query_from_date_time)
.order(created_at: :desc).limit(5)
end
def index_where_clause
where_clause = {}
where_clause[:user_detail_id] = current_user_detail.id if params[:type] == "my_question"
where_clause[:comments] = {user_detail_id: current_user_detail.id} if params[:type] == "my_answer"
where_clause[:wine_question_score_id] = params[:wine_question_score_id] if params[:wine_question_score_id].present?
where_clause
end
The methods you're using return relations so you can say things like this:
#questions = Question.joins(:comment_threads)
#questions = #questions.where("questions.created_at < ?", query_from_date_time)
#questions = #questions.tagged_with(tag_variable, wild: true, any: true) if tag_variable.present?
#questions = #questions.where(:user_detail_id => current_user_detail.id) if params[:type] == "my_question"
#questions = #questions.where(:comments => { user_detail_id: current_user_detail.id}) if params[:type] == "my_answer"
#questions = #questions.where(:wine_question_score_id => params[:wine_question_score_id]) if params[:wine_question_score_id].present?
#questions = #questions.order(created_at: :desc).limit(5)
and build the query piece by piece depending on what you have in params.
I'd probably break it down a little more:
def whatever
#questions = Question.joins(:comment_threads)
#questions = #questions.where("questions.created_at < ?", query_from_date_time)
#questions = with_tag(#questions, tag_variable)
#...
#questions = #questions.order(created_at: :desc).limit(5)
end
private
def with_tag(q, tag)
if tag.present?
q.tagged_with(tag, wild: true, any: true)
else
q
end
end
#...
and bury all the noisy bits in little methods to make things cleaner and easier to read. If you're doing this more than once then you could use scopes to hide the noise in the model class and re-use it as needed.
#tap can be helpful for modifying an object in place to apply conditional logic, in this case the object would be your .where conditions:
Post
.where(
{ user_id: 1 }
.tap do |conditions|
conditions[:tag] = 'A' if condition A
conditions[:tag] = 'B' if condition B
end
)
.order(...)
Or, perhaps it's a little cleaner if you create a helper method:
def specific_conditions
{ user_id: 1 }.tap do |conditions|
conditions[:tag] = 'A' if condition A
conditions[:tag] = 'B' if condition B
end
end
Post.where(specific_conditions).order(...)
But as a side note, if there's a case where condition A and condition B can both be true, the second conditions[:tag] = ... line will override the first. If there is not a case where both can be true, you might try to use some kind of collection to look up the proper value for tag.
CONDITION_TAGS = {
a: 'A'.freeze,
b: 'B'.freeze,
}.freeze
def specific_conditions
{ user_id: 1 }
.tap do |conditions|
conditions[:tag] = CONDITION_TAGS[condition_value] if condition_value
end
end
Post.where(specific_conditions).order(...)
#in Question class
scope :with_user_detail, -> (user_detail_id, flag=true) do
where("user_detail_id = ?", user_detail_id) if flag
end
scope :with_user_detail_comments, -> (user_detail_id, flag=true) do
joins(:comment_threads).where("comments.user_detail_id = ?", user_detail_id) if flag
end
scope :with_wine_question_score, -> (wine_question_score_id) do
where("wine_question_score_id = ?", wine_question_score_id) if wine_question_score_id.present?
end
scope :tagged_with_condition, -> (tag_variable, wild, any) do
tagged_with(tag_variable, wild, any) if tag_variable.present?
end
def this_function
my_question_flag = params[:type] == "my_question"
my_answer_flag = params[:type] == "my_answer"
Question.with_user_detail(current_user_detail.id, my_question_flag)
.tagged_with_condition(tag_variable, wild: true, any: true)
.with_user_detail_comments(current_user_detail.id, my_answer_flag)
.with_wine_question_score(params[:wine_question_score_id])
.order(created_at: :desc).limit(5)
end
You can do the following:
condition = {:tag => "A"} if condition A
condition = {:tag => "B"} if condition B
Post
.where(condition)
.where(:user_id => 1)
.order(....)
you have to use scope :
scope :my_scope, -> (variable) { where(some: vatiable) if my_condition }

Rails: Faster way to perform updates on many records

In our Rails 3.2.13 app (Ruby 2.0.0 + Postgres on Heroku), we are often retreiving a large amount of Order data from an API, and then we need to update or create each order in our database, as well as the associations. A single order creates/updates itself plus approx. 10-15 associcated objects, and we are importing up to 500 orders at a time.
The below code works, but the problem is it's not at all efficient in terms of speed. Creating/updating 500 records takes approx. 1 minute and generates 6500+ db queries!
def add_details(shop, shopify_orders)
shopify_orders.each do |shopify_order|
order = Order.where(:order_id => shopify_order.id.to_s, :shop_id => shop.id).first_or_create
order.update_details(order,shopify_order,shop) #This calls update_attributes for the Order
ShippingLine.add_details(order, shopify_order.shipping_lines)
LineItem.add_details(order, shopify_order.line_items)
Taxline.add_details(order, shopify_order.tax_lines)
Fulfillment.add_details(order, shopify_order.fulfillments)
Note.add_details(order, shopify_order.note_attributes)
Discount.add_details(order, shopify_order.discount_codes)
billing_address = shopify_order.billing_address rescue nil
if !billing_address.blank?
BillingAddress.add_details(order, billing_address)
end
shipping_address = shopify_order.shipping_address rescue nil
if !shipping_address.blank?
ShippingAddress.add_details(order, shipping_address)
end
payment_details = shopify_order.payment_details rescue nil
if !payment_details.blank?
PaymentDetail.add_details(order, payment_details)
end
end
end
def update_details(order,shopify_order,shop)
order.update_attributes(
:order_name => shopify_order.name,
:order_created_at => shopify_order.created_at,
:order_updated_at => shopify_order.updated_at,
:status => Order.get_status(shopify_order),
:payment_status => shopify_order.financial_status,
:fulfillment_status => Order.get_fulfillment_status(shopify_order),
:payment_method => shopify_order.processing_method,
:gateway => shopify_order.gateway,
:currency => shopify_order.currency,
:subtotal_price => shopify_order.subtotal_price,
:subtotal_tax => shopify_order.total_tax,
:total_discounts => shopify_order.total_discounts,
:total_line_items_price => shopify_order.total_line_items_price,
:total_price => shopify_order.total_price,
:total_tax => shopify_order.total_tax,
:total_weight => shopify_order.total_weight,
:taxes_included => shopify_order.taxes_included,
:shop_id => shop.id,
:email => shopify_order.email,
:order_note => shopify_order.note
)
end
So as you can see, we are looping through each order, finding out if it exists or not (then either loading the existing Order or creating the new Order), and then calling update_attributes to pass in the details for the Order. After that we create or update each of the associations. Each associated model looks very similar to this:
class << self
def add_details(order, tax_lines)
tax_lines.each do |shopify_tax_line|
taxline = Taxline.find_or_create_by_order_id(:order_id => order.id)
taxline.update_details(shopify_tax_line)
end
end
end
def update_details(tax_line)
self.update_attributes(:price => tax_line.price, :rate => tax_line.rate, :title => tax_line.title)
end
I've looked into the activerecord-import gem but unfortunately it seems to be more geared towards creation of records in bulk and not update as we also require.
What is the best way that this can be improved for performance?
Many many thanks in advance.
UPDATE:
I came up with this slight improvement, which essentialy removes the call to update the newly created Orders (one query less per order).
def add_details(shop, shopify_orders)
shopify_orders.each do |shopify_order|
values = {:order_id => shopify_order.id.to_s, :shop_id => shop.id,
:order_name => shopify_order.name,
:order_created_at => shopify_order.created_at,
:order_updated_at => shopify_order.updated_at,
:status => Order.get_status(shopify_order),
:payment_status => shopify_order.financial_status,
:fulfillment_status => Order.get_fulfillment_status(shopify_order),
:payment_method => shopify_order.processing_method,
:gateway => shopify_order.gateway,
:currency => shopify_order.currency,
:subtotal_price => shopify_order.subtotal_price,
:subtotal_tax => shopify_order.total_tax,
:total_discounts => shopify_order.total_discounts,
:total_line_items_price => shopify_order.total_line_items_price,
:total_price => shopify_order.total_price,
:total_tax => shopify_order.total_tax,
:total_weight => shopify_order.total_weight,
:taxes_included => shopify_order.taxes_included,
:email => shopify_order.email,
:order_note => shopify_order.note}
get_order = Order.where(:order_id => shopify_order.id.to_s, :shop_id => shop.id)
if get_order.blank?
order = Order.create(values)
else
order = get_order.first
order.update_attributes(values)
end
ShippingLine.add_details(order, shopify_order.shipping_lines)
LineItem.add_details(order, shopify_order.line_items)
Taxline.add_details(order, shopify_order.tax_lines)
Fulfillment.add_details(order, shopify_order.fulfillments)
Note.add_details(order, shopify_order.note_attributes)
Discount.add_details(order, shopify_order.discount_codes)
billing_address = shopify_order.billing_address rescue nil
if !billing_address.blank?
BillingAddress.add_details(order, billing_address)
end
shipping_address = shopify_order.shipping_address rescue nil
if !shipping_address.blank?
ShippingAddress.add_details(order, shipping_address)
end
payment_details = shopify_order.payment_details rescue nil
if !payment_details.blank?
PaymentDetail.add_details(order, payment_details)
end
end
end
and for the associated objects:
class << self
def add_details(order, tax_lines)
tax_lines.each do |shopify_tax_line|
values = {:order_id => order.id,
:price => tax_line.price,
:rate => tax_line.rate,
:title => tax_line.title}
get_taxline = Taxline.where(:order_id => order.id)
if get_taxline.blank?
taxline = Taxline.create(values)
else
taxline = get_taxline.first
taxline.update_attributes(values)
end
end
end
end
Any better suggestions?
Try wrapping your entire code into a single database transaction. Since you're on Heroku it'll be a Postgres bottom-end. With that many update statements, you can probably benefit greatly by transacting them all at once, so your code executes quicker and basically just leaves a "queue" of 6500 statements to run on Postgres side as the server is able to dequeue them. Depending on the bottom end, you might have to transact into smaller chunks - but even transacting 100 at a time (and then close and re-open the transaction) would greatly improve throughput into Pg.
http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
http://www.postgresql.org/docs/9.2/static/sql-set-transaction.html
So before line 2 you'd add something like:
def add_details(shop, shopify_orders)
Order.transaction do
shopify_orders.each do |shopify_order|
And then at the very end of your method add another end:
if !payment_details.blank?
PaymentDetail.add_details(order, payment_details)
end
end //shopify_orders.each..
end //Order.transaction..
end //method
You can monkey-patch ActiveRecord like this:
class ActiveRecord::Base
#http://stackoverflow.com/questions/15317837/bulk-insert-records-into-active-record-table?lq=1
#https://gist.github.com/jackrg/76ade1724bd816292e4e
# "UPDATE THIS SET <list_of_column_assignments> FROM <table_name> THIS JOIN (VALUES (<csv1>, <csv2>,...) VALS ( <column_names> ) ON <list_of_primary_keys_comparison>"
def self.bulk_update(record_list)
pk = self.primary_key
raise "primary_key not found" unless pk.present?
raise "record_list not an Array of Hashes" unless record_list.is_a?(Array) && record_list.all? {|rec| rec.is_a? Hash }
return nil if record_list.empty?
result = nil
#test if every hash has primary keys, so we can JOIN
record_list.each { |r| raise "Primary Keys '#{self.primary_key.to_s}' not found on record: #{r}" unless hasAllPKs?(r) }
#list of primary keys comparison
pk_comparison_array = []
if (pk).is_a?(Array)
pk.each {|thiskey| pk_comparison_array << "THIS.#{thiskey} = VALS.#{thiskey}" }
else
pk_comparison_array << "THIS.#{pk} = VALS.#{pk}"
end
pk_comparison = pk_comparison_array.join(' AND ')
#SQL
(1..record_list.count).step(1000).each do |start|
key_list, value_list = convert_record_list(record_list[start-1..start+999])
#csv values
csv_vals = value_list.map {|v| "(#{v.join(", ")})" }.join(", ")
#column names
column_names = key_list.join(", ")
#list of columns assignments
columns_assign_array = []
key_list.each {|col|
unless inPK?(col)
columns_assign_array << "THIS.#{col} = VALS.#{col}"
end }
columns_assign = columns_assign_array.join(', ')
sql = "UPDATE THIS SET #{columns_assign} FROM #{self.table_name} THIS JOIN ( VALUES #{csv_vals} ) VALS ( #{column_names} ) ON ( #{pk_comparison} )"
result = self.connection.execute(sql)
return result if result<0
end
return result
end
def self.inPK?(str)
pk = self.primary_key
test = str.to_s
if pk.is_a?(Array)
(pk.include?(test))
else
(pk==test)
end
end
#test if given hash has primary keys included as hash keys and those keys are not empty
def self.hasAllPKs?(hash)
h = hash.stringify_keys
pk = self.primary_key
if pk.is_a?(Array)
(pk.all? {|k| h.key?(k) and h[k].present? })
else
h.key?(pk) and h[pk].present?
end
end
def self.convert_record_list(record_list)
# Build the list of keys
key_list = record_list.map(&:keys).flatten.map(&:to_s).uniq.sort
value_list = record_list.map do |rec|
list = []
key_list.each {|key| list << ActiveRecord::Base.connection.quote(rec[key] || rec[key.to_sym]) }
list
end
# If table has standard timestamps and they're not in the record list then add them to the record list
time = ActiveRecord::Base.connection.quote(Time.now)
for field_name in %w(created_at updated_at)
if self.column_names.include?(field_name) && !(key_list.include?(field_name))
key_list << field_name
value_list.each {|rec| rec << time }
end
end
return [key_list, value_list]
end
end
Then, you can generate a array of hashes containing your models attributes (including theirs primary keys) and do something like:
ActiveRecord::Base.transaction do
Model.bulk_update [ {attr1: val1, attr2: val2,...}, {attr1: val1, attr2: val2,...}, ... ]
end
It will be a single SQL command without Rails callbacks and validations.
For PostgreSQL, there are several issues that the above approach does not address:
You must specify an actual table, not just an alias, in the update target table.
You cannot repeat the target table in the FROM phrase. Since you are joining the target table to a VALUES table (hence there is only one table in the FROM phrase, you won't be able to use JOIN, you must instead use "WHERE ".
You don't get the same "free" casts in a VALUES table that you do in a simple "UPDATE" command, so you must cast date/timestamp values as such (#val_cast does this).
class ActiveRecord::Base
def self.update!(record_list)
raise ArgumentError "record_list not an Array of Hashes" unless record_list.is_a?(Array) && record_list.all? {|rec| rec.is_a? Hash }
return record_list if record_list.empty?
(1..record_list.count).step(1000).each do |start|
field_list, value_list = convert_record_list(record_list[start-1..start+999])
key_field = self.primary_key
non_key_fields = field_list - [%Q["#{self.primary_key}"], %Q["created_at"]]
columns_assign = non_key_fields.map {|field| "#{field} = #{val_cast(field)}"}.join(",")
value_table = value_list.map {|row| "(#{row.join(", ")})" }.join(", ")
sql = "UPDATE #{table_name} AS this SET #{columns_assign} FROM (VALUES #{value_table}) vals (#{field_list.join(", ")}) WHERE this.#{key_field} = vals.#{key_field}"
self.connection.update_sql(sql)
end
return record_list
end
def self.val_cast(field)
field = field.gsub('"', '')
if (column = columns.find{|c| c.name == field }).sql_type =~ /time|date/
"cast (vals.#{field} as #{column.sql_type})"
else
"vals.#{field}"
end
end
def self.convert_record_list(record_list)
# Build the list of fields
field_list = record_list.map(&:keys).flatten.map(&:to_s).uniq.sort
value_list = record_list.map do |rec|
list = []
field_list.each {|field| list << ActiveRecord::Base.connection.quote(rec[field] || rec[field.to_sym]) }
list
end
# If table has standard timestamps and they're not in the record list then add them to the record list
time = ActiveRecord::Base.connection.quote(Time.now)
for field_name in %w(created_at updated_at)
if self.column_names.include?(field_name) && !(field_list.include?(field_name))
field_list << field_name
value_list.each {|rec| rec << time }
end
end
field_list.map! {|field| %Q["#{field}"] }
return [field_list, value_list]
end
end

Ruby method return more than one variable

I need to return to my Rails view more than one variable from method... But how could i do this?
For example now i have
def my1
#price = 1
#price
end
but how could i also return other valuem somethin like:
def my1
#qnt = 2
#price = 1
#price, #qnt
end
?
Also my idea is to split them to string like
#price + "/-/" + #qnt
and then just split them via /-/ in view.... But this is a bad practice...
So how could i get from one method two or more variables?
Return an array:
def my1
qnt = 2
price = 1
[price, qnt]
end
then you can do this:
p, q = my1() # parentheses to emphasize a method call
# do something with p and q
Option 2
Or you can return a custom object, like this:
require 'ostruct'
def my1
qnt = 2
price = 1
OpenStruct.new(price: price, quantity: qnt)
end
res = my1() # parentheses to emphasize a method call
res.quantity # => 2
res.price # => 1
Use another object that will hold the variables and return it. You can then access the variables from that object;
Array
The easiest way is to return an Array:
def my1
#qnt = 2
#price = 1
[ #price, #qnt ]
end
price, quantity = my1
Hash
But you could also return a Hash:
def my1
#qnt = 2
#price = 1
{ :quantity => #qnt, :price = #price
end
return_value = my1
price = return_value[:price]
quantity = return_value[:quantity]
# or
price, quantity = [ return_value[:price], return_value[:quantity] ]
Custom Class
Or a custom Class:
class ValueHolder
attr_reader :quantity, :price
def initialize(quantity, price)
#quantity = quantity
#price = price
end
end
def my1
#qnt = 2
#price = 1
ValueHolder.new(#qnt, #price)
end
value_holder = my1
price = value_holder.price
quantity = value_holder.quantity
# or
price, quantity = [ value_holder.price, value_holder.quantity ]
OpenStruct
You could use OpenStruct as Sergio mentioned.

Add to class value in ruby on rails data in loop

I have such code:
def accum_search
if params[:akbcap].present?
akbcap_array = [12,18,19,20,25,30,35,36,38,40,41,42,44,45,46,47,50,52,53,54,55,56,58,60,61,62,63,64,65,66,68,69,70,71,72,74,75,77,80,85,88,90,91,92,95,98,100,102,110,115,120,125,130,135,140,170,180,185,190,192,200,210,220,225]
min, max = params[:akbcap].split('-').map {|s| s.to_i }
logger.warn("!#!!!!!!!!!!!! AAA !!!!!!!!!!")
logger.warn(min)
logger.warn(max)
caprange = min...max
sa = akbcap_array.select {|n| caprange.include? n }
##cross = OtherProductsCrossList.find(:all, :conditions => {:cross_value => 1})
cap = "*"+params[:akbcap]+"*"
sa.each do |s|
logger.warn(s)
#accums = Accumulator.by_capacity(s).by_size(params[:akbsize]).by_brand(params[:akbbrand])
end
else
#accums = Accumulator.by_capacity(50).by_size(params[:akbsize]).by_brand(params[:akbbrand])
end
end
As you see i have such part:
sa.each do |s|
logger.warn(s)
#accums = Accumulator.by_capacity(s).by_size(params[:akbsize]).by_brand(params[:akbbrand])
end
but could i add on every iteration in #accums data from search? now it has last value( I could done it via arrays... but how to do via class-variable?
Yes, initiate it before the loop and use the << operator to append. End with flatten to make it a single dimension array.
#accums = []
# ...
sa.each do |s|
#accums << Accumulator.several_method_calls......
end
#accums.flatten!
or for compactness:
result = sa.map{|s| Accumulator.several_method_calls...... }.flatten

Resources