I have simple app that is meant to pull Adwords account metrics (via the adwordsapi) and present it to the user in a table inside a Rails view. It is working properly pulling down all info for multiple campaigns except for one issue..
I am unable to get the totals of each field (total cost, total impressions, etc.). I am able to serve impressions for each campaign within the account, but am unable to get the totals for the account.
I apologize ahead of time for the noob code to follow :)
Here is the adwordscampaign_controller.rb
class AdwordscampaignController < ApplicationController
PAGE_SIZE = 50
def index()
@selected_account = selected_account
if @selected_account
response = request_campaigns_list()
if response
@campaigns = Adwordscampaign.get_campaigns_list(response)
@campaign_count = response[:total_num_entries]
@start = params[:start]
@end = params[:end]
@myhash = Adwordscampaign.get_campaigns_list(response)
end
end
end
private
def request_campaigns_list()
# Prepare start and end date for the last week.
if params[:start].nil?
start_date = DateTime.parse((Date.today - 7).to_s).strftime("%Y%m%d")
end_date = DateTime.parse((Date.today - 1).to_s).strftime("%Y%m%d")
else
start_date = params[:start]
end_date = params[:end]
end
api = get_adwords_api()
service = api.service(:CampaignService, get_api_version())
selector = {
:fields => ['Id', 'Name', 'Status', 'Cost', 'Impressions', 'Clicks', 'Ctr', 'Conversions', 'Amount'],
:ordering => [{:field => 'Id', :sort_order => 'ASCENDING'}],
:date_range => {:min => start_date, :max => end_date},
:paging => {:start_index => 0, :number_results => PAGE_SIZE}
}
result = nil
begin
result = service.get(selector)
rescue AdwordsApi::Errors::ApiException => e
logger.fatal("Exception occurred: %s\n%s" % [e.to_s, e.message])
flash.now[:alert] =
'API request failed with an error, see logs for details'
end
return result
end
end
the relevant model: adwordscampaign.rb
class Adwordscampaign
attr_reader :id
attr_reader :name
attr_reader :status
attr_reader :cost
attr_reader :impressions
attr_reader :clicks
attr_reader :ctr
attr_reader :costdecimal
attr_reader :costperconversiondecimal
def initialize(api_campaign)
@id = api_campaign[:id]
@name = api_campaign[:name]
@status = api_campaign[:status]
budget = api_campaign[:budget]
stats = api_campaign[:campaign_stats]
@cost = (stats[:cost][:micro_amount] / 10000)
@costdecimal = (@cost * 10000).round.to_f / 1000000
@impressions = stats[:impressions]
@clicks = stats[:clicks]
@ctr = (stats[:ctr] * 100)
end
def self.get_campaigns_list(response)
result = {}
if response[:entries]
response[:entries].each do |api_campaign|
campaign = Adwordscampaign.new(api_campaign)
result[campaign.id] = campaign
end
end
return result
end
end
The table from the views\\adwordscampaign\\index.html.erb
<table class="table table-striped table-bordered">
<tr>
<th>ID
<th>Name
<th>Status
<th>Impressions
<th>Clicks
<th>CTR
<th>Cost
<% @campaigns.each do |id, campaign| %>
<tr>
<td><%= campaign.id %></td>
<td><%= campaign.name %></td>
<td><%= campaign.status %></td>
<td><%= number_with_delimiter(campaign.impressions) %></td>
<td><%= number_with_delimiter(campaign.clicks) %></td>
<td><%= number_with_precision(campaign.ctr, precision: 2) %>%</td>
<td>$<%= number_with_delimiter(campaign.costdecimal) %></td>
<% end %>
<td><%= @campaigns %></td>
</table>
I threw @campaigns in the view (at the bottom) so I could see what the output of that was. The syntax is a little unfamiliar to me but it appears to be hashes nested in a hash (correct?)
output of @campaigns in the view
{109886905=>#<Adwordscampaign:0x4528ba0 @id=109879905, @name="Upholstery Cleaning", @status="ACTIVE", @cost=2702, @costdecimal=27.02, @impressions=824, @clicks=7, @ctr=0.8495145631067961>, 103480025=>#<Adwordscampaign:0x7028b28 @id=109880025, @name="Carpet Cleaning", @status="ACTIVE", @cost=16739, @costdecimal=167.39, @impressions=4457, @clicks=29, @ctr=0.6506618801884676>, 104560145=>#<Adwordscampaign:0x3e9ibac8 @id=109880145, @name="Competitors", @status="ACTIVE", @cost=1596, @costdecimal=15.96, @impressions=515, @clicks=5, @ctr=0.9708737864077669>
Finally to the question - How would I get the total @clicks (or @impressions, @cost, etc.) for each of the 3 campaigns found here?
I've been searching for things like "how to sum identical hash keys/values" or "how to merge nested hashes" to no avail.
Thanks in advance!
@campaigns
looks like a simple hash of { id -> Adwordscampaign }. The #<ObjectName:data>
notation is Ruby doing its best to give you something readable for that object.
To sum clicks, for example, is a simple map-reduce:
total_clicks = @campaigns.map { |id, campaign| campaign.clicks } .reduce(&:+)
This creates an array of all campaign.clicks
values, then combines them all using the +
operator.
This assumes there is a #clicks
on those objects. If not, tweak accordingly.
If all you're doing is summing various attributes, you can simplify using it multiple times like so:
camp_list = @campaigns.map { |id, campaign| campaign }
total_clicks = camp_list.map(&:clicks).reduce(&:+)
total_cost = camp_list.map(&:cost).reduce(&:+)
total_impressions = camp_list.map(&:impressions).reduce(&:+)
Reducing it further is an exercise to the reader. :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.