Data Rails ActiveRecord pomiędzy

171

Muszę sprawdzić komentarze przesłane w ciągu jednego dnia. Pole jest częścią standardowych znaczników czasu, to created_at. Wybrana data pochodzi z date_select.

Jak mogę ActiveRecordto zrobić?

Potrzebuję czegoś takiego:

"SELECT * FROM comments WHERE created_at BETWEEN '2010-02-03 00:00:00' AND '2010-02-03 23:59:59'"
rtacconi
źródło

Odpowiedzi:

402

Tylko uwaga, że ​​aktualnie zaakceptowana odpowiedź jest przestarzała w Railsach 3. Zamiast tego powinieneś zrobić to:

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

Lub, jeśli chcesz lub musisz używać czystych warunków łańcuchowych , możesz zrobić:

Comment.where('created_at BETWEEN ? AND ?', @selected_date.beginning_of_day, @selected_date.end_of_day)
ndbroadbent
źródło
9
Day.where (: reference_date => 6. miesiące temu..Time.now) działa, dzięki
boulder_ruby
4
Czy nie stworzyłoby to obiektu o dużym zasięgu?
Kasper Grubbe,
3
@KasperGrubbe, gdybyś użył samego zakresu, zrobiłby to, ale Rails używa tylko pierwszej i ostatniej wartości
Dex
4
@KasperGrubbe @Dex To nie Railsy to robią. Klasa Range w Rubim zapisuje tylko dolną i górną granicę. Działa to dobrze w irb: 1..1000000000000nie jestem pewien, co masz na myśli mówiąc o „używaniu zasięgu samego w sobie”
Connor Clark
11
+1 Możemy również uczynić z tego zakres: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte
48

Osobiście stworzyłbym zakres, aby był bardziej czytelny i nadający się do ponownego użycia:

W swoim Comment.rb możesz zdefiniować zakres:

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

Następnie do zapytania utworzonego między:

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

Mam nadzieję, że to pomoże.

Marshall Shen
źródło
4
Bardzo czyste podejście ... idealne !!
Joseph N.
Wróć, aby zagłosować za tą odpowiedzią, ponieważ szukałem tego właśnie problemu. Nieprawidłowo odgadnięta składnia, #between?przyjęła zakres.
Tass
28

Rails 5.1 wprowadził nową metodę pomocnika daty all_day, patrz: 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

Jeśli używasz Railsów 5.1, zapytanie będzie wyglądać następująco:

Comment.where(created_at: @selected_date.all_day)
Bismark
źródło
1
Wspaniały. W rzeczywistości jest to część perełki ActiveSupport (a następnie całego ekosystemu ActiveRecord), więc działa również poza Railsami! Po prostu require 'active_record'i gotowe!
Master of Ducks,
24

Ten kod powinien działać dla Ciebie:

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

Aby uzyskać więcej informacji, zobacz Obliczenia czasu

Uwaga: ten kod jest przestarzały . Użyj kodu z odpowiedzi, jeśli używasz Railsów 3.1 / 3.2

Irukandji
źródło
Ok, ale z formularza mam to: {"write_at (4i)" => "18", "write_at (5i)" => "56", "content" => "rrrrrr", "write_at (1i)" = > "2010", "pisany_at (2i)" => "5", "pisany_at (3i)" => "4"} Jak mogę zbudować obiekt, który będzie używał początku_dnia?
rtacconi
To jest to, czego potrzebuję: purab.wordpress.com/2009/06/16/ ...
rtacconi
2
Podoba mi się ta metoda zamiast zaakceptowanej odpowiedzi, ponieważ nie polega na date()funkcji na poziomie bazy danych; jest potencjalnie bardziej niezależny od db.
Craig Walker
10

Uruchomiłem ten kod, aby sprawdzić, czy zaznaczona odpowiedź działa, i musiałem spróbować zamienić daty, aby uzyskać poprawną odpowiedź. To zadziałało -

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

Jeśli myślisz, że wynik powinien wynosić 36, rozważ to, proszę pana, ile dni to 3 dni dla 3 osób?

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

Używałem 3 kropek zamiast 2. Trzy kropki dają zakres, który jest otwarty na początku i zamknięty na końcu, więc jeśli wykonasz 2 zapytania dla kolejnych zakresów, nie możesz odzyskać tego samego wiersza obie.

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 []> 

I tak, zawsze miło jest używać lunety!

nos
źródło
4

Jeśli chcesz mieć tylko jeden dzień, byłoby łatwiej w ten sposób:

Comment.all(:conditions => ["date(created_at) = ?", some_date])
klew
źródło
4

istnieje kilka sposobów. Możesz użyć tej metody:

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

Albo to:

@comments = Comment.where(:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day)
ben
źródło
4

Myślę, że w tym przypadku powinno być domyślne zachowanie aktywnego rekordu. Odpytywanie dat jest trudne, zwłaszcza gdy dotyczy to stref czasowych.

W każdym razie używam:

  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
źródło
1

Możesz użyć poniższego klejnotu, aby znaleźć rekordy między datami,

Ten klejnot jest dość łatwy w użyciu i bardziej przejrzysty. Według gwiazdy używam tego klejnotu i interfejsu API bardziej przejrzystego, a dokumentacja również dobrze wyjaśniona.

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

Tutaj również można było przejść przez nasze pole Post.by_month("January", field: :updated_at)

Zapoznaj się z dokumentacją i wypróbuj.

Jenorish
źródło