Postgres: Error using GROUP BY and ORDER (on heroku) - ruby

I am trying to solve my heroku problem which it seems to have problem of
We're sorry, but something went wrong.
We've been notified about this issue and we'll take a look at it shortly.
Is there any mistake I have and how to overcome it?
How can I interpret these Heroku logs?
ActionView::Template::Error (PGError: ERROR: column "microposts.created_at" must appear in the GROUP BY clause or be used in an aggregate function
2011-11-14T17:33:07+00:00 app[web.1]: : SELECT category FROM "microposts" GROUP BY category ORDER BY microposts.created_at DESC):
2011-11-14T17:33:07+00:00 app[web.1]: 2: <% #categories= Micropost.select("category").group("category")%>
2011-11-14T17:33:07+00:00 app[web.1]: 3: <% unless #categories.nil? %>
2011-11-14T17:33:07+00:00 app[web.1]: 4:
2011-11-14T17:33:07+00:00 app[web.1]: 5: <ul><% #categories.each do |category| %>
2011-11-14T17:33:07+00:00 app[web.1]: 6: <li><%= link_to category.category, :controller =>"microposts", :category => category.category, :method => 'category_list' %></li>
2011-11-14T17:33:07+00:00 app[web.1]: 7: <% end %>
2011-11-14T17:33:07+00:00 app[web.1]: 8: </ul>
micropost model (New added)
class Micropost < ActiveRecord::Base
belongs_to :users
default_scope :order => 'microposts.created_at DESC'
attr_accessible :title,:content,:category
validates :user_id, :presence => true
validates :title, :presence => true,
:length => {:maximum =>500}
validates :content, :presence => true,
:length => {:maximum =>3000}
validates :category, :presence => true
end

Your immediate problem is that you're producing invalid SQL for PostgreSQL:
SELECT category FROM "microposts" GROUP BY category ORDER BY microposts.created_at DESC
Your ORDER BY doesn't match the rest of your query. You can't use a column in a grouped query unless that column is also grouped or if the column appears in an aggregate function, that's what the error message means. The reason is that PostgreSQL won't know which row's created_at to use when a group of rows are combined by the GROUP BY clause; some databases will just silently pick a row on their own, PostgreSQL prefers to be strict and wants you to remove the ambiguity yourself.
Try specifying the order yourself:
#categories = Micropost.select("category").group("category").order("category")
Another option is to use DISTINCT instead of GROUP BY to avoid duplicates:
#categories = Micropost.select('DISTINCT(category)')
BTW, you really shouldn't be doing that sort thing in a view, you might want to move that to your controller.
Your real problem is that you're developing on top of one database while deploying on another. I'd recommend that you switch your development environment to PostgreSQL 8.3 (if you're deploying to a Heroku shared database) or PostgreSQL 9.0 (if you're deploying to a dedicated database).

Have you been developing your app on MySQL? Heroku doesn't include MySQL. It uses postgreSQL. Look at this question here - PostgreSQL GROUP BY different from MySQL?
I quote -
MySQL's totally non standards compliant GROUP BY can be emulated by Postgres' DISTINCT ON. Consider this :
mysql :
SELECT a,b,c,d,e FROM table GROUP BY a
This delivers 1 row per value of a (which one, you don't really know). Well actually you can guess, because MySQL doesn't know about hash aggregates, so it will probably use a sort... but it will only sort on a, so the order of the rows could be random. Unless it uses a multicolumn index instead of sorting. Well, anyway, it's not specified by the query.
postgres :
SELECT DISTINCT ON (a) a,b,c,d,e FROM table ORDER BY a,b,c
This delivers 1 row per value of a, this row will be the first one in the sort according to the ORDER BY specified by the query. Simple.

Related

Ruby HAML add If Condition to each.do

I have a haml ruby site that is pulling data from Salesforce. What I need to be able to do is to set an if condition based on the productCode listed in SF. The each.do establishes a loop to display the related data for each record in the loop.
The client would like productFamily specific pages. So I need to loop through all items with a product code of GEA for one page and GFE for another page.
.row
.col-xs-12
- #price_book.where(:productCode => GEA).each do |prod|
.row
.panel.panel-default
.panel-body
.col-xs-4
%img{:src => "#{prod.productUrl}", :height => "200", :width => "150"}
When I attempt to run this I get the following error:
ActionView::Template::Error (uninitialized constant ActionView::CompiledTemplates::GEA):
7:
8: .row
9: .col-xs-12
10: - #price_book.where(:productcode => GEA).each do |prod|
11:
12: .row
13: .panel.panel-default
Thank You for your assistance, I am new to Ruby and modifying another Developers code.
If #price_book is an ActiveRecord::Relation object, not just array of YourModel and productcode is String column of YourModel then you can call additional ActiveRecord methods like where:
#price_book.where(:productcode => 'GEA')
If GEA, GFE are not variables defined in view then values should be in quotes (double quotes) 'GEA', "GFE".
You can put
= #price_book.inspect
in your template and get more info about it. Tell us what kind of object is #price_book and we will give you advice.
I was able to apply the if filter logic to the loop with the following modification to the code
- #price_book.select{ |prod| prod[:productCode] == "GEA" }.each do |prod|
This returned only items from the price book with a product code of GEA

Sequel: How to use 'order by' in a view with tinytds

I need to create a view with an order by-clause with sequel, tinytds and MSSQL
When I do so, I get the error
TinyTds::Error: The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified. (Sequel::DatabaseError)
My examplecode:
require 'sequel'
DB = Sequel.tinytds(
:host => 'server',
:database=> 'DB',
)
#Remove data from previous test
DB.drop_table(:testtab1) if DB.table_exists?(:testtab1)
DB.drop_view(:v_testtab1) rescue Sequel::DatabaseError
DB.drop_view(:v_testtab2) rescue Sequel::DatabaseError
DB.create_table(:testtab1){
primary_key :id
field :a, :type => :nvarchar, :size => 10
field :b, :type => :nvarchar, :size => 10
}
#Here the error comes up
#"SELECT * FROM `testtab1` ORDER BY `b`"
DB.create_view(:v_testtab1, DB[:testtab1].order_by(:b))
See solution on SQL-side is easy. Instead of the
SELECT * FROM `testtab1` ORDER BY `b`
I need a
SELECT top 100 percent * FROM `testtab1` ORDER BY `b`
I found a solution with an additional obsolete column (without the column dummy I get an invalid comma):
sel = DB[:testtab1].select(Sequel.lit('top 100 percent "" as dummy'), *DB[:testtab1].columns)
#SELECT top 100 percent "" as dummy, [ID], [A], [B] FROM [TESTTAB1]
DB.create_view(:v_testtab2, sel.order_by(:b))
A similar solution can be made with limit:
#Take a big number to get all entries.
#DB[:testtab1].count would take the number in moment of view creation, not usage.
sel = DB[:testtab1].limit(99999999999)
#SELECT TOP (99999999999) * FROM [TESTTAB1]
DB.create_view(:v_testtab3, sel.order_by(:b))
But I'm looking for a nicer solution. Is there another better possibility?
If it is important:
Ruby 2.1
Sequel 4.19
tiny_tds-0.6.2-x64-mingw32
MSSQL 10.50.2500.0, 64 bit

How can I avoid duplication in a join query using Sequel with Postgres on Sinatra?

I want to do a simple join. I have two tables: "candidates" and "notes".
Not all candidates have notes written about them, some candidates have more than one note written about them. The linking fields are id in the candidates table and candidate_id in the notes table. The query is:
people = candidates.where(:industry => industry).where("country = ?", country).left_outer_join(:notes, :candidate_id => :id).order(Sequel.desc(:id)).map do |row|
{
:id => row[:id],
:first => row[:first],
:last => row[:last],
:designation => row[:designation],
:company => row[:company],
:email => row[:email],
:remarks => row[:remarks],
:note => row[:note]
}
end
It works kind of fine and gets all the specified candidates from the candidates table and the notes from the notes table but where there is more than one note it repeats the name of the candidate. In the resulting list, person "abc" appears twice or three times depending on the number of notes associated with that person.
I am not actually printing the notes in the HTML result just a "tick" if that person has notes and "--" if no notes.
I want the person's name to appear only once. I have tried adding distinct in every conceivable place in the query but it made no difference.
Any ideas?
In order for distinct to work, you need to make sure you are only selecting columns that you want to be distinct on. You could try adding this to the query
.select(:candidates__id, :first, :last, :designation, :company, :email, :remarks, Sequel.as({:notes=>nil}).as(:notes)).distinct
But you may be better off using a subselect instead of a join to check for the existence of notes (assuming you are using a decent database):
candidates.where(:industry => industry, :country=>country).select_append(Sequel.as({:id=>DB[:notes].select(:candidate_id)}, :note)).order(Sequel.desc(:id)).map do |row|
{ :id => row[:id], :first => row[:first], :last => row[:last], :designation => row[:designation], :company => row[:company], :email => row[:email], :remarks => row[:remarks], :note => row[:note] }
end

ActiveRecord, find by polymorphic attribute

Having this:
class Event < ActiveRecord::Base
belongs_to :historizable, :polymorphic => true
end
user = User.create!
I can:
Event.create!(:historizable => user)
But I can't:
Event.where(:historizable => user)
# Mysql2::Error: Unknown column 'events.historizable' in 'where clause'
I have to do this instead:
Event.where(:historizable_id => user.id, :historizable_type => user.class.name)
Update
Code that reproduces the issue: https://gist.github.com/fguillen/4732177#file-polymorphic_where_test-rb
This has been implemented in Rails master and will be available in
Rails 4. Thanks.
– #carlosantoniodasilva
I do this:
user.events
This is a proper AR query, you can chain it with other scopes and stuff:
user.events.where(<your event conditions here>)
EDIT: AFAIK the other way around you must specify both fields (makes sense: you could have a user with id 4 and another thing with events, like a Party, also with id 4).
EDIT2: Regarding "Why does create work and where doesn't": create is more highlevel than where, because the former deals with "a complete model", while the latter manages things at the database table level.
ActiveRecord's create (AFAIK) uses a combination of new + update_param somewhere down the line.
update_param uses your model's xxxx= methods for assigning each individual property.
In your example, historizable= is a method built by the belongs_to expression. Since the belongs_to "knows" that it's polymorphic, it can deal with the type and id.
On the other hand, when you pass a hash to the where clause, the parameters there only refer to database fields. Rails provides scopes for "higher level" access:
class Event < ActiveRecord::Base
...
scope :by_historizable, lambda { |h| where(:historizable_id => h.id, :historizable_type => h.class.name) }
end
...
Event.by_historizable(user).where(<your other queries here>)
I've heard that this might change in Rails 4, and where might be more "intelligent". But I have not checked yet.
Try:
Event.joins(:historizable).where(:historizable => {:historizable_type => user})

Best practices for status addition in Rails

I need to add status for an object, and need a hint about the Rails way to do this. Somewhere I've seen status was added into the model, but already lost where it was.
By status, I mean something that tracks about the item state. Like {0: :ORDERED, 1: :CHANGED, 2: :SHIPPED, 3: :ARCHIVED} for order in store. Looks like it needs id that stored in DB, constant or symbol that I could use in code instead of integer id, and one or two human readable messages for UI
There's a couple simple ways to do this. If the names of the statuses are short, I'd do basically what Samy suggested and store them directly in the model. So, in your migration, you'd do
add_column :orders, :status, :string
Then, in your model, you can use the status method to retrieve the status. You'll want to make sure you only store valid statuses, so you the :inclusion validator something like this:
class Order
validates :status, inclusion: { in: %w(ordered changed shipped archived) },
presence: true
end
If the statuses are longer, you can do something very much like the above with a short name for each status, then add an additional method to give you the full status message
class Order
STATUSES = { 'ordered' => 'Order placed',
'changed' => 'A change has been made to the order',
'shipped' => 'The order has been shipped',
'archived' => 'The order has been archived' }
def self.valid_statuses
STATUSES.keys
end
validates :status, inclusion: { in: valid_statuses },
presence: true
def extended_status
STATUSES[status]
end
end
If the problem has some complexity (f.e: lots of states, the object changes its behavior when changing its state...), you could use the gem StateMachine.
MagicFieldNames might be what you are looking for, it has a discriminator type column that you can use for Single Table Inheritance.
If you want simpler, you can use a status column which value can equal ordered, changed, or shipped. You don't even need to create constants in Rails or such a thing.

Resources