Rails – 给定一组用户 – 如何获得电子邮件的输出?

我有以下内容:

@users = User.all 

用户有几个字段,包括电子邮件

我希望能够获得所有@users电子邮件的列表。

我试过了:

 @users.email.all but that errors w undefined 

想法? 谢谢

(按流行需求,发布作为真实答案)

我不喜欢fl00r的解决方案是它在数据库中为每个记录实例化一个新的User对象; 这只是不规模。 这对于一个只有10封电子邮件的表来说非常棒,但是一旦你开始涉及成千上万,你就会遇到问题,主要是Ruby的内存消耗。

通过在模型上使用connection.select_values以及一点ARel优点,可以解决这个小问题:

 User.connection.select_values(User.select("email").to_sql) 

这将为您提供数据库中电子邮件地址的直接字符串。 没有对用户对象User.select("email")并且比直接的User.select("email")查询更好地扩展,但我不会说它是“最佳规模”。 可能有更好的方法来做到这一点,我还没有意识到。

重点是: String对象将使用比User对象更少的内存,因此您可以拥有更多内存。 它也是一个更快的查询,并没有很长的路要走(运行查询,然后映射值)。 哦, map也需要更长的时间。

如果您使用的是Rails 2.3 …

然后你必须手动构建SQL,我很遗憾地说。

 User.connection.select_values("SELECT email FROM users") 

只是提供了Rails 3提供的帮助程序的另一个示例。

 User.select(:email).map(&:email) 

我仍然发现connection.select_values是一个有效的方法来解决这个问题,但我最近发现了一个内置在Rails中的默认AR方法,可以为你做这个: pluck

在您的示例中,您需要执行的所有操作都是:

 User.pluck(:email) 

select_values方法在极大的数据集上可以更快,但那是因为它没有对返回的值进行类型转换。 例如,布尔值将返回它们在数据库中的存储方式(如1和0),而不是真的| 假。

pluck方法适用于ARel,因此您可以菊花链式连接:

 User.order('created_at desc').limit(5).pluck(:email) 

只需使用:

 User.select("email") 

虽然我经常访问SO,但我今天才注册。 不幸的是,这意味着我没有足够的声誉来评论其他人的答案。

回顾Ryan上面的答案,你可以扩展ActiveRecord :: Base来创建一个方法,允许你以更干净的方式在整个代码中使用它。

在config / initializers中创建一个文件(例如,config / initializers / active_record.rb):

 class ActiveRecord::Base def self.selected_to_array connection.select_values(self.scoped) end end 

然后,您可以在ARel声明的末尾链接此方法:

 User.select('email').selected_to_array User.select('email').where('id > ?', 5).limit(4).selected_to_array 

使用它来获取所有电子邮件的数组:

 @users.collect { |user| user.email } # => ["test@example.com", "test2@example.com", ...] 

或简写版本:

 @users.collect(&:email) 

您应该避免使用User.all.map(&:email)因为它会创建大量消耗大量内存的ActiveRecord对象,其中很大一部分将不会被Ruby的垃圾收集器收集。 它也是CPU密集型的。

如果您只想从数据库中只收集一些属性而不牺牲性能,高内存使用率和CPU周期,请考虑使用Valium。

https://github.com/ernie/valium

以下是获取数据库中所有用户的所有电子邮件的示例。

 User.all[:email] 

或仅适用于订阅或其他任何用户。

 User.where(:subscribed => true)[:email].each do |email| puts "Do something with #{email}" end 

出于上述原因,使用User.all.map(&:email)被认为是不好的做法。