ruby hash with database - ruby-on-rails

I am trying to understand this line of code:
#rating = Rating.where(review_id: #review.id, user_id: #current_user.id).first
The line of code comes from a Ruby on Rails app that has a user, review, and rating model. Here is what I understand so far:
#rating is a variable
Rating.where().first is a method
review_id: #review.id + user_id: #current_user.id are parameters- and are an implicit hash key/value pair
How does review_id: #review.id or user_id: #current_user.id work with the database?
Update question: Sorry I'm still confused. How does #review.id or #current_user.id point to anything in the database? I have nothing in my database starting with the # symbol

You have 2 fields: "review_id", "user_id" in table "ratings".
Symbol # - means that is instance variable and it is available not only in the controller
variable structure example:
#current_user = {
id: 1,
name: "Jhon",
last_name: "Wayne"
}
this means that #current_user.id = 1
user_id: #current_user.id
And query search 1 in table ratings field user_id

If you know database SQL queries then
Rating.where(review_id: #review.id, user_id: #current_user.id)
is equivalent to
SELECT * from ratings where review_id = #review.id AND user_id = #current_user.id;
#rating is not just a variable , its a instance variable
Rating.where() will return an array of ratings. and Rating.where().first will return first record of the array

Rating.where provides ActiveRecord::Relation object, which knows about conditions on review_id and user_id. When you call first for the object -- it executes sql query, and appends LIMIT 1 condition.
SELECT ratings.* FROM ratings WHERE ratings.review_id = 11 AND ratings.user_id = 12 LIMIT 1
The ORM converts the response from the database to the ruby object. Which you place in the instance variable #rating, probably in a controller. This variable will be accessible in the view.

When you provide a hash in where clause it means then key of hash is field name and value of that key is value in database

This line selects all the ratings which belong to a review with id #review.id and belong to the currently logged-in user with id #current_user.id.
The SQL version of this will look something like this:
query = "SELECT * FROM ratings WHERE review_id = #{#review.id} AND user_id = #{#current_user.id}"
EDIT: In the hash, every key refers to the column name in the table and the corresponding value is what you are searching for in that column. That value is given by what is stored in the instance variable.

Related

Rails 6 get the difference of the 2 timestamp and assigned to one new field in query

I am working on the rails 6 application with postgresql database, where I have to count to the time of the call.
I have 2 fields in my database one is answered_at(timestamp) and another is end_at(timestamp)
I use the following query, and in that query, I need the difference of (end_at - answered_at) and access in call_duration field
So I can access the call_duration field by attr_accessor but I do not know how to get the difference and set it into the query.
My original query is
#in_app_calls = InAppCall.where("caller_user_id =? OR receiver_user_id =?", chat_user&.first&.id, chat_user&.first&.id)
.group_by(&:call_type) unless chat_user.nil?
following is my database record
<InAppCall id: 1, caller_user_id: 10, receiver_user_id: 61, call_type: "audio", call_answered: true, answered_at: "2020-07-16 04:24:17", end_at: nil, created_at: "2020-07-08 09:58:36", updated_at: "2020-07-16 04:24:17", on_going_updated_at: nil>
I may get nil value in answered_at(timestamp) or end_at(timestamp) field, in that case, I will not consider that record.
Can anyone help me with the query?
An elegant way to do this is to use virtual attributes that ActiveRecord basically creates on the fly for you when you modify the select list. You can do it like so:
user_id = chat_user&.first&.id
#in_app_calls = InAppCall.
select("in_all_calls.*, EXTRACT(EPOCH FROM end_at - answered_at)::int AS call_duration").
where("caller_user_id = :user_id OR receiver_user_id = :user_id", user_id: user_id).
where.not(answered_at: nil, end_at: nil).
group_by(&:call_type) if user_id.present?
Note the additional field that I'm creating with AS call_duration => ActiveRecord simply turns this into an attr_reader on the model, so you can do #in_app_calls[0].call_duration and such things like you would with any regular column.
I also took the liberty of cleaning up your handling of the user_id – I hope it's correct this way, otherwise you should have no trouble reverting this bit back to your original.

access to record params with ActiveRecord relation number

I'm trying to get a record in DB by having these two lines in one of my models:
a = Arel::Table.new(:receivers)
e = Receiver.where(a[:name].matches('%afsane%'))
In my receivers table I have a row in which the name column equals to "afsane".I want to have that row's id in my model.
but by printing the e in my model I've got this :
"========#<Receiver::ActiveRecord_Relation:0x0056094261eff8>============"
which gives the relation number but no params.
When I run them in rails console I got this response:
#<ActiveRecord::Relation [#<Receiver id: 2, name: "afsane", created_at: "2016-09-27 09:24:16", updated_at: "2016-10-09 10:10:02">]>
I managed to have this in my model But I couldn't .
ps:Using Rails 5.
Have any Ideas ?
I'm not sure what the variable a looks like but the variable e is a collection.
where returns a collection which means you will have to iterate through e in order to pull out some data.
Like so:
e.each do |data|
data.name
end
If you want to return only 1 result then you can simply do the following:
e = Receiver.where(a[:name].matches('%afsane%')).limit(1)
Note: I've kept the answer simple but there are more elegant solutions to this so I recommend you reading the ActiveRecord Rails Guides

Ruby Gem ActiveRecord find method with multiple conditions

I'm building a Sinatra application using three database's tables: user, post and like.
I'd want to run a query that will find an entry in the like table like so:
FIND in like WHERE user_id == params[:user_id] AND post_id == params[:post_id]
(for one condition I'll be using: Like.find_by_user_id(params[:user_id]))
My question is:
How to run a find query with multiple conditions using the ActiveRecord Gem?
Use where:
Like.where('user_id = ? AND post_id = ?', params[:user_id], params[:post_id])
or
Like.where('user_id = :user_id AND post_id = :post_id', params)
Is important to keep in mind that the paremeters of the where need to be converted to the expected type for example params[:post_id].to_i
Similar to find_by_user_id for user_id column you can combine multiple column names and get a dynamic finder find_by_user_id_and_post_id:
Like.find_by_user_id_and_post_id(params[:user_id], params[:post_id])
When there are more than "bearable" columns in the find_by_ finder, you could use where and supply the condition as follows:
Like.where(user_id: params[:user_id], post_id: params[:post_id])
Like.find_by_user_id(params[:user_id]) - this syntax is deprecated in ActiveRecord 4.
Instead try using where method of ActiveRecord query interface, to pass array conditions. Example:
Like.where("user_id = ? AND post_id = ?", params[:user_id], params[:post_id])
If you are expecting one record to be the result:
To replace find_by_whatever you can use find_by(whatever) for example User.find_by(username:"UsernameIsMyUsername",password:"Mypassword"). You should use find_by if there is only one record that you expect to match your search.
If you are expecting more than one record to be the result:
If you expect more than one you should use where with where(username:"MyUsername",password:"Password"). This will return all the resulting records in an array.

How to show all departments where school name = x?

Upon the creation of a department, users have the option to add the name of a school. On the show page of the school, I want to show all the departments with the school of that name.
My school controller's show action looks like this:
def show
#department = Department.where(:school == 'university of connecticut')
end
This obviously isn't working. What is the correct syntax for this?
Either if these should give you the expected results:
#department = Department.where(school: 'university of connecticut').first
or
#department = Department.where('school = ?', 'university of connecticut').first
where takes either a hash or a SQL statement. Note that in the first example, we're using the shortcut hash method when using a symbol symbol: value, which is equivalent to :symbol => value
Also, keep in mind that where returns an ActiveRecord::Relation object, not an ActiveRecord object. You'll need to add .first or another form of .find if you wish to receive an ActiveRecord object directly.
You're close:
Department.where(school: 'university of connecticut').first
i.e. normal hash syntax.

Rails returns a nil, when searching with find_by

I'm beginning to learn RoR, but i've a problem which i don't understand. With Product.find :all returns all the records from DB. But if i want to find_by_gender(1) (or even 2) it returns a nil, i'm certain that the db contains products with a gender
My code controller:
gender = params[:gender].to_i
#search_results = Product.find_by_gender(gender)
this returns a nill,
What am i doing wrong?
Greetings!
find_by_... returns either first record or nil if none found, find_all_by_... returns all records that match (or empty array if none). In your case nil means no records found with gender = 1.
Verify your data first!
Look at some sample records:
Do something like:
Product.all(:limit => 5).each {|product| product.id.to_s + product.gender}
or go into sql
sql> select id, gender from products where id < 6;
If you are to verify what the gender values are you can then create named scopes in your model for those conditions, e.g. (rails3)
(Product Model - app/models/product.rb)
scope :male where(:gender) = male_value # i.e. 1 or 'M' or 'Male' or whatever
scope :female where(:gender) = female_value # i.e. '2' or 'F' or whatever
Which will then you let write Products.male or Products.female !
Final note - should gender be in your users table? , or is this for male / female specific products?
in rails console execute
Product.pluck(:gender)
And u will know that values does it have in AR(i think true and false), so u have to use query Product.find_by_gender(true)

Resources