将SQL查询转换为ActiveRecord并将其呈现为表

时间:2015-08-03 00:03:30

标签: sql ruby-on-rails ruby postgresql activerecord

我正在尝试在我的模型中翻译原始SQL查询以使用ActiveRecord查询接口。我认为我正确地翻译了查询,但我无法将其转换为数组以进行渲染。

这是我的模特:

class Pgdb < ActiveRecord::Base

  self.abstract_class = true
  self.table_name = 'test'

  if Rails.env.development?
    establish_connection :pg_development
  end

  def self.getInfo(name)
    get = Pgdb.where(city: "New York")
    get_a = get.to_a
    get_a
  end
end

我能够呈现的原始SQL查询是:

get = connection.query("SELECT * FROM test WHERE city = "New York")

如上面的代码所示,我正在访问外部PostgreSQL数据库并试图使用#to_a将ActiveRecord对象转换为数组,但这不起作用。当我尝试在我的视图中渲染它时:

<% @info.each do |row| %>
  <tr>
    <% row.each do |element| %>
      <td><%= element %></td>
    <% end %>
  </tr>
<% end %>

我收到错误:undefined method 'each' for #<Pgdb:0x007fd37af79040>。我尝试在代码中不同位置的对象上使用to_a,但没有任何效果。

控制器

def index
end

def new
  @thing = Thing.new
end

def create
  @info = Pgdb.getInfo(@thing.something)
  render :index
end

2 个答案:

答案 0 :(得分:2)

您收到undefined method 'each'实例的错误Pgdb,因为您的代码正在尝试迭代此行中实例的数据属性:

<% row.each do |element| %>

ActiveRecord实例不是您可以迭代的属性集合。相反,它们是响应为其属性命名的消息的对象。换句话说,你可以这样做:

p = Pgdb.first
p.city # because the underlying table has a `city` attribute

但你不能这样做:

p.each { |attribute| puts attribute }

但是,ActiveRecord为这件事提供了attributes访问器。 attributes方法返回一个哈希值,您可以使用each方法迭代该哈希值。因此,可以执行此操作:

p.attributes.each { |key, value| puts "#{key}: #{value}" }

在您的视图中,您可以使用以下内容替换内部循环:

<% row.attributes.each do |key, value| %>
  <td><%= "#{key}: #{value}" %></td>
<% end %>

这应该为您的Pgdb实例提供属性。

顺便说一句,没有必要将where的结果投射到Array中的Pgdb::getInfowhere查询会返回ActiveRecord::Relation个对象,该对象会响应each以及Enumerablemap等其他select个消息,类似于阵列。在您的代码中,您成功地遍历

中的结果集
<% @info.each do |row| %>

无论您是否在to_a中使用getInfo,这都会有效。 将结果集转换为数组是有充分理由的。例如,ActiveRecord::Relation对象具有其他功能,例如作用域,您可能经常需要使用它。

希望有所帮助。快乐的编码!

答案 1 :(得分:1)

将rails连接到外部数据库的正确方法是使用config/database.yml文件:

# SQLite version 3.x
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
#
defaults: &defaults
  adapter: postgresql
  encoding: utf8
  template: template0

# used for test & development
local:
  host: localhost
  username: j_random_user # change this!
  password: p4ssword # change this!

development:
  <<: *defaults
  <<: *local
  database: my_app_development

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *defaults
  <<: *local
  database: my_app_test

production:
  <<: *defaults
  host: "my_app_something.rds.amazonaws.com" # change this!
  username: my_amazon_db_user # change this!
  password: my_amazon_user # change this!
  reconnect: true
  port: 3306

您可能希望使用本地postgres数据库进行开发,并使用pgbackup镜像生产数据库。

但是你的主要问题是,在创建rails应用程序时,你几乎都做错了。这看起来像一个PHP示例,其中一些无能的灵魂正在重新发明第1000次数据库管理器。

所以这是一个快速的Rails MVC&amp; ActiveRecord速成课程:

模型反映域中的对象。假设我们有一个宠物店应用程序。

我们当然需要宠物模型:

$ rails g model Pet name:string
$ rake db:migrate

这会在数据库中创建一个pets表和一个Pet类。请注意,表名是复数,模型名称是单数。

# app/models/pet.rb
class Pet < ActiveRecord::Base

end 

然后我们可以通过以下方式访问宠物:

Pet.all
Pet.find(1) # find pet where id is 1
# ... etc

我们可以通过以下方式制作宠物:

pet = Pet.create(name: "Spot")

大多数basic rails tutorials都涵盖了所有这些内容。

没有型号的连接。

ActiveRecord::Base.establish_connection
con = ActiveRecord::Base.connection
res = con.execute('SELECT * FROM foo')

虽然如果你实际上没有使用每个表的模型并且稍微遵循MVC约定,那么使用ActiveRecord并没有多大意义。这是可能的,但它根本没有给你带来任何好处。

同样地做没有MVC的Rails是可行的,但重点是什么?

使用旧数据库

让我们假设你有一个遗留数据库,但是有些人虽然使用了匈牙利应用程序数据库专栏(耸肩),却很酷:

persons:
  intPersonID: Integer, Autoincrement, Primary Key 

并且您希望将其映射到Rails模型

 class User < ActiveRecord::Base
   self.table_name 'persons'
   self.primary_key 'intPersonID'
 end

或者在你的情况下:

class Test < ActiveRecord::Base
  self.table_name 'test' # since it's not "tests"
end

Test.where(city: "New York")