Selecting second entry in rails console? - ruby-on-rails

I need to select the second entry in the User model.
User.second does not work, nor does User.2 or User.two.
I'm trying to set u to the second User entry (u = User.2)

The following should work:
User.all.second
User.offset(1).first
# Assuming you are using incremental keys and have users with ID's 1 and 2:
User.find(2)

Related

No error on updating deleted object in rails

Rails executing update on deleted records.
I have a web app on ruby on rails in which I created some users and after that I opened the rails console and assigned U1 to one of my user let say last user then assigned the same User to U2. Then I run U1.destroy which executes successfully
after that I updated the name of user through U2 and it returns me true Although, user was destroyed from database when I checked it. My concern is rails should give me false as there was no object in database against that ID.
If you want to double check that record exists before updating you can use reload
user.reload.update(name: "Some Name")
It will raise ActiveRecord::RecordNotFound if record with such id is absent
UPDATE changes the values of the specified columns in all rows that satisfy the condition.
https://www.postgresql.org/docs/current/sql-update.html
Rails doesn't return false or raise an exception because the UPDATE is still a valid query in the database, even if no rows match the condition. If you connect directly to your PostgreSQL database and run...
UPDATE users
SET name = 'test'
WHERE id = 123
...if 123 is an id that no longer exists, then the database will successfully execute the query and respond with:
UPDATE 0
If it is an id that still exists, the database will respond with:
UPDATE 1
This is similar to how Rails behaves if you use update_all. If you were to run update_all on a record that no longer exists, you'd see something like:
User.where(id: 123).update_all(name: 'test')
=> 0
But if the record exists you'd see:
User.where(id: 123).update_all(name: 'test')
=> 1
No error will be raised.
The purpose of the Rails update and update_all methods is just to attempt to run an UPDATE query in the database. If there is a timing issue and the record no longer exists, that's not something that the database or Rails is designed to give warnings about.

Rails 5.1 has_many through - associated fields

(See example schema image below)
I am attempting to query a single user from the users table using the email field, along with the id & key fields from the applications table. The results should contain the user found (if any), along with the application (referenced using the key & id fields) and the applications_users associated data.
I can easily write SQL manually to perform this operation:
SELECT
"users".*,
"applications_users"."scopes",
"jwt_applications".*
FROM
"users"
INNER JOIN
"applications_users" ON "applications_users"."user_id" = "users"."id"
INNER JOIN
"jwt_applications" ON "jwt_applications"."id" = "applications_users"."application_id"
WHERE
"users"."email" = 'rainbows#unicorns.net'
AND "jwt_applications"."id" = '01daafc9-2169-4c78-83e9-37ac0a473e3d'
AND "jwt_applications"."key" = 'follow_the_rainbow'
LIMIT 1
However, I cannot for the life of me get the query correct when using ActiveRecord.
These are the unsuccessful attempts I have made thus far:
user = User.where(email: args[:username]).joins(:applications).merge(
JwtApplication.where(id: args[:application][:id], key: args[:application][:key])
).take!
This gets the user correctly, however Rails performs a second SQL query when I attempt to access user.applications (and it also returns all applications associated with the user; so it appears to disregard the id & key conditions)
user = User.where(email: args[:username]).joins(:applications).merge(
JwtApplication.where(id: args[:application][:id], key: args[:application][:key])
).references(:applications_users).take!
This gets the user correctly and also the correct application (yay!), however Rails performs a second SQL query if I attempt to call user.applications_users -- it also returns a collection for all data inside the applications_users table (again, disregarding the id & key conditions)
user = User.where(email: args[:username]).joins(:applications).where(
jwt_applications: {
id: args[:application][:id],
key: args[:application][:key]
}
).take!
This gets the correct user, however Rails performs another SQL query when I attempt to access user.applications -- also returning all applications.
Anyway, hopefully a Rails genius can shed some light on this question! I will be the first to admit that I am by no means a Rails expert; I have spent the last 10 years of my professional career coding in PHP & C++, so please bear with me if this comes off as a stupid question :)
Not sure if this is something you're looking for but...
You can write ActiveRecord query like (join model should be implicitly added to your query):
User.joins(:applications).where(email: email).where(applications: { key: key, id: id})
Where email, key and id as params to pass to the query.
On top of that query you can use select fields to get everything you need:
user = User.joins(:applications).where(email: email).where(applications: { key: key, id: id}).select('users.*, applications.id as appid applications.key as appkey').first
That will give you back the user model (if present) or empty relation if nothing matches your criteria.
You can then call the fields like
user.appid
user.appkey
You can always call select ('users.*, application_users.scopes, applications.*) which will return you all the fields in single instance (still under User model) BUT duplicate fields like id will only be shown once, that's why it's better to grab just the fields you want and give them unique identifiers like I've shown with appid and appkey.
Again, might not be exactly what you're after, but hopefully it points you in the right direction!

ruby on rails pairing users in database

How can I write a code in Ruby on rails that picks user X from my database( let say I have a column called 'taskdone' which accepts only boolean values ... And user X is true in such column) such that when a new user signs up, user X is displayed on his profile. And the new user is given a task to complete. If he
completes it successfully user X can confirm from his own account that the new user has completed his task by clicking a button which writes a value of true to the new users paid 'task done ' column. And after user X has confirmed four people, his value in the column should go back to false. It's quite complicated please I need someone to help am frustrated searching Google without answers
You can do this in two ways
1- If you need the information about "which user confirms another user" You can create an association to hold for each user X which other users he has confirmed.
2 - If you won't use these info you can just create a column that counts the number of confirmed users in the Users tabel.
In both cases, After a user confirms another user make a check if he has confirmed 4 users or not using the callback after create and then update the taskdone column.
after_create :update_task_done
In the first way do
def update_task_done
if self.confirmed_users.count == 4
self.update(taskdone: false)
end
end
In the second way
def update_task_done
if self.confirmed_users_count == 4 # notice this is column.
self.update(taskdone: false)
end
end

rails can you reference a model within a model?

I seem to have run into a problem with trying to use a model in another model in Rails.
I am pulling a list of users from Active Directory with LDAP in a dropdown. I want to parse the cn that I get from Ldap into a firstname and lastname.
The problem I am running into is that I need to find a record in the users model. The parsing is being done in observations.rb.
Observation.rb:
def parse_employee
#emp_name = '' #initialize
self.employee_raw = self.employee_raw[2...-2] # get rid of the quotes and brackets
#emp_name = self.employee_raw.split(' ') # split first/last names
#emp_first_name = #emp_name[0] #Grab the first name
#emp_last_name = #emp_name[1] # grab the surname
#user = User.where("last_name like ?", #emp_last_name)
self.employee_id = #user.id
end
I've played with this quite a bit and it appears that I can't reference other models from within a model.
To sum up, what I am trying to do is
1. Have the user select the appropriate person from a dropdown that is pulled via LDAP from active directory.
2. Use the first and last names to find the appropriate user in my user table (Right now I'm just trying to get it to work with the last name as that is unique enough)
3. When I find the correct user in the user table, enter that id in the employee_id field in my observations table.

Rails checking if an object is also assigned to another

in my Rails application I've got a n:m relation between movies and tags. (has_and_belongs_to_many)
So each tag can be assign to several movies.
Now when I add new tags to a movie I want to check If this Tag is already assigned to this movie.
What is the esiest way in rails to check if there is a relation ship between the tag and the movie?
I fetch the tag with:
#tagfound = Tag.where("tagname = ?", data[:tagname])
The List with all Tags from the movie can be fetched with this:
#vid.tags
Thanks for your help
You may not need to check. You can simply do this
movie.tags = [array, of, tags]
movie.save # note, you don't need to save. The line above saves.
or
movie.tag_ids = [1,2,3,4]
movie.save # note, you don't need to save. The line above saves.
and that will take care of it setting new tags and removing the ones that are no longer connected. Good for checkbox UI or a tokenizer.
To answer your question, to find if a movie has a tag, you can do this
tag.in?(movie.tags)
And this is the way to add a single
movie.tags << tag unless tag.in?(movie.tags)
[EDIT]
If you do this
movie.update_attributes(movie_params)
and one of the params is the tag_ids, the movie will only save the new tags if it is valid (no other errors).
I believe there are 2 ways you can do this.
Check if #tagfound is included in #vid.tags
#vid.tags.include? #tagfound
Add the tag & call uniq after.
#vid.tags << #tagfound
#vid.tags.uniq!

Resources