Ruby - Datamapper - Collecting records by joining two models - ruby

I have two tables
users
-------
id
name
organization_id
organizations
----------
id
org_name
org_unique_num
abc
xyz
organization_id in users table is foreign key to organizations table's id
class Organization
include DataMapper::Resource
property :id, Serial
property :org_name, String
property :org_unique_num, Integer
property :abc String
property :xyz String
has n, :users
end
class User
include DataMapper::Resource
property :id, Serial
property :name, String
property :organization_id, Integer
property :age, Integer
belongs_to :organization
end
I want to grab the user's record with joining Organization table where user's age > 25. So the result should look like
user_id name organization_id org_name org_unique_num age
12 John 356 ATT 76763 38
35 Lisa 981 IBM 2376 28
So how can I achieve this? Please note I dont want column abc and xyz in the result.
User.all(:age.gt => 25)
This will just give me users with age >25, but I want to grab user's org info as well. Is it possible to do it one statement? or will have to do it in multiple steps. Like collecting all user_id then pass to Organization model to with id in().. that would be ugly.
Any help will be appreciated.

DataMapper will do all join job for you.
you do not need to extract organizations for each user, this is done automatically.
So, you simply fetch your users with this: User.all(:age.gt => 25)
And each user will have its organization attached to it:
User.all(:age.gt => 25).each do |user|
p user.name
# organization not yet fetched, only referenced
p user.organization
# now organization are fetched
p user.organization.id # display org ID
p user.organization.org_name # display org name
# etc
end
Regard "i do not need abc and xyz", if they are Text columns, DataMapper will load them lazily, meant the data will be fetched only when requested via user.abc and user.xyz

Related

Take total price from all product for many users

i have issue
Model Driver has association like has_many: orders
class Driver < User
has_many :orders
end
and Order has belongs_to :user
class Order < ActiveRecord::Base
belongs_to :user
end
and Order has column like price
My problem is, i want to display all drivers by table
first column will be first_name, next last_name,
i want to display total price for each users. price will be counting by summing by all orders for user,
Problem is n+1, how i can display total price for each user, without sent separate request to the DB
Example of index page
first_name.
last_name
Price
Arian
Lain
2500
Brain
Kokun
4700
You can get a sum for grouped values using a single SQL query with SUM and GROUP BY. In Rails, this can look like this:
#sums = Order.group_by(:user_id).sum(:price)
# {1 => 2500, 2 => 4700, ...}
In your view, you can then fetch the sum for the respective user using the user's id as a key, e.g. with this (assuming you have the current driver / user in the driver variable):
<%= #sums[driver.id] %>

How to group and sum by foreign key?

I have these two models in my Rails app:
class Person < ApplicationRecord
has_many :payments
end
class Payment < ApplicationRecord
belongs_to :person
end
How can I group the payments by person and order them by amount?
Right now I have...
Payment.group(:person_id).sum("amount")
...which works but doesn't include the persons' names. It returns something like this:
{ 1 => 1200.00, 2 => 2500.00 }
How can I replace the IDs / integers with the persons' names and also sort the whole thing by amount?
Thanks for any help!
Just be a bit more specific:
Payment.select('people.name, SUM(payments.amount)').joins(:person).group(:person_id)
Assuming that the persons table is named people in your application.
This will return the ActiveRecord::Relation that you can work with:
Person.joins(:payments).group('persons.id').select("persons.id, persons.name, sum(payments.amount) as amounts_summ")
Only for unique name fields:
Assuming you have name property for Person model, solution can be like this:
Payment.joins(:person).group(:name).order('sum_amount DESC').sum(:amount)
It generates query
SELECT SUM("payments"."amount") AS sum_amount, "name" AS name FROM "payments" INNER JOIN "persons" ON "persons"."id" = "payments"."persons_id" GROUP BY "name" ORDER BY sum_amount DESC
and return hash like this:
=> {"Mike"=>22333.0, "John"=>5676.0, "Alex"=>2000.0, "Carol"=>2000.0}

Rails 5: Insert/Update only if there's no filled specific field for that id

I have a Followups table with the fields: patient_id, death_date (and other fields..).
There could be multiple records for the same patient_id but there must be only one death_date for that patient_id.
A unique index won't work as the user could insert two different death_date.
Which is the best way to achieve this in Rails 5?
If possible, please make an example.
Thanks
You could do this with a callback on the Followup model:
Assuming a Patient has_many :followups
class Followup
belongs_to :patient
validate :check_for_existing_death_date
private
def check_for_existing_death_date
# This will grab the first one if any with a death date exist
# This also assumes that the patient_id and patient exist
followup = patient.followups.where("death_date IS NOT NULL").take
# if you want to raise an error...
if followup
errors.add(:death_date, 'There is already a death date for this patient')
return false
end
# If not, do something with the data
# if followup
# self.death_date = nil # or followup.death_date if you want it saved on followups as well
# end
end
end
I would think that the best way to do this would be to store the death_date on the Patient record, since death only happens once per patient.

Using ActiveRecord with column names with spaces in them

I work on a team that is using ActiveRecord to access the schema on a MSSQL server. Modifying the schema is not an option and the column names have spaces in them, a la SPACEY COLUMN.
When writing the ActiveRecord class to access a table with spaces in it, what is good practice?
We also need this to work with factory girl...
AR-JDBC (as well as the AR-SQLServer-Adapter) will/should handle this just fine since it auto-magically quotes column name identifiers using "[ COlumn NAME ]" ... I personally would hide this from bubbling up as much as possible e.g. using aliases :
class MySpacey < ActiveRecord::Base
set_table_name 'SPACEY TABLE'
set_primary_key 'MY ID'
alias_attribute :id, :'MY ID'
end
Consider User is the Model and User Name is the column you need to access.
User.where('User Name' => 'Bob')
You can add multiple conditions also,
User.where('User Name' => 'Bob', 'Email Address' => 'sample#sample.com')
You can also try,
User.where('[User name] = ? AND [Email Address] = ?', 'Bob', 'sample#sample.com')
And if your table itself has space in it. Try,
class User < ActiveRecord::Base
self.table_name = "user table"
end

How to add a uuid primary key to existing table without id column

Other than dropping and recreating a table, how can I add a primary key id column of type uuid to a table that was created without an id field - a join table?
I tried:
add_column :organizations_users, :id, :uuid, primary_key: true
but the column doesn't get set as a primary key.
Looking at the new_column_definition ActiveRecord method, the code above should work:
column.primary_key = type == :primary_key || options[:primary_key]
I must be having a brain fart...
An old question, but if anyone comes across it, this worked for me in Rails 5.2. I was already using UUIDs for primary key :id columns in other tables, so you might need to set that up first if you're not.
def change
add_column :products_questions, :id, :uuid, primary_key: true, default: -> { "gen_random_uuid()" }
end

Resources