简体   繁体   English

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

[英]Rails - given an array of Users - how to get a output of just emails?

I have the following: 我有以下内容:

@users = User.all

User has several fields including email. 用户有几个字段,包括电子邮件

What I would like to be able to do is get a list of all the @users emails. 我希望能够获得所有@users电子邮件的列表。

I tried: 我试过了:

@users.email.all but that errors w undefined

Ideas? 想法? Thanks 谢谢

(by popular demand, posting as a real answer) (按流行需求,发布作为真实答案)

What I don't like about fl00r's solution is that it instantiates a new User object per record in the DB; 我不喜欢fl00r的解决方案是它在数据库中为每条记录实例化一个新的User对象; which just doesn't scale. 这只是不规模。 It's great for a table with just 10 emails in it, but once you start getting into the thousands you're going to run into problems, mostly with the memory consumption of Ruby. 这对于一个只有10封电子邮件的表来说非常棒,但是一旦你开始涉及成千上万,你就会遇到问题,主要是Ruby的内存消耗。

One can get around this little problem by using connection.select_values on a model, and a little bit of ARel goodness: 通过在模型上使用connection.select_values以及一点ARel优点,可以解决这个小问题:

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

This will give you the straight strings of the email addresses from the database. 这将为您提供数据库中电子邮件地址的直接字符串。 No faffing about with user objects and will scale better than a straight User.select("email") query, but I wouldn't say it's the "best scale". 没有对用户对象User.select("email")并且比直接的User.select("email")查询更好地扩展,但我不会说它是“最佳规模”。 There's probably better ways to do this that I am not aware of yet. 可能有更好的方法来做到这一点,我还没有意识到。

The point is: a String object will use way less memory than a User object and so you can have more of them. 问题的关键是:一个String对象将使用的方式较少的内存比User对象,这样你可以有更多的人。 It's also a quicker query and doesn't go the long way about it (running the query, then mapping the values). 它也是一个更快的查询,并没有很长的路要走(运行查询,然后映射值)。 Oh, and map would also take longer too. 哦, map也需要更长的时间。

If you're using Rails 2.3... 如果您使用的是Rails 2.3 ...

Then you'll have to construct the SQL manually, I'm sorry to say. 然后你必须手动构建SQL,我很遗憾地说。

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

Just provides another example of the helpers that Rails 3 provides. 只是提供了Rails 3提供的帮助程序的另一个示例。

I still find the connection.select_values to be a valid way to go about this, but I recently found a default AR method that's built into Rails that will do this for you: pluck . 我仍然发现connection.select_values是一个有效的方法来解决这个问题,但我最近发现了一个内置在Rails中的默认AR方法,可以为你做这个: pluck

In your example, all that you would need to do is run: 在您的示例中,您需要执行的所有操作都是:

User.pluck(:email)

The select_values approach can be faster on extremely large datasets, but that's because it doesn't typecast the returned values. select_values方法在极大的数据集上可以更快,但那是因为它没有对返回的值进行类型转换。 Eg, boolean values will be returned how they are stored in the database (as 1's and 0's) and not as true | 例如,布尔值将返回它们如何存储在数据库中(如1和0)并且不是真的| false. 假。

The pluck method works with ARel, so you can daisy chain things: pluck方法适用于ARel,因此您可以菊花链式连接:

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

While I visit SO frequently, I only registered today. 虽然我经常访问SO,但我今天才注册。 Unfortunately that means that I don't have enough of a reputation to leave comments on other people's answers. 不幸的是,这意味着我没有足够的声誉来评论其他人的答案。

Piggybacking on Ryan's answer above, you can extend ActiveRecord::Base to create a method that will allow you to use this throughout your code in a cleaner way. 回顾上面Ryan的回答,你可以扩展ActiveRecord :: Base来创建一个方法,允许你以更干净的方式在整个代码中使用它。

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

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

You can then chain this method at the end of your ARel declarations: 然后,您可以在ARel声明的末尾链接此方法:

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

只需使用:

User.select("email")

Use this to get an array of all the e-mails: 使用它来获取所有电子邮件的数组:

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

Or a shorthand version: 或简写版本:

@users.collect(&:email)

You should avoid using User.all.map(&:email) as it will create a lot of ActiveRecord objects which consume large amounts of memory, a good chunk of which will not be collected by Ruby's garbage collector. 您应该避免使用User.all.map(&:email)因为它会创建大量消耗大量内存的ActiveRecord对象,其中很大一部分将不会被Ruby的垃圾收集器收集。 It's also CPU intensive. 它也是CPU密集型的。

If you simply want to collect only a few attributes from your database without sacrificing performance, high memory usage and cpu cycles, consider using Valium. 如果您只想从数据库中只收集一些属性而不牺牲性能,高内存使用率和CPU周期,请考虑使用Valium。

https://github.com/ernie/valium https://github.com/ernie/valium

Here's an example for getting all the emails from all the users in your database. 以下是从数据库中的所有用户获取所有电子邮件的示例。

User.all[:email]

Or only for users that subscribed or whatever. 或仅适用于订阅或其他任何用户。

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

Using User.all.map(&:email) is considered bad practice for the reasons mentioned above. 出于上述原因,使用User.all.map(&:email)被认为是不好的做法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM