Get impresions count from today, yesterday and this month, Impresionist gem - ruby-on-rails

I am using gem called impressionist to log page views on show action.
Everythink works just great.I can get number of all pageviews with:
#advertisement.impression_count
But now I want to be able filter pageviews per today, yesterday and this month.
So far I came up with this solution.
#today = Impression.where( :conditions => { :created_at => Date.today...Date.today+1 }, :impresionable_id =>#advertisement.id)
There is no errors.
Then In view:
<%= "#{#today} views so far!" %>
gives me #<Impression::ActiveRecord_Relation:0x000000068d46f8>
then I tried to add like : <%= "#{#today.impression_count} views so far!" %> gives me this :
undefined method `impression_count'
then I tried just :<%= "#{#today.count} views so far!" %> and still error:
Mysql2::Error: Unknown column 'conditions.created_at' in 'where clause': SELECT COUNT(*) FROM `impressions` WHERE (`conditions`.`created_at` >= '2014-12-18' AND `conditions`.`created_at` < '2014-12-19') AND `impressions`.`impresionable_id` = 127
Any ideas ?
Thanks in advance!

#today = Impression.where( :conditions => { :created_at => Date.today...Date.today+1 }, :impresionable_id =>#advertisement.id)
returns a #<Impression::ActiveRecord_Relation:0x000000068d46f8>.
Try this:
#today = Impression.where(created_at: Date.today...Date.today+1, impresionable_id: #advertisement.id).count

Add scopes in impression.rb
scope :today, -> {where("created_at >= ? AND created_at < ?", Time.now.beginning_of_day, Time.now.end_of_day)}
scope :yesterday, -> {where("created_at >= ? AND created_at < ?", 1.day.ago.beginning_of_day, 1.day.ago.end_of_day)}
scope :this_month, -> {where("created_at >= ? AND created_at < ?", Time.now.beginning_of_month, Time.now.end_of_month)}
in Controller:
#today = Impression.today.where(impresionable_id: #advertisement.id)
#yesterday = Impression.yesterday.where(impresionable_id: #advertisement.id)
#this_month = Impression.this_month.where(impresionable_id: #advertisement.id)
And you can use these scopes anywhere you need to filter Impressions by date today, yesterday or this month. It's better compared to writing the where clause everywhere.

There's no need for the conditions hash.
today = Date.today
range = today..today.next_day
#imp = Impression.where(created_at: range, impressionable_id: #advertisement.id)
And if an #advertisement can have impressions, then the following would be better:
#imp = #advertisement.impressions.where(created_at: range)
Then to get the count, you must:
#today = #imp.count
Also, just FYI, you might need to use DateTime.now instead of Date.today because you're comparing with a datetime field i.e. created_at.

It was easier than I though
In advertisement.rb
has_many :impressions, :as=>:impressionable
def view_count_yesterday
impressions.where("created_at >= ? AND created_at < ?", 1.day.ago.beginning_of_day, 1.day.ago.end_of_day).size
end
def view_count_today
impressions.where("created_at >= ? AND created_at < ?", Time.now.beginning_of_day, Time.now.end_of_day).size
# impressionist_count(:start_date => 1.day.ago)
end

Related

Rails 4 - How to get specific records based on where conditions

I have a Sale model with an :offer_end column with a date data type. I would like to display specific records of Sale where :offer_end >= Date.today. I tried to get this to work in the controller but im not sure what is the correct syntax to achieve this. This is what im currently doing which isnt working:
def index
#shops = Shop.all
#sales = Sale.where("offer_end >= Date.today", {offer_end: params[:offer_end]})
end
First of all you can't pass the Date.today as a string to the query, it will be passed to the database and it won't understand it.
The query should be something like this
#sale = Sale.where('offer_end > ?', Date.today)
The Date.today will be evaluated then passed as a value to the query.
You could replace the Date.today with any date object or date string, which in your case seems to be in theparams[:offer_end]
#sale = Sale.where('offer_end > ?', params[:offer_end])
You can use scope for these type of operations:
class Sale < ActiveRecord::Base
scope :get_products, ->(date){where(" sales.offer_end >= ? ", date)}
end
In controller you can use this scope as below:
#sales = Sale.get_products(params[:offer_end])
or you can use it directly in controller:
#sales = Sale.where("offer_end >= ?", Date.today)
and you can use params[:offer_end] instead of Date.today

Rails: Query with association?

I want to gather all posts where created_at <= Time.now, status = 0 and dislikes < 3. created_at and status is columns in the Post table, but Dislike is its own table. How can I access the amount of dislikes within the query (Post and Dislike is "connected" through has_many)?
I have this now, and it works:
#posts = Post.where("created_at <= ? AND status = ?", Time.now, 0).order("created_at DESC")
How can I include the amount of dislikes in the query?
(The Dislike table consist of :post_id and :user_id and I can get the amount of dislikes on a post by writing #post.dislikes.count)
There is at least two approaches to reach the goal:
Using having in your query
#posts = Post.joins(:dislikes).
where("posts.created_at <= ? AND posts.status = ?", Time.now, 0).
group("posts.id").
order("posts.created_at DESC").
having("COUNT(dislikes.id) < 3")
Use counter cache column (described in RailsCasts episode)
#posts = Post.
where("created_at <= ? AND status = ? AND dislikes_count < ?", Time.now, 0, 3).
order("created_at DESC")

Find and display nearest date in RoR

I am new to ruby on rails and I'm not sure where to start with this. I have a model for users, and one for projects. Users have many projects, and projects have one user. There is an end_date column in the projects table (as well as a name column).
What I want to do is find the project with the nearest end_date and display it's name and end date on the user's show page.
I tried putting this code in the projects controller, but I do not know if it is working, because I don't know how to access it and display the project name in the view.
def next_deadline(after = DateTime.now, limit = 1)
find(:all, :conditions => ['end_date > ?', after], :limit => limit)
end
Any help would be appreciated. Let me know if more information is needed.
As #Dan mentioned, you do need the :order clause to get the first one, but you should add it to your query and not replace the :conditions (otherwise you'll get the project with the earliest end_date irrespective of your after argument). The way you're defining this method is a bit off though. It should be defined in your Project model (and definitely not the controller) as a class method, or, what I think is a better approach, as a scope. In Rails < 3 (which it seems that you're using):
class Project < ActiveRecord::Base
named_scope :next_deadline, Proc.new { |after = DateTime.now, limit = 1| {:conditions => ['end_date > ?', after], :order => "end_date ASC", :limit => limit} }
...
end
Or in Rails >= 3:
class Project < ActiveRecord::Base
scope :next_deadline, Proc.new { |after = DateTime.now, limit = 1| where('end_date > ?', after).order("end_date ASC").limit(limit) }
...
end
Also, you can always test this kind of code using the Rails console: script/console in Rails < 3, rails c in Rails >= 3.
#projects = Project.find_by_sql("SELECT projects.* FROM projects
JOIN users ON users.id = projects.user_id AND projects.user_id = " + #user.id.to_s + "
WHERE projects.end_date > now()
ORDER BY projects.end_date ASC
LIMIT " + limit)
or
#projects = Project.where(:user_id => #user.id)
.where("end_date > ?", DateTime.now)
.order("end_date ASC")
You want to use :order, not :conditions.
Model.find(:all , :order => "end_date ASC")
Then the first result will be the item with the closest end_date
As Dan said, the condition you wrote won't get the nearest end date, but the dates that are greater than today, or the date passed in as a parameter.
In your User model you could write
def next_deadline_project
self.projects.first
end
as long as you give projects a default scope that orders records by end_date
In order to show information on the view you must set it in an instance variable in the User's controller show method. Instance variables are passed to views and you can access them to display the data.
#project = next_deadline_project
And in your show.html.erb you can use something like:
<%= #project.name %> - <%= #project.end_date %>

Active Record Query Using Associated Model in Find Clause

I'm having a blonde moment and probably a brain freeze.
In my rails3 app, I have users and tasks. My users have many tasks...
I have due and overdue tasks as follows:
#due = Task.find(:all, :conditions => ["dueddate >= ? AND AND status = ?", Date.today, false], :include => :taskcategories, :order => "dueddate asc")
What I want to do in my tasks view, is list the users with due tasks...
For some reason, I can't get my head around it. I have tried this, but it's not working:
#task = Task.all
#user = User.find(:all, :conditions => ["#task.dueddate <= ? AND
#task.status = ?", Date.today + 7.days, false])
I'm sure this is easy, can anyone help me!!?
I guess this should work
updated
User.joins(:tasks)
.where("tasks.dueddate <= ? AND tasks.status = ?", Date.today + 7.days, false).group(:id)
This should work with SQLite and MySQL. However, PostgreSQL requires that you supply all the columns of the table. If it's a small table, you could simply type the names. Or you could add this method to the model:
def self.column_list
self.column_names.collect { |c| "#{self.to_s.pluralize.downcase}.#{c}"}.join(",")
end
and change .group(:id) to .group(User.column_list)

Combine arrays of conditions in Rails

I'm using the Rails3 beta, will_paginate gem, and the geokit gem & plugin.
As the geokit-rails plugin, doesn't seem to support Rails3 scopes (including the :origin symbol is the issue), I need to use the .find syntax.
In lieu of scopes, I need to combine two sets of criteria in array format:
I have a default condition:
conditions = ["invoices.cancelled = ? AND invoices.paid = ?", false, false]
I may need to add one of the following conditions to the default condition, depending on a UI selection:
#aged 0
lambda {["created_at IS NULL OR created_at < ?", Date.today + 30.days]}
#aged 30
lambda {["created_at >= ? AND created_at < ?", Date.today + 30.days, Date.today + 60.days]}
#aged > 90
lamdba {["created_at >= ?", Date.today + 90.days]}
The resulting query resembles:
#invoices = Invoice.find(
:all,
:conditions => conditions,
:origin => ll #current_user's lat/lng pair
).paginate(:per_page => #per_page, :page => params[:page])
Questions:
Is there an easy way to combine these two arrays of conditions (if I've worded that correctly)
While it isn't contributing to the problem, is there a DRYer way to create these aging buckets?
Is there a way to use Rails3 scopes with the geokit-rails plugin that will work?
Thanks for your time.
Try this:
ca = [["invoices.cancelled = ? AND invoices.paid = ?", false, false]]
ca << ["created_at IS NULL OR created_at < ?",
Date.today + 30.days] if aged == 0
ca << ["created_at >= ? AND created_at < ?",
Date.today + 30.days, Date.today + 60.days] if aged == 30
ca << ["created_at >= ?", Date.today + 90.days] if aged > 30
condition = [ca.map{|c| c[0] }.join(" AND "), *ca.map{|c| c[1..-1] }.flatten]
Edit Approach 2
Monkey patch the Array class. Create a file called monkey_patch.rb in config/initializers directory.
class Array
def where(*args)
sql = args[0]
unless (sql.is_a?(String) and sql.present?)
return self
end
self[0] = self[0].present? ? " #{self[0]} AND #{sql} " : sql
self.concat(args[1..-1])
end
end
Now you can do this:
cond = []
cond.where("id = ?", params[id]) if params[id].present?
cond.where("state IN (?)", states) unless states.empty?
User.all(:conditions => cond)
I think a better way is to use Anonymous scopes.
Check it out here:
http://railscasts.com/episodes/112-anonymous-scopes

Resources