Question

I have a class, Event, that has a field starts_at to say when the event starts, in datetime. The start of the Rails 3 version of this class looked as follows:

class Event < ActiveRecord::Base
  scope :between, lambda {|start_time, end_time|
    {:conditions => ["? < starts_at < ?", Event.format_date(start_time), Event.format_date(end_time)] }
  }

In the Event controller, the use of this to index events within a timeframe is as follows:

class EventsController < ApplicationController
  # GET /events
  # GET /events.json
  def index
    @events = Event.scoped
    @events = Event.between(params['start'], params['end']) if (params['start'] && params['end'])
    respond_to do |format|
      format.html # index.html.erb
      format.json { render :json => @events }
    end
  end

How do I rewrite the lamda for Rails 4, especially the ":condition =>" to scope it between the start and end times as shown in the (pretty straightforward) original lamda? I understand the original, but I cannot think how to use "where(...)" to get a time between two limit, as previously done with the condition.

Also, what do I use in the controller now that Event.scoped is deprecated?

Many thanks.

Was it helpful?

Solution

# in model
scope :between, ->(from, to) { 
  where(starts_at: (Event.format_date(from)..Event.format_date(to)))
}

# in controller
@events = Event.all
if params['start'] && params['end']
  @events = @events.between(params['start'], params['end'])  
end
...

Please note the BETWEEN syntax in Mysql has a slightly different meaning than your original query. Your query was <, BETWEEN uses <=.

OTHER TIPS

Using where

Actually changing :conditions to where is pretty straightforward. What you need in most cases is just change :conditions to where method as following:

{:conditions => ["name = ?", custom_name]}

where(name: custom_name)

In other cases you need to chain the where method with others already provided by rails:

{:conditions => ["name = ?", custom_name], :limit => 10}

where(name: custom_name).limit(10)

About comparing dates, rails knows how to handle it using ranges... for example:

where(create_at: 2.days.ago..Time.now)

or yourself can set a specific command to database.

About Model#scoped

Now it's useless, because rails use lazy loading and methods like where, all, order, etc.. are chainable. So you don't need it.

This should work:

scope :between, lambda { |start_time, end_time|
  where('? < starts_at AND starts_at < ?', Event.format_date(start_time), Event.format_date(end_time))
}

And BTW, this syntax is valid (and recommended) in Rails 3 also.

Now, Event.all is equivalent to deprecated Event.scoped - i.e. it returns ActiveRecord::Relation (and not an Array, like it used to).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top