Ruby on Rails Ransack Datetime to date search - ruby-on-rails

Like carvil I have in my model a datetime for created_at although I wanted the "equals" predicate to compare the created_at and a date (like '2012-09-26').
So I added in my model (in order to add casted attributes and take off the old created_at/update_at/deleted_at :
ransacker :created_at do
Arel::Nodes::SqlLiteral.new("date(items.created_at)")
end
ransacker :updated_at do
Arel::Nodes::SqlLiteral.new("date(items.updated_at)")
end
ransacker :deleted_at do
Arel::Nodes::SqlLiteral.new("date(items.deleted_at)")
end
# Hide some attributes for advanced search
UNRANSACKABLE_ATTRIBUTES = ["created_at", "updated_at", "deleted_at"]
def self.ransackable_attributes auth_object = nil
(column_names - UNRANSACKABLE_ATTRIBUTES) + _ransackers.keys
end
But when I confirm the query (created_at equals to '2012-03-24') I have this error:
NoMethodError (undefined method `name' for "date(items.created_at)":Arel::Nodes::SqlLiteral):
Surprisingly, it works with "greater than" and "less than". Only "equals" occurs this error.
I made all of this for all my models and 60% works (the remain 40% occurs this error).
In the console :
irb(main):232:0> Item.search(:created_at_eq => Date.today.to_s).result
(Object doesn't support #inspect)
Thanks for your help
EDIT :
I have a default_scope which makes :
Item(:deleted_at false)
But I don't know why it occurs the error

Refer to second example of Ransack wiki,
in the model:
ransacker :created_at , type: :date do
Arel.sql('date(created_at)')
end
in the view:
<%= f.search_field(
:created_at_date_equals, placeholder: t(:date_format)
) %>
...
<%= sort_link(#search, :created_at, default_order: :desc) %>
config/initializers/ransack.rb
Ransack.configure do |config|
config.add_predicate 'date_equals',
arel_predicate: 'eq',
formatter: proc { |v| v.to_date }
validator: proc { |v| v.present? },
type: :string
end
The new predicate 'date_equals' is added for the date equal search. The ransacker declared with type: :date and get the date from datetime column with Arel

I had some problems with this, and came with this:
ransacker :created_at, type: :date do
Arel.sql('date(created_at)')
end

Please changes Arel::Nodes::SqlLiteral.new('date(column_name)') with Arel.sql('date(column_name)').
Your syntax will be ::
ransacker :created_at do
Arel.sql("date(items.created_at)")
end
ransacker :updated_at do
Arel.sql("date(items.updated_at)")
end
ransacker :deleted_at do
Arel.sql("date(items.deleted_at)")
end
I hove this would be helpful.

Related

Sorting error ActiveRecord::StatementInvalid PG::UndefinedColumn in Rails/Grape app

I want to sort all Campaign by campaign_code in my admin panel, to do so I've created code below in my endpoint and serializer which front will be have in response. The same logic works well for sorting by id or name but it wont worked for sorting of existing campagin_code number.
endpoint
optional :sort, type: Hash do
optional :sort, type: Hash do
optional :total, type: String, values: %w[asc desc]
end
end
get do
scoped_collection = scope_admin_resource(filter(Campaign.all))
admin_serialize paginate(filter(sort(scoped_collection)))
end
serializer
class CampaignSerializer
attributes :id, :total,
attribute :total do |campaign|
campaign.campaign_codes.count
end
end
With that code I've an error:
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column campaigns.total does not exist
There is no such column in campaigns table

ruby check if current date is within date records

Let's say I have a model called Absence that looks something like this
:id => :integer,
:employee_id => :integer,
:start_date => :date,
:end_date => :date
I need to check if an Employee is away today, and return true if they are. Someone is away if they have an absence record that
Has a start date is today or before today,
Has an end date that is either null, or today or ahead of today.
so I need a method on the Employee that is something like
def is_away
?????
end
please help!
I would do something like this:
# add this to absence.rb
def covers_today?
(start_date..end_date).cover?(Date.today)
end
# add this to employee.rb
def away?
absences.any?(&:covers_today?)
end
After doing this just call away? on an employee:
#employee.away?
# => true, if employee has an absense that covers the current date
Assuming that Employee has_many :absences, this should work:
def away?(date = Date.today)
absences.where('start_date <= :date AND (end_date >= :date OR end_date IS NULL)', date: date).exists?
end
You can try this too.
def is_away?
(start_date <= Date.today) and (end_date.nil? or end_date <= Date.today) ? true : false
end

Thinking-Sphinx with ActsAsTaggableOn tags search

I have a Rails app in which I use Thinking-Sphinx for search and ActsAsTaggableOn for tagging. I want to be able to include the currently selected tag in my search query. I have tried the following but not got it to work.
In my controller:
def show
#team_tags = #team.ideas.tag_counts_on(:tags)
if params[:tag]
#ideas = #team.ideas.search(params[:search], :conditions => { tags: "tag" })
else
#ideas = #team.ideas.search(params[:search])
end
end
My index for my Idea model:
ThinkingSphinx::Index.define :idea, :with => :real_time do
[...]
indexes tags.name, :as => :tags
has user_id, type: :integer
has team_id, type: :integer
[...]
end
This gives me he following error:
ActionView::Template::Error (index idea_core: query error: no field 'tags' found in schema
When I have a tag selected my URLs looks like this:
/teams/1/tags/tag
So, what should I do to get Thinking-Sphinx and ActsAsTaggableOn to work together?
What you've got for your field will only work with SQL-backed indices, not real-time indices.
In your case, what you want to do is create a method in your model that returns all the tag names as a single string:
def tag_names
tags.collect(&:name).join(' ')
end
And then you can refer to that in your index definition:
indexes tag_names, :as => :tags
Once you've done that, you'll need to regenerate your Sphinx indices, as you've changed the structure: rake ts:regenerate.

How to make fields on my model not searchable but they should still be available in the _source?

I am using the tire gem for ElasticSearch in Rails.
Ok so I have been battling with this the whole day and this is how far I have got. I would like to make fields on my model not searchable but they should still be available in the _source so I can use them for sorting on the search result.
My mappings:
mapping do
indexes :created_at, :type => 'date', :index => :not_analyzed
indexes :vote_score, :type => 'integer', :index => :not_analyzed
indexes :title
indexes :description
indexes :tags
indexes :answers do
indexes :description
end
end
My to_indexed_json method:
def to_indexed_json
{
vote_score: vote_score,
created_at: created_at,
title: title,
description: description,
tags: tags,
answers: answers.map{|answer| answer.description}
}.to_json
end
My Search query:
def self.search(term='', order_by, page: 1)
tire.search(page: page, per_page: PAGE_SIZE, load: true) do
query { term.present? ? string(term) : all }
sort {
by case order_by
when LAST_POSTED then {created_at: 'desc'}
else {vote_score: 'desc', created_at: 'desc'}
end
}
end
end
The only issue I am battling with now is how do I make vote_score and created_at field not searchable but still manage to use them for sorting when I'm searching.
I tried indexes :created_at, :type => 'date', :index => :no but that did not work.
If I understand you, you are not specifying a field when you send your search query to elasticsearch. This means it will be executed agains the _all field. This is a "special" field that makes elasticsearch a little easier to get using quickly. By default all fields are indexed twice, once in their own field, and once in the _all field. (You can even have different mappings/analyzers applied to these two indexings.)
I think setting the field's mappings to "include_in_all": "false" should work for you (remove the "index": "no" part). Now the field will be tokenized (and you can search with it) under it's fieldname, but when directing a search at the _all field it won't affect results (as none of it's tokens are stored in the _all field).
Have a read of the es docs on mappings, scroll down to the parameters for each type
Good luck!
I ended up going with the approach of only matching on the fields I want and that worked. This matches on multiple fields.
tire.search(page: page, per_page: PAGE_SIZE, load: true) do
query { term.present? ? (match [:title, :description, :tags, :answers], term) : all }
sort {
by case order_by
when LAST_POSTED then {created_at: 'desc'}
else {vote_score: 'desc', created_at: 'desc'}
end
}
end

Grouping results and summarizing a field in one query with Mongoid?

I'm trying to execute a more or less advanced query with Mongoid that basically gets metrics for a date range, groups them by day and then summarizes the values for each day, it should also tell me how many entries there are for each day.
I highly doubt this can be done with the active record part of Mongoid, but I don't know how to execute queries on the mongo driver directly.
My model:
class Metric
include Mongoid::Document
field :id_session, :type => Integer
field :metric, :type => Integer
field :value, :type => Integer
field :date, :type => Date
field :time, :type => Time
validates_numericality_of :value
validates_presence_of :id_session, :metric, :value
before_create :set_date
def set_date
self.time = Time.now
self.date = Date.now
end
end
I've been able to get the results grouped by date simply by using Metric.distinct(:date), but I don't know how to do a sum and count of those results as I can't use that method on the results.
Any ideas? I prefer to stay within the Mongoid active record methods but if anyone knows how I can execute queries directly on the MongoDB driver that would help too.
Thanks!
Managed to get it working
result = Metric.collection.group(
['date'] , nil, {:count => 0, :value => 0}, "function(x, y) { y.count++; y.value += x.value }"
)
Credits go to the answer on this page

Resources