Comments (11)
Not in the current version, but I think this is an interesting feature. I will think on adding something like this in a future release. You always have the option of adding those methods yourself, for example:
...
def total_views_today
views_on_web.today + views_on_app.today
end
...
This would give you more fine grained control over what methods-do-what, without messing excessively with tracked fields. For example, I mean, reader methods like "today" or "yesterday" does not return simple numbers (Fixnum), they return a customized class of ReaderExtender. This class acts like a Fixnum, but adds the "hourly" method so that you can also view a detailed hourly array. For example, try this over one of your models:
# Pretend @web is one of your models from the database
puts @web.views_on_web.today # Ok, nothing new
puts @web.views_on_web.today.hourly # This returns a 24 items array for a detailed hourly drill down
puts @web.views_on_web.today.class.name # Surprise! This is not a Fixnum
If you really want to add a method who acts like a super-tracking field, this is more elaborate. I coded for you a simple class called "Assimilator" that behaves like a "proxy" object or something like that:
# Assimilator class, produces "proxy" objects that assimilates other tracking fields
# Resistance is futile... :-)
class Assimilator
def initialize(owner, *fields)
@owner, @fields = owner, fields
end
def method_missing(name, *args, &blk)
# First "send" retrieves the tracking field, second forwards the current call
result = @owner.send(@fields.first).send(name, *args, &blk)
# Iterate over remaining trackers
@fields[1..-1].inject(result) do |res, field|
res + @owner.send(field).send(name, *args, &blk)
end
end
end
You can include the above code before defining the model, then, inside the model definition:
# Track exposure in search on site
track :views_on_web
# Track exposure in search on mobile
track :views_on_app
# Track combined exposure
def views_total
Assimilator.new self, :views_on_web, :views_on_app
end
Standard Disclaimer This example is done in about 5 minutes! I don't know how it will perform in production. :-) (However, I tested it agains the Trackoid specs, so it at least... work).
from trackoid.
While writing my last comment, I was thinking about two solutions that might fit better to you. You can test what of those works for you balancing easy of implementation, data size, etc, but I show here for you to decide:
Solution 1 Simply adding another tracker for total_views.
You'll need to call "inc" twice, one for either :views_on_web / :views_on_app and another for :views_total. Your data will grow, but you gain in flexibility since the calculation of web + app views must be done in all the code that retrieves it (think another process outside Rails, like fast access with Node.js to the data or whatever).
Solution 2 Why don't you use aggregators?
This will be my preferred solution, since this adds you the flexibility of adding more "sources" later, not only "web" or "app", but might be "facebook" or "twitter" or wathever.
If you don't know how aggregation works, check this example. (Again, I'm typing while thinking, beware of the typos) :-)
# Inside the "web" model class
track :views
aggregate :sources do |src|
# You must return a string to be the 'aggregation' key
return "web" if is_from_web(src)
return "app" if is_from_app(src)
nil # Returning nil here does NOT add as aggregation
# but it counts against the 'views' as total.
end
Key important things:
- You can use
@web.views.inc
like normal, but you don't get aggregated information. (beware!) - You must use
@web.views(obj).inc
andobj
is an object you will receive in the aggregate method above. - If you use "aggregate", it adds aggregators to ALL track fields.
For example, you can use the "referer" string for the aggregation key, if you reduce it to "web" or "app" perhaps using some calculations. Or either you can pass the "request" object if you must look into headers or something.
I suggest yo to test the aggregation thing inside some test environment, so you can check how it works and to test if it fits your needs. For the above example, you can do things like:
# Add one page view today for each source
# In real world, "web" and "app" strings will be the referer string
# or something you can test as the "source" of the view
@web.views("web").inc
@web.views("app").inc
@web.views.inc # Note that we don't use aggregation parameter here
# Results:
# @web.views.today == 3
# @web.views.sources.today == [["web", 1], ["app", 1]]
# @web.views.sources("web").today == 1
# @web.views.sources("app").today == 1
# @web.sources.count == 2 -- This is how many sources, not views!
I have not tested the example, I'm writing this on the fly but I think this is how aggregation works... :-) Please, tell me if this helps.
from trackoid.
Thanks for your extensive response! Seems to me that doing it with aggregators is the best way to go. I'll try that and get back to you if I find a better solution.
from trackoid.
What would these methods do? "is_from_web", "is_from_app"
from trackoid.
I included these methods as an example of what you can / should do inside an aggregation method. It's supposed to return some key as a string. When you declare an aggregation like:
aggregate :source do |obj|
# Inspect 'obj' and return a string as the key of the aggregation
end
There, the 'obj' is simply whatever you pass as parameter of @model.views(obj).inc
and it's up to you to decide what to pass in there.
As an example, imagine an aggregation like "browsers". If you aggregate browsers, you don't usually want to have a key for every combination of vendor, version, subversion, os, etc, etc. What you will do is "reduce" the user agent string to some common key like "safari", "mozilla", "chrome"... you name it.
aggregate :browsers do |user_agent|
case
when user_agent.match(/Mozilla/)
"mozilla"
when user_agent.match(/Chrome/)
"chrome"
.... every other major browser ...
else
"other"
end
end
See what happens? You will end up easily growing the aggregate method. You can move all this hassle out of here doing an external method like get_browser_key(user_agent)
and returning that instead of populating the model declaration with that big switch statement. However, it works for relatively short calculations like:
aggregate :weekday do |date|
date.strftime("%A")
end
Remember the intended use of aggregations and Trackoid in general for that matter: avoid doing calculations while displaying data by letting the server do this for you in advance. You need to balance what to save and reduce in aggregations, for example if you don't care about browser versions, don't save it! :-)
from trackoid.
Cool, sorry for the delayed answer, Thanks for your detailed explanation =)
from trackoid.
Works great by the way!
from trackoid.
However. When I reload! my console I get this error message:
/Users/yeggeps/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/trackoid-0.3.7/lib/trackoid/aggregates.rb:136: warning: already initialized constant AdAggregates
Where I aggregate and track Ad
Any idea why?
from trackoid.
This has to do with how Rails does the reloading and the config.cache_classes
option.
If this is a warning, go ahead and forget it. It will work as expected.
If you do reload!
many times a day, probably you would want to set config.cache_classes = true
but I think this will defeat the effect of the reload!
to begin with. :-)
from trackoid.
Anyway, it's a good issue to remove in a future Trackoid version. :-) Good catch!
from trackoid.
Ok, cool! :-) closing this.
from trackoid.
Related Issues (20)
- Mongoid scope? HOT 4
- Testing trackoid HOT 1
- Trackoid breaking to_json? HOT 8
- undefined method `validated?' for #<Mongoid::Tracking::Tracker> HOT 4
- NoMethodError in create_tracking_accessors HOT 4
- Upgrade to Mongoid 3.0 syntax? HOT 19
- Aggregate class can not be defined in ruby 1.9.3-p125 HOT 2
- A way to 'hide' trackoid data in output (console). HOT 3
- Is' it possible to get aggregated value for tracker ? HOT 6
- Problem using trackoid in embedded documents HOT 4
- Access and Write of RAW data (or at least been able to copy the Trackoid object) HOT 1
- unexpected sum behavior -- Rails 3.2.8, Mongoid 3.0.9, Ruby 1.9.3, & Trackoid 0.4.0 HOT 2
- Ruby 2.0 regression on sum HOT 1
- Support for rails 4.0 and ruby 2.0 HOT 6
- It would be nice to allow aggregate key to be of different data type HOT 1
- 0.4.1?
- ClassAlreadyDefined raised on all requests but first with Rails 3.1. HOT 6
- Specs fail with mongoid 2.1.2 HOT 7
- sum doesn't work HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from trackoid.