update Rails / ActiveRecord / SQL database dynamically - sql

I have a database full of stories, and each story belongs to a user.
I already have a user_id attribute for each story.
I recently added a user_name attribute to all my stories as well.
Now all of those user_name attributes are nil.
In the console, I can do Story.first.user_name = Story.first.user.name to set the user_name attribute to the first story's user.name value.
How can I iterate through all my stories in my Postgresql database and dynamically update each story's user_name value?
I want to use something like ActiveRecord's update_all method, but with a dynamic argument.
I tried in the Rails console:
Story.update_all('user_name = Story.user.name')
but that returned:
SQL (36.2ms) UPDATE "stories" SET user_name = Story.user.name
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "user"
LINE 1: UPDATE "stories" SET user_name = Story.user.name
^
: UPDATE "stories" SET user_name = Story.user.name
from (irb):14
Not sure how to use the FROM in raw SQL, or how to write the correct command in ActiveRecord.

The easiest way is to iterate over all records in the stories table:
Story.find_each {|story| story.update(user_name: story.user.name)}
If your goal is not to touch timestamps or validations as with update_all you can do
Story.find_each {|story| story.update_column(:user_name, story.user.name)}

Related

Creating a scope in Ruby on Rails, that returns an instance of an object only if all the associated instances fit a certain condition

I have a table called Carts with a has_many relationship to another table called Subcarts. I want to create a scope that returns all instances of the Cart table where all the associated Subcarts fits a particular condition (ex: subcart.status == 1). If even one subcart that is associated to a Cart instance has a status of 1, the query should not return the cart instance.
scope :cart_bucket, -> {
includes(:subcarts).
where.not('subcarts.status = ?', 1).
references(:subcarts)
I've also tried to use select within the query but had an error returned because of the return array data type. I would like to keep this within a scope and not create a method if at all possible.
You can select all the carts ids from those subcarts where the status is not 1 and use that as the where clause to leave out all the carts matching those ids:
Cart.where('NOT EXISTS (SELECT s.cart_id FROM subcarts s WHERE s.cart_id = carts.id AND s.status = 1)')
The ActiveRecord version might change a bit:
Cart.where.not(id: Subcart.where(status: 1).select(:cart_id))
There the SQL generated uses a NOT IN clause instead of NOT EXISTS.

How does Rails convert an ActiveRecord::Result to an ActiveRecord object?

Let's say I have a model comment.rb and a comments table in my PG db.
If I fetch the first comment in the rails console:
Comment.first
it will use the following SQL statement to fetch it:
SELECT "comments".* FROM "comments" ORDER BY "comments"."id" ASC LIMIT 1
And I get my Comment record:
#< Comment:0x007f973234212b with its attributes.
However, if I execute this SQL statement like this:
ActiveRecord::Base.connection.exec_query("SELECT comments.* FROM comments ORDER BY comments.id ASC LIMIT 1")
it will return an ActiveRecord::Result, on which I can call .columns or .rows.
How can I turn this ActiveRecord::Result into the actual ActiveRecord object that I'm trying to retrieve. What does Rails do to output it in the form of the actual record with its attributes?

SQL Server: If, Else Select Statements to populate a grid

I'm trying to populate a data-grid with information from my table. One of the fields in this table is Active basically used as a flag set to either True or False.
I have a query on my website that checks if the currently logged-in user's is an administrator or not.
Using that in a TOKEN I can input [LSX:IsAdmin] that will return either true or false.
All data in my table that is NOT flagged Active=True i'd like to display only to Administrators which is what my TOKEN is for.
I'm having some difficulties with my query below to achieve that.
IF('LSX:IsAdmin'='True')
SELECT * FROM SaleEvents
ELSE
SELECT * FROM SaleEvents WHERE Active = True
Error Message Invalid object name 'SaleEvents'.
First picture shows how to find out schema name (CIS, dbo, TestCars, TestDoc, TestMoney). 'dbo' schema usually exists and default.
However, you can change default schema for user (second picture).
You do not specify schema name in your query, that's why default schema is used.
To specify a schema name you should add it before table name
SELECT * FROM <your schema>.SaleEvents WHERE Active = 1

ActiveRecord find position (index) of record within relation based off value of attribute

I have a collection ActiveRecord User objects. User has an attribute, engagement, which is a float. Assuming users = User.all.order(engagement: :desc) returns 1000 records and current_user is a User object within users, I would like to know the position or index current_user within users without querying the database again or using an enumerator method such as each_with_index, which is slow. Is this possible?
collect the ids and find the index of the current_user.id
index = User.all.order(engagement: :desc).map(&:id).index(current_user.id)
you can just pluck the id to avoid map
index = User.order(engagement: :desc).pluck(:id).index(current_user.id)
#BKSpurgeon You can do this entirely in the DB using something like
User.where("engagement < ?", current_user.engagement).count + 1

column doesn't exist in table whiel its showing the column in schema

i am using postgresql .i am using psql.i run a command \d+ user i get schema of user table .
but when i run the command select first_name from user .its giving me error
ritesh=# select first_name from user;
ERROR: column "first_name" does not exist
LINE 1: select first_name from user;
^
as you can see in the screenshot .How to resolve it and where i am mistaking please explain.
This problem occurs because "user" is a keyword. You should not use it for table names, etc. Otherwise you get fun like this.
See, user is a magic pseudo-function that returns the current username - it's an alias for current_user:
regress=> SELECT user;
current_user
--------------
testuser
(1 row)
So what you're trying to do is call the function user in a set-returning context, and get the column first_name from it. The function result has no such column, hence the error.
Don't just schema-qualify your table as public.user to get around this. At minimum you should be using quoted identifiers if you're going to use SQL keywords for table names, e.g.:
select first_name from "user";
but really, it'll be much better to just name your table something that doesn't conflict with a keyword.
try "select first_name from public.user"