Association in rails Model - ruby-on-rails

Below is the model Structure.
class UserFamilyRole < ActiveRecord::Base
belongs_to :user_family
belongs_to :user_role
belongs_to :organization
end
class UserFamily < ActiveRecord::Base
has_many :user_family_roles
has_many :user_roles
end
I am looking for below result from the above UserFamilyRole table.
{
user_family1: [user_role1, user_role2],
user_family2: [user_role1, user_role2, user_role3]
...
}
I achieved this Result from below query:
user_family_roles = UserFamilyRole.where(:organization_id => org_id)
results = {}
juser_family_roles.each do |user_family_role|
user_family = UserFamily.find(user_family_role.user_family_id)
result[user_family.name] = user_family.user_roles.collect(&:title)
end
puts results
But Above query doesn't look optimized one so can anyone help me to write the optimized query.
In our App org_id is present.

Related

How to merge two double joins in ActiveQuery

I have two double joins (I believe that's what they would be considered) and it just seems awfully slow to do them separately. I know there are debates as to whether or not an individual query is quicker than multiple queries and vice versa but I am willing to try anything.
Here are my existing statements:
line_stops = OpsHeader.joins(
ops_stop_rec: :driver_header
)
.select(
:pbbname,
:pb_net_rev,
:ops_driver1,
:pb_id,
:ops_stop_id,
:dh_first_name,
:dh_last_name,
:ops_delivered_time
)
.where(
:ops_stop_rec => {
ops_arrive_time: params[:startDate] .. params[:endDate]
})
line_items = OpsHeader.joins(
ops_stop_rec: :ops_line_items
).select(
:pbbname,
:opl_amount,
:pb_id,
:ops_type,
:ops_stop_id,
:ops_order_id,
:ops_driver1,
:ops_delivered_time
)
.where(
:ops_stop_rec => {
ops_arrive_time: params[:startDate] .. params[:endDate]
}
)
Just for reference, I am pulling these from an old Firebird Database and the server hardware is not necessarily quick either, so there may be more at play than I am thinking. Also, I have to data manipulation on top of that before I serve it to the client.
Anyway, here are my associations:
class OpsHeader < ApplicationRecord
belongs_to :pb_bill
belongs_to :pb_master
has_many :ops_stop_rec, foreign_key: 'ops_order_id'
self.table_name = 'OPS_HEADER'
self.primary_key = 'pb_id'
end
class OpsStopRec < ApplicationRecord
#belongs_to :ops_order
#belongs_to :ops_im_equip
belongs_to :ops_header, foreign_key: 'pb_id'
belongs_to :driver_header, foreign_key: 'ops_driver1'
has_many :ops_line_items, foreign_key: 'opl_stop_id'
self.table_name = 'OPS_STOP_REC'
self.primary_key = 'ops_stop_id'
end
class OpsLineItem < ApplicationRecord
#belongs_to :opl_order
#belongs_to :opl_stop
belongs_to :ops_stop_rec, foreign_key: 'ops_stop_id'
self.table_name = 'OPS_LINE_ITEMS'
self.primary_key = 'opl_stop_id'
end
class DriverHeader < ApplicationRecord
#belongs_to :dh_paythru
has_many :ops_stop_rec, foreign_key: 'ops_driver1'
self.table_name = 'DRIVER_HEADER'
self.primary_key = 'dh_id'
end
What you're looking for is a union operator. There is a gem which can handle it for you.
Or try using using two left outer joins and add an OR condition.

How to implement dynamic class_name for the association has_many? For the same table, different engines

Please tell me the way how to implement dynamic associative link, which is itself determined by the attribute model.
I have two engines(Tbitcoin, Tstripe) each of them have a table payment. The model User has pay_currency attribute, which is the managing.
class User < ActiveRecord::Base
has_many :payments, ~> { where "pay_currency = 'real'" } , class_name: Tstripe::Payment, foreign_key: :uid
has_many :payments, ~> { where "pay_currency = 'bitcoin'" } ,class_name: Tbitcoin::Payment, foreign_key: :uid
end
What are the ways to dynamically determine the engine using User.last.payments.create ?
I think that you need a regular method instead of has_many association which will find proper payments associated with the user according to pay_currency value. Example:
class User < ActiveRecord::Base
def payments
payment_class = case pay_currency
when "real"
Tstripe::Payment
when "bitcoin"
Tbitcoin::Payment
end
payment_class.for_user(self)
end
end
class Tstripe::Payment < ActiveRecord::Base
belongs_to :user
def self.for_user(user)
where(user_id: user.uid)
end
end

Rails 4 SQL query rails way

i have this query, which I want to se in rails way. Could please anyone help me here?
select * from users
,buyer_events
,supplier_events
where (users.id = buyer_events.buyer_id
or users.id = supplier_events.supplier_id)
and supplier_events.event_id = 11
and buyer_events.event_id = 11;
PostgreSQL
If more information is needed just write in comments :)
I guess it should be something like this:
class User
has_many :supplier_events
has_many :buyer_events
scope :with_event, ->(event_id) {
joins(:supplier_events, :buyer_events).merge(supplier_events.for_event(event_id)).merge(buyer_events.for_event(event_id))
}
end
class SupplierEvent
belongs_to :supplier, class_name: :User
belongs_to :event, class_name: :Event
scope :for_event, ->(event_id) { where(event_id: event_id) }
end
class BuyerEvent
belongs_to :buyer, class_name: :User
belongs_to :event, class_name: :Event
scope :for_event, ->(event_id) { where(event_id: event_id) }
end
Then issue:
User.with_event(11)
class User < ActiveRecord::Base
...
def self.buyers_and_suppliers user_id
joins(:buyer_events, :supplier_events).where(users: {id: user_id}, supplier_events: {event_id: 11}, buyer_events: {event_id: 11})
end
...
end

Association not working

I have three models:
Department
class Department < ActiveRecord::Base
has_many :patients, :dependent => :destroy
has_many :waitingrooms, :dependent => :destroy
end
Waitingroom with fields patient_id:integer and department_id:integer
class Waitingroom < ActiveRecord::Base
belongs_to :patient
end
Patient with department_id:integer
class Patient < ActiveRecord::Base
belongs_to :department
has_many :waitingrooms
end
I save a waitingroom after a patient was in the waitingroom! So now i tried to retrieve the patients who where in the the waitingroom of the department:
def index
#waited = #current_department.waitingrooms.patients
end
Somehow it didnt worked it returned this error:
undefined method `patients' for #<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Waitingroom:0x374c658>
But this worked: What did i wrong? Thanks!
def index
#waited = #current_department.waitingrooms
end
You can't invoke an association on a collection. You need to invoke it on a specific record. If you want to get all the patients for a set of waiting rooms, you need to do this:
def index
rooms = #current_department.waitingrooms
#waited = rooms.map { |r| r.patients }
end
If you want a flat array, you could (as a naive first pass) use rooms.map { |r| r.patients }.flatten.uniq. A better attempt would just build a list of patient ids and fetch patients once:
#waited = Patient.where(id: rooms.pluck(:patient_id).uniq)

Complex ActiveRecord Query

I'm having a hard time wrapping my head around how to build this query. I'm not sure if I should try to create a bunch of scopes and try to chain them. Or do I put it into a class method? Or would I do a combo of both? If anyone could give me a short example it would keep me from jumping out the window, I've been working on this for over a week now.
class CensusDetail < ActiveRecord::Base
belongs_to :apartment
belongs_to :resident
end
class Apartment < ActiveRecord::Base
belongs_to :apartment_type
has_many :census_details
has_many :residents, :through => :census_details
end
class ApartmentType < ActiveRecord::Base
has_many :apartments
end
class Resident < ActiveRecord::Base
has_many :census_details
has_many :apartments, :through => :census_details
end
apartment.rent_ready = boolean value if apartment is ready
apartment_type.occupany = the number of allowed occupants in an apartment
census_detail.status = either "past", "present", or "new"
census_detail.moveout_date = date time resident is scheduled to move out
I need to build a query that does the following:
- if the apartment is rent ready then do the following:
- pull a list from census_details of all residents set as "current" for each apartment
-if the # of residents is less than the value of apartment_type.occupancy for this
apartment, then list it as available
-if the # of residents is = to the value of apartment_type.occupancy then
-does any resident have a scheduled move out date
-if not, do not list the apartment
-if yes, then list apartment
Thanks in advance for any help or suggestions.
I haven't cleaned it up yet, but this is working for me, so I wanted to share.
apartment_type.rb
class ApartmentType < ActiveRecord::Base
has_many :apartments, :dependent => :nullify
end
census_detail.rb
class CensusDetail < ActiveRecord::Base
belongs_to :resident_contacts
belongs_to :apartments
scope :get_current_residents, ->(id) { where("status = ? and apartment_id = ?", "current", id) }
end
apartment.rb where most of the work is happening
class Apartment < ActiveRecord::Base
belongs_to :apartment_type
has_many :census_details
has_many :residents, :through => :census_details
scope :rent_ready, -> { where(:enabled => true) }
def self.available
available_apartments = []
rent_ready_apartments = self.rent_ready.all
rent_ready_apartments.each do |apt|
tmp = ApartmentType.where('id = ?', apt.apartment_type_id).pluck(:occupancy)
occupancy = tmp[0]
current_residents = CensusDetail.get_current_residents(apt.id)
resident_count = current_residents.count
if resident_count < occupancy
available_apartments << apt
end
if resident_count = occupancy
scheduled = false
current_residents.each do |res|
if res.moveout_date
scheduled = true
end
end
if scheduled == true
available_apartments << apt
end
end
end
available_apartments
end
end
The code is a bit ugly but its so far passing my tests. I would have edited my original question instead of answering in case someone has a better way of doing this but each time I do my question gets voted down. If anyone knows a better way please let me know because I'm at a point in the app where there are about 50 tables and now it's all getting tied together with complex queries.

Resources