Data do ActiveRecord do Rails entre

171

Preciso consultar os comentários feitos em um dia. O campo faz parte dos registros de data e hora padrão, is created_at. A data selecionada é proveniente de a date_select.

Como posso usar ActiveRecordpara fazer isso?

Eu preciso de algo como:

"SELECT * FROM comments WHERE created_at BETWEEN '2010-02-03 00:00:00' AND '2010-02-03 23:59:59'"
rtacconi
fonte

Respostas:

402

Apenas observe que a resposta atualmente aceita está obsoleta no Rails 3. Você deve fazer isso:

Comment.where(:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day)

Ou, se você deseja ou precisa usar condições de cadeia pura , pode:

Comment.where('created_at BETWEEN ? AND ?', @selected_date.beginning_of_day, @selected_date.end_of_day)
ndbroadbent
fonte
9
Day.where (: reference_date => 6.months.ago..Time.now) funciona, graças
boulder_ruby
4
Isso não criaria um objeto de grande alcance?
Kasper Grubbe
3
@KasperGrubbe se você usou a faixa por si só faria, mas Rails usa apenas os primeiros e últimos valores
Dex
4
@KasperGrubbe @Dex Não é o Rails que faz isso. A classe Range no Ruby salva apenas os limites inferior e superior. Isso funciona bem no irb: 1..1000000000000não sei ao certo o que você quer dizer com 'usando o intervalo por si só'
Connor Clark
11
+1 Também podemos fazer um escopo: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte
48

Eu pessoalmente criaria um escopo para torná-lo mais legível e reutilizável:

No Comment.rb, você pode definir um escopo:

scope :created_between, lambda {|start_date, end_date| where("created_at >= ? AND created_at <= ?", start_date, end_date )}

Em seguida, para consulta criada entre:

@comment.created_between(1.year.ago, Time.now)

Espero que ajude.

Marshall Shen
fonte
4
Abordagem muito limpa ... perfeita !!
Joseph N.
Voltar para votar esta resposta porque procurei por esse mesmo problema. Adivinhado incorretamente na sintaxe, assumiu #between?aceito um intervalo.
Tass
28

O Rails 5.1 introduziu um novo método auxiliar de data all_day, consulte: https://github.com/rails/rails/pull/24930

>> Date.today.all_day
=> Wed, 26 Jul 2017 00:00:00 UTC +00:00..Wed, 26 Jul 2017 23:59:59 UTC +00:00

Se você estiver usando o Rails 5.1, a consulta seria semelhante a:

Comment.where(created_at: @selected_date.all_day)
Bismark
fonte
1
Glorioso. Na verdade, isso faz parte da jóia do ActiveSupport (e subsequentemente de todo o ecossistema do ActiveRecord), portanto também funciona fora do Rails! Apenas require 'active_record'e está tudo pronto!
Master of Ducks
24

Este código deve funcionar para você:

Comment.find(:all, :conditions => {:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day})

Para mais informações, consulte Cálculos de tempo

Nota: Este código está obsoleto . Use o código da resposta se você estiver usando o Rails 3.1 / 3.2

Irukandji
fonte
Ok, mas pelo formulário que recebo: {"escrita_at (4i)" => "18", "escrita_at (5i)" => "56", "conteúdo" => "rrrrrr", "escrita_at (1i)" = > "2010", "escrita_at (2i)" => "5", "escrita_at (3i)" => "4"} Como criar um objeto para usar o início do dia?
Rtacconi 04/03/10
É isso que eu preciso: purab.wordpress.com/2009/06/16/…
rtacconi
2
Eu gosto desse método sobre a resposta aceita, porque não depende de uma date()função de nível de banco de dados ; é potencialmente mais independente de db.
Craig Walker
10

Corri esse código para verificar se a resposta verificada funcionava e tive que tentar trocar as datas para acertar. Isso funcionou--

Day.where(:reference_date => 3.months.ago..Time.now).count
#=> 721

Se você está pensando que o resultado deveria ter sido 36, considere isso, senhor, quantos dias são 3 dias para 3 pessoas?

boulder_ruby
fonte
6
Comment.find(:all, :conditions =>["date(created_at) BETWEEN ? AND ? ", '2011-11-01','2011-11-15'])
kaushal sharma
fonte
5

Eu tenho usado os 3 pontos, em vez de 2. Três pontos fornecem um intervalo aberto no início e fechado no final. Portanto, se você fizer duas consultas para os intervalos subsequentes, não poderá obter a mesma linha novamente. ambos.

2.2.2 :003 > Comment.where(updated_at: 2.days.ago.beginning_of_day..1.day.ago.beginning_of_day)
Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE ("comments"."updated_at" BETWEEN '2015-07-12 00:00:00.000000' AND '2015-07-13 00:00:00.000000')
=> #<ActiveRecord::Relation []> 
2.2.2 :004 > Comment.where(updated_at: 2.days.ago.beginning_of_day...1.day.ago.beginning_of_day)
Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE ("comments"."updated_at" >= '2015-07-12 00:00:00.000000' AND "comments"."updated_at" < '2015-07-13 00:00:00.000000')
=> #<ActiveRecord::Relation []> 

E, sim, sempre é bom usar um escopo!

Nroose
fonte
4

Se você quiser apenas um dia, seria mais fácil assim:

Comment.all(:conditions => ["date(created_at) = ?", some_date])
klew
fonte
4

existem várias maneiras. Você pode usar este método:

start = @selected_date.beginning_of_day
end = @selected_date.end_of_day
@comments = Comment.where("DATE(created_at) BETWEEN ? AND ?", start, end)

Ou isto:

@comments = Comment.where(:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day)
ben
fonte
4

Deveria haver um comportamento padrão de registro ativo sobre isso. A consulta de datas é difícil, principalmente quando há fuso horário.

Enfim, eu uso:

  scope :between, ->(start_date=nil, end_date=nil) {
    if start_date && end_date
      where("#{self.table_name}.created_at BETWEEN :start AND :end", start: start_date.beginning_of_day, end: end_date.end_of_day)
    elsif start_date
      where("#{self.table_name}.created_at >= ?", start_date.beginning_of_day)
    elsif end_date
      where("#{self.table_name}.created_at <= ?", end_date.end_of_day)
    else
      all
    end
  }
Augustin Riedinger
fonte
1

Você pode usar a gema abaixo para encontrar os registros entre as datas,

Esta gema é muito fácil de usar e mais clara Por estrela, estou usando essa gema e a API é mais clara e a documentação também é bem explicada.

Post.between_times(Time.zone.now - 3.hours,  # all posts in last 3 hours
                  Time.zone.now)

Aqui você também pode passar nosso campo Post.by_month("January", field: :updated_at)

Por favor, consulte a documentação e tente.

Jenorish
fonte