在我的Ruby on Rails 3 app控制器中,我试图在我的编辑视图中创建一个实例变量数组。
User表有一个user_id和reseller_id。 Certificate表有一个user_id。
我需要从User表中获取在User表和Certificate表中都有user_id的reseller_id。
这是我的用户模型:
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation, :remember_token, :reseller_id, :validate_code, :validate_url, :validated, :admin, :avatar
belongs_to :reseller
has_one :certificate
end
这是我的证书模型:
class Certificate < ActiveRecord::Base
attr_accessible :attend, :pass, :user_id
validates :user_id, presence: true
end
这是我的控制器,这似乎只存储证书表中的最后一个user_id。
#@train should be reseller.id(s) of all users in Certification table.
@certs = Certificate.all
@certs.each do |user|
@id = []
@id << user.user_id
@id.each do |id|
if User.find(id)
@train = []
@train << User.find(id).reseller_id
end
end
end
谢谢
答案 0 :(得分:1)
首先,您不应将{id} each
块嵌套在each
块内以获取证书。你应该构建你的id数组,然后再循环它。你只得到最后一个user_id的原因是因为“@id”在你的代码当前写入时只会有一个元素。你的“@train”数组也会遇到同样的问题。因为您在迭代器中声明了数组,所以每次迭代都会重新创建它(在其中没有任何内容)。使用现有代码,这应该有效:
@certs = Certificate.all
@ids = []
@certs.each do |user|
@ids << user.user_id
end
@train = []
@ids.each do |id|
if User.find(id)
@train << User.find(id).reseller_id
end
end
更简洁的方式如下:
cert_user_ids = Certificate.all.map(&:user_id)
reseller_ids = cert_user_ids.map { |id| User.find(id).reseller_id rescue nil }.compact
Map是一个可枚举的方法,它返回与第一个数组大小相等的数组。在每次迭代中,无论块内的代码返回“替换”返回的新数组中的该元素。换句话说,它将一个数组的值映射到相同大小的新数组。第一个map函数获取所有证书的user_ids(使用&:user_id
是Certificate.all.map { |cert| cert.user_id }
的快捷方式)如果找到用户,则第二个map函数返回用户的“reseller_id”。如果没有找到具有该id的用户,则返回nil。最后,compact从新映射的reseller_id数组中删除所有nil值,只留下代理商ID。
如果您希望以最有效和最有效的方式执行此操作,最大限度地减少数据库调用并允许数据库执行大部分繁重工作,您可能希望使用连接:
reseller_ids = User.joins(:certificates).all.map(&:reseller_id)
这将抓取具有该用户ID的证书的所有用户。然后它再次利用map将返回的用户映射到一个只包含user.reseller_id的新数组。
Ruby在这种类型的过滤中往往比RDBM系统(如mysql)慢,因此最好尽可能多地将数据委托给数据库。
(请注意,默认情况下,此连接会将user.id与certificate.user_id进行比较。因此,如果您的users表中的'primary key'被命名为'user_id',那么这将无效。为了使其成为工作时,您应该使用标准“id”作为主键,或者您需要指定'user_id'是用户模型中的主键)
答案 1 :(得分:1)
1)正确版本的代码
@certs = Certificate.all
@reseller_id = [] # 1
@certs.each do |user|
id = user.user_id # 2
if u = User.find(id)
@reseller_id << u.reseller_id # 3
end
end
2)Rails方式
像这样的东西
@reseller_id = User.joins(:certificates).select('users.reseller_id').map { |u| u['reseller_id']}
PS
请不要将此代码保留在控制器中: - )