searching records between start date and end dates for ransack
Asked Answered
O

6

8

Hi i am using ransack + kalendae_assets gem for searching records in between start date and end date for this i am using ransack PREDICATES by referring https://github.com/ernie/ransack/blob/master/lib/ransack/constants.rb

here is my code

<%= search_form_for @search, url: guest_search_rooms_path, html: {:method =>:post} do |f| %>
  <%= f.label :start_date_eq , "Start Date"%>   
  <%= f.text_field :start_date_eq, class: 'release_date' %>     

  <%=f.label :end_date_eq, "End Date" %>   
  <%= f.text_field :end_date_lteq, class: 'release_date' %>     
  <%= f.submit "search" %>
<% end %>

rooms.controller

def guest_search 

  @search = Room.search(params[:q])
  @roome = @search.result(:distinct => true)
  @room= @roome.where("status IS ?", true).order("room_type_id desc")

  #@room = @search.result(:distinct => true)
 end 

but when i enters start and end date it not searches how can i do this

Ottilie answered 9/4, 2013 at 6:44 Comment(7)
show the output of @room.to_sqlRandolph
this shows blank nothing display anything though there are many records present in that date rangeOttilie
@room.to_sql should return the query that activerecord will use to retrieve the data. Try 'Room.search(params[:q]).result.to_sql'.Randolph
no this not worked. it gives me error that NoMethodError (undefined method `result' for nil:NilClass)Ottilie
@Ottilie did you ever find a solution for this? I am looking for similar implementation.Dovecote
I think instead of <%= f.text_field :start_date_eq, class: 'release_date' %> you should write <%= f.text_field :start_date_gteq, class: 'release_date' %>.Dittman
@Dovecote can you see the answer and let me know your feedback on itOttilie
G
2

You can use range with starting date and end date. Then you can get search result between the dates. Here is the sample code in your search form:

<div class="control-group">
    <%= f.label :scrap_date_cont, "Scrap Date", class: 'control-label' %>
    <div class="controls">
      <% if q.scrap_date_cont.blank? %>
    <%= f.text_field :scrap_date_cont, include_blank: true, default: nil, :class => 'datepicker3', :style=>"width:100px;" %> 
      <% elsif !q.scrap_date_cont.blank? %>
      <%= f.text_field :scrap_date_cont, :value => "#{change_date_format_for_edit_page(q.scrap_date_cont)}", :class => 'datepicker3', :style=>"width:100px;" %> 
      <% end %>&nbsp;<%= link_to "Select Range", "#", :id => 'dates' %> 

    </div>
  </div>


     <div class="control-group" id="range" style="display:none" >
        <%= f.label :scrap_date_gteq, "Range", class: 'control-label' %>

        <div class="controls">
          <% if q.scrap_date_gteq.blank? %>
          <%= f.text_field :scrap_date_gteq, include_blank: true, default: nil, :class => 'datepicker1', :style=>"width:100px;" %>
          <% elsif !q.scrap_date_gteq.blank? %>
          <%= f.text_field :scrap_date_gteq, :value => "#{change_date_format_for_edit_page(q.scrap_date_gteq)}", :class => 'datepicker1', :style=>"width:100px;" %> 
          <% end %>

           <% if q.scrap_date_lteq.blank? %>
          <%= f.text_field :scrap_date_lteq, include_blank: true, default: nil, :class => 'datepicker2', :style=>"width:100px;"  %>
           <% elsif !q.scrap_date_lteq.blank? %>
           <%= f.text_field :scrap_date_lteq, :value => "#{change_date_format_for_edit_page(q.scrap_date_lteq)}", :class => 'datepicker2', :style=>"width:100px;" %> 
           <% end %>
        </div>
      </div>

And Here is the controller code:

params[:q][:scrap_date_cont] = change_date_format(params[:q][:scrap_date_cont]) if !(params[:q][:scrap_date_cont]).blank?
    params[:q][:scrap_date_cont] =  params[:q][:scrap_date_cont].to_date.strftime("%d/%Y/%m") if !(params[:q][:scrap_date_cont]).blank?
    params[:q][:scrap_date_gteq] = change_date_format(params[:q][:scrap_date_gteq]) if !(params[:q][:scrap_date_gteq]).blank?
    params[:q][:scrap_date_gteq] =  params[:q][:scrap_date_gteq].to_date.strftime("%d/%Y/%m") if !(params[:q][:scrap_date_gteq]).blank?
       params[:q][:scrap_date_lteq] = change_date_format(params[:q][:scrap_date_lteq]) if !(params[:q][:scrap_date_lteq]).blank?
     params[:q][:scrap_date_lteq] =  params[:q][:scrap_date_lteq].to_date.strftime("%d/%Y/%m") if !(params[:q][:scrap_date_lteq]).blank? 

Helper code:

#Change date format in edit time
 def change_date_format_for_edit_page(date)
    new_date = date.strftime("%m/%d/%Y")
    puts new_date.inspect
    return new_date
  end

Script :

$("#dates").click(function () {
  var $that = $(this);
  $("#range").toggle("slow", function() {
    $that.toggleClass("toggled-off");
  });
});

I think it might help you...

Gamba answered 13/3, 2014 at 7:34 Comment(0)
B
7

With https://github.com/dangrossman/bootstrap-daterangepicker you can do date range search with:

= search_form_for q, url: orders_path, builder: SimpleForm::FormBuilder do |f|
  = f.input :daterange , input_html: {value: "#{q.date_gteq.to_s} - #{q.date_lteq.to_s}"}
  = f.input :date_gteq, as: :hidden
  = f.input :date_lteq, as: :hidden

:coffee
  $ ->
    $('#q_daterange').daterangepicker
      format: "YYYY-MM-DD"
      startDate: $('#q_date_gteq').val()
      endDate: $('#q_date_lteq').val()
      ranges:
        'This Week': [moment().startOf('week'), moment().endOf('week')],
        'Next Week': [moment().add('week', 1).startOf('week'), moment().add('week', 1).endOf('week')]
    , (start, end, label) ->
      $('#q_date_gteq').val start.format("YYYY-MM-DD")
      $('#q_date_lteq').val end.format("YYYY-MM-DD")
    .on 'apply.daterangepicker', -> $('#order_search').submit()
Barn answered 27/6, 2014 at 21:22 Comment(0)
D
4

You could make a custom predicate.

In my view I have a ransack search field like

= f.text_field :request_date_between, class: 'daterange'

That will send a date to the controller like

'2015-10-01 to 2015-10-31'

then in my down and dirty ransack.rb initializer I have;

Ransack.configure do |config|
  config.add_predicate 'between',
                       arel_predicate: 'between',
                       formatter: proc { |v| v.split(' to ') },
                       type: :string
end

module Arel
  module Predications
    def between other
      gteq(other[0]).and(lt(other[1]))
    end
  end
end
Dumbarton answered 29/8, 2016 at 14:48 Comment(0)
S
4

to make between predicate recognize local timezone, in ransack.rb initializer...

Ransack.configure do |config|
  config.add_predicate 'between',
                       arel_predicate: 'between',
                       formatter: proc { |v| Range.new(*v.split(' to ').map { |s| Time.zone.parse(s) }) },
                       type: :string
end

No need to overwrite Arel::Predications#between.

(This works only on datetime column type.)

Spooky answered 28/9, 2018 at 11:17 Comment(1)
Works perfect. Thanks.Fiber
G
2

You can use range with starting date and end date. Then you can get search result between the dates. Here is the sample code in your search form:

<div class="control-group">
    <%= f.label :scrap_date_cont, "Scrap Date", class: 'control-label' %>
    <div class="controls">
      <% if q.scrap_date_cont.blank? %>
    <%= f.text_field :scrap_date_cont, include_blank: true, default: nil, :class => 'datepicker3', :style=>"width:100px;" %> 
      <% elsif !q.scrap_date_cont.blank? %>
      <%= f.text_field :scrap_date_cont, :value => "#{change_date_format_for_edit_page(q.scrap_date_cont)}", :class => 'datepicker3', :style=>"width:100px;" %> 
      <% end %>&nbsp;<%= link_to "Select Range", "#", :id => 'dates' %> 

    </div>
  </div>


     <div class="control-group" id="range" style="display:none" >
        <%= f.label :scrap_date_gteq, "Range", class: 'control-label' %>

        <div class="controls">
          <% if q.scrap_date_gteq.blank? %>
          <%= f.text_field :scrap_date_gteq, include_blank: true, default: nil, :class => 'datepicker1', :style=>"width:100px;" %>
          <% elsif !q.scrap_date_gteq.blank? %>
          <%= f.text_field :scrap_date_gteq, :value => "#{change_date_format_for_edit_page(q.scrap_date_gteq)}", :class => 'datepicker1', :style=>"width:100px;" %> 
          <% end %>

           <% if q.scrap_date_lteq.blank? %>
          <%= f.text_field :scrap_date_lteq, include_blank: true, default: nil, :class => 'datepicker2', :style=>"width:100px;"  %>
           <% elsif !q.scrap_date_lteq.blank? %>
           <%= f.text_field :scrap_date_lteq, :value => "#{change_date_format_for_edit_page(q.scrap_date_lteq)}", :class => 'datepicker2', :style=>"width:100px;" %> 
           <% end %>
        </div>
      </div>

And Here is the controller code:

params[:q][:scrap_date_cont] = change_date_format(params[:q][:scrap_date_cont]) if !(params[:q][:scrap_date_cont]).blank?
    params[:q][:scrap_date_cont] =  params[:q][:scrap_date_cont].to_date.strftime("%d/%Y/%m") if !(params[:q][:scrap_date_cont]).blank?
    params[:q][:scrap_date_gteq] = change_date_format(params[:q][:scrap_date_gteq]) if !(params[:q][:scrap_date_gteq]).blank?
    params[:q][:scrap_date_gteq] =  params[:q][:scrap_date_gteq].to_date.strftime("%d/%Y/%m") if !(params[:q][:scrap_date_gteq]).blank?
       params[:q][:scrap_date_lteq] = change_date_format(params[:q][:scrap_date_lteq]) if !(params[:q][:scrap_date_lteq]).blank?
     params[:q][:scrap_date_lteq] =  params[:q][:scrap_date_lteq].to_date.strftime("%d/%Y/%m") if !(params[:q][:scrap_date_lteq]).blank? 

Helper code:

#Change date format in edit time
 def change_date_format_for_edit_page(date)
    new_date = date.strftime("%m/%d/%Y")
    puts new_date.inspect
    return new_date
  end

Script :

$("#dates").click(function () {
  var $that = $(this);
  $("#range").toggle("slow", function() {
    $that.toggleClass("toggled-off");
  });
});

I think it might help you...

Gamba answered 13/3, 2014 at 7:34 Comment(0)
B
2

Here's a solution with a dropdown to choose the date range. We'll add a between predicate and pass it a datetime range formatted as a string, like below:

(5.days.ago..5.days.from_now).to_s

=> "2021-05-30 15:21:05 +0200..2021-06-09 15:21:05 +0200"

First add a Ransack between predicate, relying on the native between Arel predicate. The formatter takes that string value and splits it on '..', converts the start/end dates as DateTime and builds a range.

# config/initializers/ransack.rb
Ransack.configure do |config|
  config.add_predicate 'between',
    arel_predicate: 'between',
    formatter: proc { |v| Range.new(*v.split('..').map{ |s| DateTime.parse(s) }) },
    validator: proc { |v| v.present? },
    type: :string
end

In a model or view model or helper or else, define the options for the select:

# app/helpers/rooms_helper.rb
module RoomsHelper
  def rooms_search_ranges
    now = Time.current
    next_month = 1.month.from_now
    {
      "This month" => now.beginning_of_month..now.end_of_month,
      "Next month" => next_month.beginning_of_month..next_month.end_of_month
    }
  end
end

And in your form, assuming your model has an booked_at attribute:

<%= search_form_for @search, url: guest_search_rooms_path, html: {:method =>:post} do |f| %>

  <%= f.select :booked_at_between, rooms_search_ranges %>

  <%= f.submit "search" %>
<% end %>
Backtrack answered 4/6, 2021 at 13:22 Comment(1)
The add_predicate approach is definitely the most correct one. I just followed your approach and it worked perfectly for me. thanksSiderolite
L
1

In my case, I did like this:

Just pass a single date, and it will search from beginning `til end of that date.

initializers/ransack.rb

Ransack.configure do |config|
  config.add_predicate 'between_begin_and_end',
                   arel_predicate: 'between_begin_and_end',
                   formatter: proc { |v| v.to_date },
                   validator: proc { |v| v.present? },
                   type: :string
end

module Arel
  module Predications
    def between_begin_and_end date
      gteq(date.to_date.beginning_of_day).and(lt(date.end_of_day))
    end
  end
end

view

<%= f.text_field :date_field_here_between_begin_and_end, class: 'datepicker', placeholder: 'yyyy/mm/dd' %>
Leblanc answered 8/5, 2019 at 6:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.