1

I made a scope help me to select objects

  scope :best_of_the_month, ->(year, month) do
    time = Time.new(year, month)
    start_time = time.beginning_of_month
    end_time = time.end_of_month
    where("created_at > ? AND created_at < ?", start_time, end_time).where("likes > ?", 15).where("rating > ?", 4.85).order_by_rating.to_a.uniq(&:author)
  end

Then, I want to loop through this method, from 2014/1 to now. How can I do it?

Maybe something like this:

  start_date = Date.create(2014,1).month
  end_date = Date.today.month
  @monthly_videos = []
  (start_date..end_date).each do |year, month|
    videos = Video.best_of_the_month(year, month)
    @monthly_videos << videos
  end

I find a solution here, How to Loop through Months in Ruby on Rails. But it seems about looping through the days. Not the month

Community
  • 1
  • 1
ZK Zhao
  • 19,885
  • 47
  • 132
  • 206

2 Answers2

1

With the best_of_the_month scope defined to take month and year as params, the following code should work:

date = Date.new(2014,1,1)
@monthly_videos = []
while true
  videos = Video.best_of_the_month(date.year, date.month)
  @monthly_videos << videos
  date += 1.month
  break if date == Date.today.beginning_of_month
end
Prakash Murthy
  • 12,923
  • 3
  • 46
  • 74
  • Could you explain why using a `while true` loop? – ZK Zhao Jan 10 '15 at 15:08
  • Using `while true` to continue looping till `break` exits the loop. This happens when the condition is met. See the details about `break` here: http://www.tutorialspoint.com/ruby/ruby_loops.htm – Prakash Murthy Jan 10 '15 at 15:10
  • Semantically speaking, it would be better to use `loop do end` instead of a `while true; end` loop. – yeyo Jan 10 '15 at 15:16
  • I have use this kind loop before. How can I change it to something more elegant? Or is this a very practical approach for looping? – ZK Zhao Jan 11 '15 at 02:42
1

You could use the Date#next_month method

date           = Date.new(2014,1,1)
final_date     = Date.new(Date.today.year, Date.today.month)
@monthly_video = []

loop do
    @monthly_videos << Video.best_of_the_month(date.year, date.month)

    break if date == final_date
    date = date.next_month
end
yeyo
  • 2,954
  • 2
  • 29
  • 40
  • For the range approach, how many times would it iterate? I thought it would iterate all the dates' month? – ZK Zhao Jan 11 '15 at 02:41
  • @cqcn1991, it will iterate more than necessary I'm afraid. I suppose one can't use range for months. I've fixed the code I was proposing (for obvious reasons). Thank you for pointing this out. – yeyo Jan 11 '15 at 04:50