i have a custom method on my model and i want to use it in a where condition, i already accomplish this for sorting with custom methods, but can't find a way for search with custom conditions.
Now i have this, in my model
attr_accessible :end, :start
def time_left
self.end.to_i - Time.now.utc.to_i - Time.now.utc_offset
end
def time_left_to_start
self.start.to_i - Time.now.utc.to_i - Time.now.utc_offset
end
def status
if self.time_left_to_start > 0
1 #proximamente
elsif self.time_left_to_start < 0 and self.time_left > 0
2 #funcionando
else
3 #finalizado
end
end
and for my controller
def index
#next_events = Event.all.sort_by(&:time_left).reverse!.reject { |e| e.status != 1 }.take(5)
end
i know i can write the entire condition on the where method, but my idea is don't repeat my self and avoid to loop for all the events to remove each one where the status isn't 1, i just need the last 5 each time and looks to me really bad idea ask to the db for all the records each time.
Thanks in advance, regards!
After refactoring my code i came across with this
def time_left
(self.end - Time.now).to_i
end
def time_left_to_start
(self.start - Time.now).to_i
end
def status
if self.start < Time.now and self.end > Time.now
1 #En curso
elsif self.start > Time.now
2 #Proximamente
else
3 #Finalizado
end
end
def self.status(status)
if status == 1 #eventos en curso
where("(events.start < ?) AND (events.end > ?)", Time.now, Time.now)
elsif status == 2 #proximos eventos
where("events.start > ?", Time.now)
elsif status == 3 #eventos finalizados
where("events.end < ?", Time.now)
elsif status == 4 #eventos proximos y en curso
where("events.end > ?", Time.now)
end
end
and making queries like this
#next_events = Event.status(2).order('events.start DESC').reject { |e| e.time_left_to_start > 12.hour }.take(18)
Thanks for your time, regards!
Related
I have two tables: App (with a release_id field) and User.
Models
class App < ActiveRecord::Base
has_one :user
end
class User < ActiveRecord::Base
belongs_to :app
end
Class
class Stats::AppOverview
def initialize(from:, apps:)
#from = from || Date.new(2010)
#apps = apps
end
def total_count
{ apps: { total: total_app, with_user: app_with_user } }
end
private
def app_since
#apps.where('created_at >= ?', #from)
end
def total_app
devices_since.count
end
def app_with_user
User.where(app: app_since).count
end
end
I would like to return
the number of app records for a given array of release_id
the number of app records that belong to each user, satisfying other criteria
This is how I use the class
Stats::AppOverview.new(from: 1.month.ago.iso8601,
apps: App.where(release_id: [1,2,3,4,5,19,235]).total_count
#=> { apps: { total: 65, with_user: 42 } }
For the moment I do it in two queries, but is it possible to put them in the same query? Is this possible using active record?
I have two models:
class Invoice < ActiveRecord::Base
has_many :payments_received
end
class PaymentReceived < ActiveRecord::Base
belongs_to :invoice
end
I need to write a query to find invoices that have either no payments_received or the sum of the payments_received.amount is less than the invoice.amount
I am able to find invoices with no payments_received:
#invoices = Invoice.includes(:payments_received).where( :payments_received => { :invoice_id => nil } )
But I need to find invoices where the sum of all of its associated payments_received is less than invoice.amount.
This is a class method that accomplishes what I need, but I'd like to do this without pulling all of the invoices out of the database and iterating through each one of them.
def self.unpaid
unpaid_invoices = []
total_payments = 0
invoices = Invoice.all
invoices.each do |invoice|
if invoice.payments_received.empty?
unpaid_invoices << invoice
else
invoice.payments_received.each do |payment_received|
total_payments += payment_received.amount
end
if total_payments < invoice.amount
unpaid_invoices << invoice
end
end
end
unpaid_invoices
end
you can chain where clauses:
#invoices = Invoice.includes(:payments_received).where( :payments_received => { :invoice_id => nil } ).where("payments_received.amount > ?", amount)
try writing them both individually and after you're getting what you want to return chain the query together.
I hope you want something like this.
#invoices.collect do |invoice|
invoice.payments_received.pluck(:amount).sum < invoice.amount ? invoice : next
end.compact
I have a model that has two columns (started_at and ended_at). I want to add a custom validator that ensures that no other record exists with dates that overlap with the record I'm validating. So far I have:
# app/models/event.rb
class Event < ActiveRecord::Base
validates_with EventValidator
end
# app/validators/event_validator.rb
class EventValidator < ActiveModel::Validator
attr_reader :record
def validate(record)
#record = record
validate_dates
end
private
def validate_dates
started_at = record.started_at
ended_at = record.ended_at
arel_table = record.class.arel_table
# This is where I'm not quite sure what type of query I need to perform...
constraints = arel_table[:started_at].gteq(ended_at)
.and(arel_table[:ended_at].lteq(started_at))
if record.persisted?
constraints = constraints
.and(arel_table[:id].not_eq(record.id))
end
if record.class.where(constraints).exists?
record.error[:base] << "Overlaps with another event"
end
end
end
I don't know exactly what query I need to ensurethat there is no overlapping. Any help is greatly appreciated
I don't use Arel but I think the query should be:
constraints = arel_table[:started_at].lteq(ended_at)
.and(arel_table[:ended_at].gteq(started_at))
Two periods overlap when
period1.start < period2.end
period1.end > period2.start
Have a look at Validates Overlap gem
You can either use it instead your code or take condition code from it
# Return the condition string depend on exclude_edges option.
def condition_string(starts_at_attr, ends_at_attr)
except_option = Array(options[:exclude_edges]).map(&:to_s)
starts_at_sign = except_option.include?(starts_at_attr.to_s.split(".").last) ? "<" : "<="
ends_at_sign = except_option.include?(ends_at_attr.to_s.split(".").last) ? ">" : ">="
query = []
query << "(#{ends_at_attr} IS NULL OR #{ends_at_attr} #{ends_at_sign} :starts_at_value)"
query << "(#{starts_at_attr} IS NULL OR #{starts_at_attr} #{starts_at_sign} :ends_at_value)"
query.join(" AND ")
end
I would construct a query that looks something like this:
Event.exists?( 'started_at < ? AND ended_at > ?', ended_at, started_at )
If this returns true, an overlapping record exists.
How could I change the column name in the argument of a where clause? Something like this is what I'm after:
def self.filter_by_time(datetime)
where('? < ?', datetime, Time.now)
end
Thanks!
def self.filter_by_time(datetime)
where("#{datetime} < ?", Time.now)
end
You can try this:
def self.filter_by_time(datetime)
where("datetime < ?", Time.now)
end
I would like to add some methods to some AR Models of my App; but I think they should only be available under some circumstances; this requires some meta-programming.
So I'd like to have a file where I put all my debug methods, the only question is where to put it?
Example, I have the models:
class Admin::Restaurant < ActiveRecord::Base
class Admin::Order < ActiveRecord::Base
And in my file I have (it does deppend on MetaWhere.operator_overload! initialization):
if Rails.env != 'production'
class Admin::Order
def self.mock_make
r = Restaurant.first
user_query = User.where( :created_at > "2011-04-01" )
u = user_query.first( :offset => ( user_query.count * rand ).to_i )
o = r.orders.new
o.user = u
o.value = rand(100) + rand.round(2)
if o.save
return o
else
return nil
end
end
end
end
The thing is.. I can't get it to work on /config/initializers or /app/models.
Wrap it as a external module and include it with if condition
class MyClass << ActiveRecord::Base
include MyExtraModule if Rails.env == 'development'
end
Put them in config/environments/development.rb