How to order string columns differently - ruby-on-rails

I have a has_many association like this:
has_many :respostas_matriz_alternativas, :class_name => 'RespostaMatrizAlternativa',
:order => 'respostas_matriz.codigo asc',
:include => :resposta_matriz
Well the fragment that matters is the "order". Codigo is a varchar column wich will contain in most cases numeric values. To show this data I need to order it by code, but when I have only numbers the order becomes awkward, something like:
1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, ...
What do you suggest for me to solve it?
Thanks.

I don't know that there's much you can do if the column will contain a mix of strings and numbers, but if the column will always be numeric you could use something like:
:order => 'cast(respostas_matriz.codigo as unsigned) asc'

The accepted answer works for SQLite but not PostgreSQL, I had to use one of the built in types to achieve the same result with different databases:
order: 'cast(respostas_matriz.codigo as integer) asc'

I'm kind of just a beginner with Ruby, but could you use something like the following to split the string into an array of smaller strings, then convert each string to an integer.
I don't have my rubydoc in front of me, but something like
:order => 'respostas_matriz.codigo.split.map {|s| s.to_i}'

Related

Thinking sphinx results based on model preference

I have two models: 'A' and 'B', and want to search objects from both of them using Thinking sphinx, but I want all results of model 'A' first and then 'B'. How can I do that?
I pass the following options to sphinx query
{:match_mode=>:extended, :sort_mode=>:extended, :star=>true, :order=>"#relevance DESC", :ignore_errors=>true, :populate=>true, :per_page=>10, :retry_stale=>true, :classes => [A,B]}
And then get search results using:
ThinkingSphinx.search "*xy*", options
But it gives results in mixed ordering, whereas I need all 'A' objects first. How can I do that?
The easiest way is to add an attribute to both models' indices:
has "1", :as => :sort_order, :type => :integer
The number within the string should be different per model. And then your :order argument becomes:
:order => 'sort_order ASC, #relevance DESC'

How do I group these objects into a hash?

I have an event modal, which has a datetime field titled scheduled_time. I need to create a hash that has a day name in a certain format ('mon', 'tue' etc) as the key, and the count of events that take place on that day as the value. How can I do this?
{
'mon' => 2,
'tue' => 4,
'wed' => 3,
'thu' => 5,
'fri' => 12,
'sat' => 11,
'sun' => 7,
}
I'm using Rails 3.2.0 and Ruby 1.9.2
The easiest would be to use count with a :group option:
h = Model.count(:group => %q{to_char(scheduled_time, 'dy')})
The specific function that you'd GROUP BY would, as usual, depend on the database; the to_char approach above would work with PostgreSQL, with MySQL you could use date_format and lower:
h = Model.count(:group => %q{lower(date_format(scheduled_time, '%a'))})
For SQLite you'd probably use strftime with a %w format and then convert the numbers to strings by hand.
Note that using Model.count(:group => ...) will give you a Hash with holes in it: if there aren't any entries in the table for that day then the Hash won't have a key for it. If you really want seven keys all the time then create a Hash with zeros:
h = { 'mon' => 0, 'tue' => 0, ... }
and then merge the count results into it:
h.merge!(Model.count(:group => ...))

Issue with Rails 2.3.5 Active Record Conditions for IN

I am having a issue using active record conditions in rails 2 with postgres. My problem is when ever I try to use this query (I am using geokit, but that is not the issue)
Table.all(:conditions => ["id IN (?)", id_array.join(",")], :origin => origin, :within => 20)
I get this problem:
ActiveRecord::StatementInvalid: PG::Error: ERROR: invalid input syntax for integer: "21,28"
LINE X: ...OM "tables" WHERE (((id IN (E'21,28...
Why is it putting the "E'" in there and how to I get rid of it?
With id_array.join(","), you pass a single string to the function. As all strings get escaped and surrounded by single quotes when put into the generated SQL query, you naturally get the SQL error, as in this IN statement you can only use comma-separated integers.
The simple solution is to directly pass an array to the function. ActiveRecord then creates the correct values in SQL on its own. You can use it like this:
Table.all(:conditions => ["id IN (?)", id_array], :origin => origin, :within => 20)
Alternatively, you could use this even more ruby-like syntax which produces the exact same SQL query:
Table.all(:conditions => {:id => id_array}, :origin => origin, :within => 20)
You have already been directed to a different path. But to answer your question:
Why is it putting the "E'" in there ...
That is the escape string syntax of PostgreSQL. The default behaviour of PostgreSQL has changed with version 9.1, backslash-escapes are no longer interpreted, unless there is an E in front of the opening single quote. The new behaviour reflects the SQL standard.
'one backslash: \' -- backslash has no special meaning in Postgres 9.1
E'one backslash: \\' -- must use E'' syntax to interpret escape sequences
Some clients play it safe and put the E in front of every string literal to get the same behaviour regardless of the PostgreSQL version or the setting of standard_conforming_strings in particular. Others ask the server about the setting and adapt the syntax accordingly. Either way, it is just a waste of (very few) CPU cycles to put an E in front of a string literal that doesn't contain a backslash.
I dont think u need to join the values. even in Rails 2. That been said, try this out:
Table.all(:conditions => ["id IN (?)", id_array], :origin => origin, :within => 20)
Try this instead:
Table.all(:conditions => ["id IN (#{id_array.join(",")})"], :origin => origin, :within => 20
I had the same issue with mysql trying to run count() function and syntax i used to fix it was
Issue.all(:conditions => "status_id IN (5, 15, 19, 21, 25)").count

Using :order and :limit options - Ruby On Rails

Is there any way I can use the :limit and :order options in the find method. I'm trying to sort activities by descending order, such that the newest activities are shown. However, when I try to use the (:all, :limit => 5, :order=> 'Date desc) I get an error. I need to limit to only 5 records, and when I disregard the order option, it works but not what I need...
Thanks
I think you missed a quote in your example.
Model.find(:all, :limit => 5, :order=> 'created_at desc')
Make sure that a date column exists in your table.
Is your date column actually called date? First, I would change that, date is the name of a function in most databases, that could be the cause of the error you are seeing. Rails uses created_at, updated_at, etc, so following that naming scheme will make your code more readable to future maintainers.
You could try to quote the column name in back-ticks:
:order => "`date` desc"

How can I count the number of records that have a unique value in a particular field in ROR?

I have a record set that includes a date field, and want to determine how many unique dates are represented in the record set.
Something like:
Record.find(:all).date.unique.count
but of course, that doesn't seem to work.
This has changed slightly in rails 4 and above :distinct => true is now deprecated. Use:
Record.distinct.count('date')
Or if you want the date and the number:
Record.group(:date).distinct.count(:date)
What you're going for is the following SQL:
SELECT COUNT(DISTINCT date) FROM records
ActiveRecord has this built in:
Record.count('date', :distinct => true)
Outside of SQL:
Record.find(:all).group_by(&:date).count
ActiveSupport's Enumerable#group_by is indispensable.
the latest #count on rails source code only accept 1 parameter.
see: http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-count
so I achieved the requirement by
Record.count('DISTINCT date')
Detailing the answer:
Post.create(:user_id => 1, :created_on => '2010-09-29')
Post.create(:user_id => 1, :created_on => '2010-09-29')
Post.create(:user_id => 2, :created_on => '2010-09-29')
Post.create(:user_id => null, :created_on => '2010-09-29')
Post.group(:created_on).count
# => {'2010-09-29' => 4}
Post.group(:created_on).count(:user_id)
# => {'2010-09-29' => 3}
Post.group(:created_on).count(:user_id, :distinct => true) # Rails <= 3
Post.group(:created_on).distinct.count(:user_id) # Rails = 4
# => {'2010-09-29' => 2}
As I mentioned here, in Rails 4, using (...).uniq.count(:user_id) as mentioned in other answers (for this question and elsewhere on SO) will actually lead to an extra DISTINCT being in the query:
SELECT DISTINCT COUNT(DISTINCT user_id) FROM ...
What we actually have to do is use a SQL string ourselves:
(...).count("DISTINCT user_id")
Which gives us:
SELECT COUNT(DISTINCT user_id) FROM ...
Also, make sure you have an index on the field in your db, or else that query will quickly become sloooow.
(It's much better to do this in SQL, otherwise you pull the entire db table into memory just to answer the count.)

Resources