2013-12-20 16 views
0

在我的Ruby on Rails 3应用程序控制器中,我试图在我的编辑视图中使用一个实例变量数组。从表属性中创建与另一个表属性匹配的值的数组

用户表具有user_id和reseller_id。 证书表具有user_id。

我需要从User表中获取用户表和证书表中具有user_id的reseller_id(s)。

这里是我的用户模型:

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 

谢谢

回答

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

请勿将此代码保留在控制器中:-)

+0

控制器为什么不合适? – DDDD

+0

在小型应用程序或原型中,无论如何,但是在具有较长使用寿命的大型应用程序中,保持控制器和AR模型变薄并将所有bissine逻辑移动到另一个层面是一种很好的方式。可能是服务层,可能是域模型层。 – andrykonchin

1

嗯,首先,你不应该巢each块证书内的IDS' each块。你应该建立你的ids数组,然后再循环它。你只得到最后一个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 

更Rubyish和简洁的方式将是以下几点:

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_id(使用&:user_idCertificate.all.map { |cert| cert.user_id }的快捷方式)第二个map函数返回用户的“reseller_id”(如果找到用户)。如果找不到具有该用户名的用户,它将返回nil。最后,compact从新映射的reseller_ids数组中删除所有nil值,仅留下经销商ID。

如果你想这样做,能够以最有效和railsy的方式,最大限度地减少数据库调用,并允许数据库做最繁重的工作,你可能会希望使用联接:

reseller_ids = User.joins(:certificates).all.map(&:reseller_id) 

这会抓住所有具有该用户标识的证书所在的用户。然后它再次利用map将返回的用户映射到一个只包含user.reseller_id的新数组。

Ruby比RDBM系统(比如mysql)在这种类型的过滤方面往往更慢,因此最好尽可能多地将工作委托给数据库。 (注意,这个连接默认将user.id与certificate.user_id进行比较,因此,如果你的用户表中的'主键'被命名为'user_id',那么这是行不通的。为了使它起作用,你应该使用标准的“id”作为主键,或者你需要指定'user_id'是你在用户模型中的主键)

相关问题