Return a single Rails request field

I have problems with something that should be so simple, but I don't know what I'm doing wrong. I'm just trying to execute a query that returns a single field instead of a full record in Rails 3.

model method

def self.find_user_username(user_id) user_name = User.select("user_name").where(user_id) return user_name end 

I look at the Rails Guide ( http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields ) and it just says (where viewable_by, locked = fields):

 Client.select("viewable_by, locked") 

I tried flip flopping select, for example:

 User.select("user_name").where(user_id) - AND - User.where(user_id).select("user_name") 

but do not work. Actually I even tried:

 user_name = User.select("yoda").where(user_id) 

and I didn’t get an error. When I look at the point of view where I have:

 Friend.find_user_username(friend.user_id) 

I just keep getting the hash: ActiveRecord :: Relation: 0x2f4942f0

+5
source share
7 answers

By the way, if we are talking about ActiveRecord :: Relate to this class of the object returned there, and select, as he said in the Rails Guide, which you are reading. It is optimized for the connection between several methods, and you get the model object when you really get access to the association element (so behind the scenes the SQL query is run only once). This means that you get a Relation object because you are just returning it.

In this case, perhaps the best solution is to simply use find and access the user_name attribute

 def self.find_user_username(user_id) User.find(user_id).user_name end 

The request will receive all other attributes from the database, but you will only return the username.

-one
source
 User.where(:id => user_id).pluck(:user_name).first 

Must do what you are trying to do.

pluck "takes a column name as an argument and returns an array of values ​​of the specified column with the appropriate data type

+22
source

You need to add .first to force the request to return a record, because where returns only the activerecord relation.

 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" 
+1
source

Your problem is not select , but where . Your status is now substantially WHERE #{user_id} . If you did this in the Rails console, you will see something like this:

 1.9.2p290 :003 > puts User.select('user_name').where(1).to_sql SELECT user_name FROM "users" WHERE (1) 

You need to pass the conditions as a hash to where and take the first record, as others suggested:

 User.select('user_name').where(:id => user_id).first 
+1
source

Many people link to .pluck . He has a caution, he returns an array of columns for the found records.

If the column is unique, such as id , this is not a problem, the database will send the same content to Active Record, 1 record 1 column using limit(1) or not. Its use is useless, and most likely it will be rejected by the database query optimizer.

But if the column is not unique, this could be a more serious problem. first is called after AR executes a query on the database, returning [0] results obtained from the database. limit , called earlier and sent to the database as part of the request.

Consider the following table and configuration:

 > Log => Log(id: integer, user_id, integer, event_type: integer, timestamp: datetime) > user_newest_logs = Log.where(user_id: 1).order(timestamp: :desc) 

Now let's get the date time of the last event for user_id = 1:

1) this is the best way

 > 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) both get the same data from the database

 > 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) everyone extracts the same data from the database

 > 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 

So, if you do, pluck(:column).first may actually be worse than just find_by.column .

+1
source

It seems that without returning each field, the query returns an object, not a specific field value. You can change the return of return user_name to 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 

Or you can see if User.user_name.where(user_id).first what you need.

0
source

there is a method called 'pluck' refer http://apidock.com/rails/ActiveRecord/Calculations/pluck

0
source

Source: https://habr.com/ru/post/1399509/


All Articles