Rotae ActiveRecord data tra


171

Devo interrogare i commenti fatti in un giorno. Il campo fa parte dei timestamp standard, è created_at. La data selezionata proviene da a date_select.

Come posso usare ActiveRecordper farlo?

Ho bisogno di qualcosa del tipo:

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

Risposte:


402

Solo una nota che la risposta attualmente accettata è deprecata in Rails 3. Dovresti invece farlo:

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

Oppure, se vuoi o devi usare condizioni di stringa pure , puoi fare:

Comment.where('created_at BETWEEN ? AND ?', @selected_date.beginning_of_day, @selected_date.end_of_day)

9
Day.where (: reference_date => 6.months.ago..Time.now) funziona, grazie
boulder_ruby,

4
Questo non creerebbe un oggetto dalla portata enorme?
Kasper Grubbe,

3
@KasperGrubbe se usassi l'intervallo da solo lo farebbe, ma Rails usa solo il primo e l'ultimo valore
Dex

4
@KasperGrubbe @Dex Non è Rails a farlo. La classe Range in Ruby salva solo i limiti inferiore e superiore. Funziona bene in irb: 1..1000000000000non sono chiaro cosa intendi per "utilizzo della gamma da solo"
Connor Clark,

11
+1 Possiamo anche farne uno scopo: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte

48

Personalmente avrei creato un ambito per renderlo più leggibile e riutilizzabile:

In Comment.rb è possibile definire un ambito:

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

Quindi per eseguire una query creata tra:

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

Spero che sia d'aiuto.


4
Approccio molto pulito ... perfetto !!
Joseph N.

Torna a votare questa risposta perché ho cercato proprio questo problema. Indovinato in modo errato alla sintassi, si presume che abbia #between?accettato un intervallo.
Tass

28

Rails 5.1 ha introdotto un nuovo metodo di supporto della data all_day, consultare: 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 stai usando Rails 5.1, la query sarebbe simile a:

Comment.where(created_at: @selected_date.all_day)

1
Glorioso. Questo in realtà fa parte della gemma ActiveSupport (e successivamente dell'intero ecosistema ActiveRecord), quindi funziona anche al di fuori di Rails! Solo require 'active_record'e sei pronto!
Master of Ducks

24

Questo codice dovrebbe funzionare per te:

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

Per maggiori informazioni dai un'occhiata ai calcoli del tempo

Nota: questo codice è obsoleto . Usa il codice dalla risposta se stai usando Rails 3.1 / 3.2


Ok ma dal modulo ottengo questo: {"written_at (4i)" => "18", "written_at (5i)" => "56", "content" => "rrrrrr", "written_at (1i)" = > "2010", "written_at (2i)" => "5", "written_at (3i)" => "4"} Come posso costruire un oggetto da usare begin_of_day?
rtacconi,

Questo è quello di cui ho bisogno: purab.wordpress.com/2009/06/16/…
rtacconi

2
Mi piace questo metodo rispetto alla risposta accettata perché non si basa su una date()funzione di livello db ; è potenzialmente più indipendente dal db.
Craig Walker,

10

Ho eseguito questo codice per vedere se la risposta selezionata funzionava e ho dovuto provare a scambiare le date per farlo bene. Questo ha funzionato--

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

Se pensi che l'uscita avrebbe dovuto essere 36, considera questo, signore, quanti giorni sono 3 giorni per 3 persone?


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

5

Ho usato i 3 punti, invece di 2. Tre punti ti danno un intervallo che è aperto all'inizio e chiuso alla fine, quindi se fai 2 query per intervalli successivi, non puoi ottenere la stessa riga in tutti e due.

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, sì, sempre bello usare un ambito!


4

Se vuoi ottenere solo un giorno, sarebbe più facile in questo modo:

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

4

ci sono molti modi. Puoi usare questo metodo:

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

O questo:

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

4

A mio avviso, dovrebbe esserci un comportamento record attivo predefinito. Interrogare le date è difficile, specialmente quando sono coinvolti i fusi orari.

Ad ogni modo, io 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
  }

1

Puoi utilizzare la gemma di seguito per trovare i record tra le date,

Questa gemma è abbastanza facile da usare e più chiara. Per iniziare sto usando questa gemma e l'API più chiara e anche la documentazione ben spiegata.

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

Qui puoi anche passare il nostro campo Post.by_month("January", field: :updated_at)

Si prega di consultare la documentazione e provarla.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.