我遇到的问题应该很容易,但我不知道我做错了什么。我只是尝试执行一个返回单个字段的查询,而不是Rails 3中的完整记录。
模型方法
def self.find_user_username(user_id)
user_name = User.select("user_name").where(user_id)
return user_name
end
我正盯着Rails指南(http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields) 它只是说(其中viewable_by,locked = fields):
Client.select("viewable_by, locked")
我试过翻转选择,就像这样:
User.select("user_name").where(user_id) - AND -
User.where(user_id).select("user_name")
但是没有工作。事实上,我甚至尝试过:
user_name = User.select("yoda").where(user_id)
我没有收到错误。当我查看视图时,我在哪里:
Friend.find_user_username(friend.user_id)
我只是不断获取哈希:ActiveRecord :: Relation:0x2f4942f0
答案 0 :(得分:22)
答案 1 :(得分:1)
您需要添加.first
以强制查询返回记录,因为where
仅返回activerecord关系。
1.9.3p0 :048 > user = User.select('first_name').where('id = 1').first
User Load (0.6ms) SELECT first_name FROM `users` WHERE (id = 1) LIMIT 1
+------------+
| first_name |
+------------+
| Johnny |
+------------+
1 row in set
1.9.3p0 :049 > user.first_name
=> "Johnny"
答案 2 :(得分:1)
您的问题不是select
,而是where
。您现在的状况基本上是WHERE #{user_id}
。如果您在Rails控制台上执行此操作,您会看到如下内容:
1.9.2p290 :003 > puts User.select('user_name').where(1).to_sql
SELECT user_name FROM "users" WHERE (1)
您需要将条件作为哈希值传递给where
,并按照其他人的建议获取第一条记录:
User.select('user_name').where(:id => user_id).first
答案 3 :(得分:1)
很多人提到.pluck
。它确实有一个警告,它返回用于找到记录的列的数组。
如果列是唯一的,例如id
,那么这不是问题,数据库将使用或不使用limit(1)
向Active Record发送相同的内容,即1记录1列。使用它是没有用的,并且最肯定的是它将被数据库查询优化器丢弃。
但是,如果列不是唯一的,那么实际上这可能是一个更大的问题。 AR执行数据库查询后,将调用first
,并返回[0]
从数据库中获得的结果。 limit
,之前被调用,并作为查询的一部分发送到数据库。
请考虑以下表格和设置:
> Log
=> Log(id: integer, user_id, integer, event_type: integer, timestamp: datetime)
> user_newest_logs = Log.where(user_id: 1).order(timestamp: :desc)
现在,让我们获取user_id = 1的最后一个事件日期时间:
1)这是最好的方法
> user_newest_logs.limit(1).pluck(:timestamp).first
SELECT timestamp FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC LIMIT 1
=> Fri, 09 Aug 2019 23:00:00 UTC +00:00
2)都从数据库中检索相同的数据
> user_newest_logs.first
SELECT * FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC LIMIT 1
=> #<Log:0x00111111>
id: 920821839,
user_id: 1,
event_type: 1,
timestamp: Fri, 09 Aug 2019 23:00:00 UTC +00:00
> user_newest_logs.first.timestamp
SELECT * FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC LIMIT 1
=> Fri, 09 Aug 2019 23:00:00 UTC +00:00
3)都从数据库中检索相同的数据
> user_newest_logs.pluck(:timestamp)
SELECT timestamp FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC
=> [Fri, 09 Aug 2019 23:00:00 UTC +00:00,
Fri, 09 Aug 2019 22:00:00 UTC +00:00,
Fri, 09 Aug 2019 21:00:00 UTC +00:00,
Fri, 09 Aug 2019 20:00:00 UTC +00:00,
...
]
> user_newest_logs.pluck(:timestamp).first
SELECT timestamp FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC
=> Fri, 09 Aug 2019 23:00:00 UTC +00:00
> user_newest_logs.pluck(:timestamp).count # NOT PRETTY HUH?!
=> 1523
因此,如果您这样做,pluck(:column).first
实际上可能比仅仅find_by.column
更糟糕。
答案 4 :(得分:0)
看起来虽然没有返回每个字段,但查询确实返回了一个对象而不是特定字段的值。您可以将return user_name
的返回值更改为return user_name.user_name
。
def self.find_user_username(user_id)
user_name = User.select("user_name").where(user_id)
return user_name
end
或者您可能会看到User.user_name.where(user_id).first
是否能满足您的需求。
答案 5 :(得分:0)
顺便说一句,如果问题是关于ActiveRecord :: Relation它是由where和select返回的对象的类,正如你在阅读的Rails指南中所说的那样。 它被优化为在几个方法之间链接,并且在实际访问关联的元素时获得模型对象(因此在幕后SQL查询只运行一次)。这意味着你得到了Relation对象,因为你只需返回它。
在这种情况下,最好的解决方案可能就是使用find并访问user_name属性
def self.find_user_username(user_id)
User.find(user_id).user_name
end
查询将从数据库获取所有其他属性,但您只返回用户名。
答案 6 :(得分:0)
有一种名为'pluck'的方法,请参考http://apidock.com/rails/ActiveRecord/Calculations/pluck