Fetch Google Analytics for Model Instances in Ruby on Rails - ruby-on-rails

I am trying to fetch the page views for each instance of our model Campaigns. After much Googling, I used this post as the basis of my work: http://gistflow.com/posts/398-pageviews-for-posts I am instead using the updated Legato gem.
I am having trouble fetching and saving to the database the pageviews for each Campaign.
Here is the modified code working from the gistflow post.
Rake task:
namespace :campaigns do
task :update_page_views => :environment do
google_analytics = GoogleAnalytics.new
#campaigns = Campaign.all
#campaign = Campaign.find(:all)
#campaigns.each do |campaign|
page_views = google_analytics.page_views(campaign)
campaign.update_attribute(:page_views, page_views) if page_views
end
end
end
Legato model:
class GoogleAnalytics
extend Legato::Model
metrics :pageviews
dimensions :page_path
attr_reader :profile
def page_views(campaign)
access_token = GoogleOauth2Installed.access_token
user = Legato::User.new(access_token)
profile = user.profiles.first
GoogleAnalytics.results(
profile,
:filters => {:page_path.eql => campaign.path},
:start_date => 5.years.ago.to_date,
:end_date => Date.today
).to_a.first.try(:pageviews)
end
end
However, I receive an error
undefined method `path' for #<Campaign:0xbf334a4>
If I change the filter line to:
:filters => {:page_path.eql => campaign},
then the task runs, but all of the campaigns have the same number of views which matches the total of all of the campaigns.
I played around with the GA Query tool mentioned in Getting query results with Legato gem
and can get a result I want with:
filters = ga:pagePath==/campaigns/6
However, even if I plug that into the code, the task still results with all of the campaigns having the same number which is the total of campaigns.
I have also looked at this answer How to pull Google Analytics stats? but do not have enough reputation yet to ask Severin to explain how to modify the query.
I have looked into the Impressionist gem but would like to make it work with GA as we would like to pull more GA data in the future.
Thanks so much for any help!!

Related

Rails: Fetch feed entries from certain date with Feedjira

How's it going SO'ers?
I've appended a Recent News section to the top of Users Dashboard, where it fetches news stories through Feedjira, saves the NewsEntry to the database (postgres) and then picks three random NewsEntries to display in the Dashboard#index view.
I've also created a rake task NewsEntry.update_from_feed(feed_url) to update the table with new NewsEntries scheduled to run once every 24 hours.
My problem, because it's a Recent News section I would like to fetch the NewsEntries that were published today (or yesterday; this could be a time as well). Eventually I'll add to the rake task to remove old articles and update the feed with newer articles. Right now I am getting an error trying to fetch entries on a certain date:
NoMethodError: undefined method `where' for #<Array:0x00007fcab2910d00>
NewsEntry
class NewsEntry < ApplicationRecord
def self.update_from_feed(feed_url)
feed = Feedjira::Feed.fetch_and_parse(feed_url)
add_entries(feed.entries)
end
private
def self.add_entries(entries)
today = Date.today
entries.where("published_at = ?", today) do |entry|
unless exists? :guid => entry.id
create!(
:title => entry.title,
:url => entry.url,
:published_at => entry.published,
:guid => entry.id
)
end
end
end
end
Thanks in advance for any help!

Rails App Movies API - Heroku

I have a Rails Movie App which will potentially use APIs from other websites to fill my database.
I am using the TMDB.org API (I already have an API Key) to extract, for now lets say the Title and Description of a movie.
How would I go by extracting information from the tmdb site to my site and display the information in <% #movie.title %> and <% #movie.description %>
The information taken will need to be placed in my PostgreSQL Database using Heroku
So thats one question
The other question is how would I do this without running a method for every movie in the TMDB database
For Example, using the Ruby-TMDB Gem, instead of running
TmdbMovie.find(:title => "The Social Network", :limit => 10, :expand_results => true, :language => "en")
and
TmdbMovie.find(:title => "The Dark Knight Rises ", :limit => 10, :expand_results => true, :language => "en")
for every movie I want in my database (which is every movie in the TMDB Database), what would I run to GET ALL Movies.
And then Display them in my movies :show page
To sum it all up, how to I get database information from TMDB.org to my rails app and display information from a TMDB Movie :show page to my movie :show page, using the Ruby-TMDB Gem IN Heroku? Would there be a rake task, if so what would it be?
Many Thanks!
There are 2 problems you wish to tackle.
How and where in my rails app should I pull the data?
Yeah this can be accomplished with rake. Add a new rake file lib/tasks/tmdb.rake
namespace :db do
task :pull_tmdb_data => :environment do
Tmdb.api_key = "t478f8de5776c799de5a"
# setup your default language
Tmdb.default_language = "en"
# find movies by id
#movie = TmdbMovie.find(id: 123)
Movie.create title: #movie.title, description: #movie.description
# find movies in groups
#movies = TmdbMovie.find(:title => 'Iron Man')
#movies.each do |movie|
Movie.create title: movie.title, description: movie.description
end
end
end
And now everytime you want to populate your db with tmdb you can simply run rake db:pull_tmdb_data
What are the necessary queries to pull all the movies from tmdb?
By glancing over their api there is no shortcut to duplicating the database, if you want to duplicate it your best bet may be to contact them directly. You can brute force it by trying every possible id for movies but beware that they do throttle you. Below is a quote from their website.
We do enforce a small amount of rate limiting. Please be aware that should you exceed these limits, you will receive a 503 error.
30 requests every 10 seconds per IP
Maximum 20 simultaneous
connections
It may be worth considering if you really need to duplicate tmdb. When tmdb is adding new movies and fixing errors in their data your database will be outdated as a result you will face a slew of data integrity issues which will be hard to resolve.

how to append database records in to a variable in ruby on rails

I fetched all users from the database based on city name.
Here is my code:
#othertask = User.find(:all, :conditions => { :city => params[:city]})
#othertask.each do |o|
#other_tasks = Micropost.where(:user_id => o.id).all
end
My problem is when loop gets completed, #other_task holds only last record value.
Is it possible to append all ids record in one variable?
You should be using a join for something like this, rather than looping and making N additional queries, one for each user. As you now have it, your code is first getting all users with a given city attribute value, then for each user you are again querying the DB to get a micropost (Micropost.where(:user_id => o.id)). That is extremely inefficient.
You are searching for all microposts which have a user whose city is params[:city], correct? Then there is no need to first find all users, instead query the microposts table directly:
#posts = Micropost.joins(:user).where('users.city' => params[:city])
This will find you all posts whose user has a city attribute which equals params[:city].
p.s. I would strongly recommend reading the Ruby on Rails guide on ActiveRecord associations for more details on how to use associations effectively.
you can do it by following way
#othertask = User.find(:all, :conditions => { :city => params[:city]})
#other_tasks = Array.new
#othertask.each do |o|
#other_tasks << Micropost.where(:user_id => o.id).all
end
Here is the updated code:
#othertask = User.find_all_by_city(params[:city])
#other_tasks = Array.new
#othertask.each do |o|
#other_tasks << Micropost.find_all_by_user_id(o.id)
end
You are only getting the last record because of using '=' operator, instead you need to use '<<' operator in ruby which will append the incoming records in to the array specified.
:)
Try:
User model:
has_many :microposts
Micropost model:
belongs_to :user
Query
#Microposts = Micropost.joins(:user).where('users.city' => params[:city])

Cleaning up controllers to speed up application

So in my app I have notifications and different record counts that are used in the overall layout, and are therefore needed on every page.
Currently in my application_controller I have a lot of things like such:
#status_al = Status.find_by_name("Alive")
#status_de = Status.find_by_name("Dead")
#status_sus = Status.find_by_name("Suspended")
#status_hid = Status.find_by_name("Hidden")
#status_arc = Status.find_by_name("Archived")
#balloon_active = Post.where(:user_id => current_user.id, :status_id => #status_al.id )
#balloon_dependent = Post.where(:user_id => current_user.id, :status_id => #status_de.id )
#balloon_upcoming = Post.where(:user_id => current_user.id, :status_id => #status_sus.id )
#balloon_deferred = Post.where(:user_id => current_user.id, :status_id => #status_hid.id )
#balloon_complete = Post.where(:user_id => current_user.id, :status_id => #status_arc.id )
..
Thats really just a small piece, I have at least double this with similar calls. The issue is I need these numbers pretty much on every page, but I feel like I'm htting the DB wayyyy too many times here.
Any ideas for a better implementation?
Scopes
First off, you should move many of these into scopes, which will allow you to use them in far more flexible ways, such as chaining queries using ActiveRecord. See http://edgerails.info/articles/what-s-new-in-edge-rails/2010/02/23/the-skinny-on-scopes-formerly-named-scope/index.html.
Indexes
Second, if you're doing all these queries anyway, make sure you index your database to, for example, find Status quickly by name. A sample migration to accomplish the first index:
add_index :status (or the name of your Status controller), :name
Session
If the data you need here is not critical, i.e. you don't need to rely on it to further calculations or database updates, you could consider storing some of this data in the user's session. If you do so, you can simply read whatever you need from the session in the future instead of hitting your db on every page load.
If this data is critical and/or it must be updated to the second, then avoid this option.
Counter Caching
If you need certain record counts on a regular basis, consider setting up a counter_cache. Basically, in your models, you do the following:
Parent.rb
has_many :children
Child.rb
belongs_to :parent, :counter_cache => true
Ensure your parent table has a field called child_count and Rails will update this field for you on every child's creation/deletion. If you use counter_caching, you will avoid hitting the database to get the counts.
Note: Using counter_caching will result in a slightly longer create and destroy action, but if you are using these counts often, it's usually worth going with counter_cache.
You should only need 1 database query for this, something like:
#posts = Post.where(:user_id => current_user.id).includes(:status)
Then use Enumerable#group_by to collect the posts into the different categories:
posts_by_status = #posts.group_by do {|post| post.status.name }
which will give you a hash:
{'Alive' => [...], 'Dead' => [...]}
etc.

Sort by date using acts_as_solr

I have gotten sorting working from my rails application using acts_as_solr for text fields, as seen below with Title.
I am having problems getting it to work for date.
My model has the following
class Article < ActiveRecord::Base
acts_as_solr :fields[:title, {:title_s=> :string}, {:created_at_d => :date}]
def title_s
self.title
end
def created_at_d
self.created_at
end
The following is being sent to the solr server:
path=/select params={wt=ruby&rows=10start=0&sort=created_at_d_d+asc&fl=pk_i,score&q=(+searchtext)..........
The solr code
Article.paginate_all_by_solr(searchString, :order=> "created_at_d asc", :page = page, :per_page => results_per_page, :total_entrieds => count)
Is there something obvious I am doing wrong? I am not sure that the {:created_at_d => :date} in the model is the correct way to set up the index for dates.
When I just coin it off of :created_at, I get the error around tokenized fields similar to that when I tried to sort against :title.
Something was wrong with the index.
When I went into script/console and ran
Article.rebuild_solr_index
It did not index the date correctly.
I created a rake task from with the following site.
http://henrik.nyh.se/2007/06/rake-task-to-reindex-models-for-acts_as_solr
When I ran
>rake solr:reindex
The index was created correctly and the date sorting started working.

Resources