移动到Postgresql时排序已损坏

时间:2013-11-10 20:01:50

标签: ruby-on-rails ruby postgresql heroku sqlite

我正在使用SQLite3开发期间将我的应用程序部署到heroku(和n00b一样)。我部署到Heroku,我收到特定页面的错误。我加载Postgresql作为我的开发数据库,​​我注意到由于sort函数我的错误正在发生。这在SQLite3中完全正常,但是在Postgresql中被破坏了。任何人都知道如何更改语法以使用Postgresql?

def index
  @users = User.paginate(:page => params[:page], :per_page => 100).search(params[:search]).find(:all, :order => sort_order('id'))
 end

private
#called to sort the table. taking in case insensitive  
def sort_order(default)
  "LOWER( #{(params[:c] || default.to_s).gsub(/[\s;'\"]/,'')} ) #{params[:d] == 'down' ? 'DESC' : 'ASC'}"
end 

这是我收到的错误

ActiveRecord::StatementInvalid in UsersController#index

PG::UndefinedFunction: ERROR: function lower(integer) does not exist LINE 1: SELECT "users".* FROM "users" ORDER BY LOWER( id ) DESC L... ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. : SELECT "users".* FROM "users" ORDER BY LOWER( id ) DESC LIMIT 100 OFFSET 0

3 个答案:

答案 0 :(得分:0)

Rails已经知道列类型,您可以通过columns_hash访问此信息。 columns_hash将列名称映射到列对象,列对象的type与您在create_table中使用的类型相匹配。例如:

User.columns_hash['id'].type

会给你:integer

User.columns_hash['created_at'].type

会给你:datetime。这使您可以在sort_order

中执行此类操作
def sort_order(default)
  c    = params[:c] || default.to_s
  type = User.columns_hash[c].type
  c    = "lower(#{c})" if(type == :string || type == :text)
  "#{c} #{params[:d] == 'down' ? 'DESC' : 'ASC'}"
end

当然,您应该将params[:c]列入白名单以防万一有人试图将某些令人讨厌的内容放入您的SQL中,但您可以使用User.columns_hash.has_key?

cols = User.columns_hash
c    = (cols.has_key?(params[:c]) ? params[:c] : default).to_s
type = User.columns_hash[c].type
c    = "lower(#{c})" if(type == :string || type == :text)
"#{c} #{params[:d] == 'down' ? 'DESC' : 'ASC'}"

这种事情甚至可以跨数据库移植。

答案 1 :(得分:0)

“ID”是INTEGER类型吗?如果是这样,只需删除LOWER()功能即可。如果没有,您将需要转换为TEXT或VARCHAR。例如。 ORDER BY CAST(id AS TEXT)

答案 2 :(得分:-1)

您可以将值强制转换为文本,但您需要检查postgres或者破解SQLite。

#called to sort the table. taking in case insensitive  
def sort_order(default)
  sort_col = (params[:c] || default.to_s).gsub(/[\s;'\"]/,'')
  sort_col += "::text" if ActiveRecord::Base.connection.class.to_s.match(/PostgreSQLAdapter$/)
  "LOWER( #{sort_col} ) #{params[:d] == 'down' ? 'DESC' : 'ASC'}"
end