Rails joins polymorphic model attribute where condition is met - ruby-on-rails

I can't figure out how to make this query work. I'm looking to get all the user ids of addresses who have a user that is an admin.
Address
.near([#address.latitude, #address.longitude], 5)
.where(addressable_type: 'User')
.joins(:addressable)
.where('addressable.is_admin = ?', true)
.pluck(:id)
Address.rb
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
User.rb
class User < ApplicationRecord
has_one :address, :as => :addressable, dependent: :destroy

You cannot directly join the addressable relation as the addressable entities could belong to different models. You could try something like this:
Address
.near([#address.latitude, #address.longitude], 5)
.where(addressable_type: 'User')
.joins("INNER JOIN users on users.id = addresses.addressable_id")
.merge(User.admin)
.pluck(:id)
.merge can be used to invoke scopes of joined tables. Here, User model would have a scope called admin which would return admin users.

Related

Rails find or load specific record from includes on has_many

Apologies for the terrible title!
Background
Users can have many Organisations
Organisations can have many Users
UserOrganisations is the join model and stores data about a specific user in a specific organisation.
class Organisation < ApplicationRecord
has_many :user_organisations, dependent: :destroy
has_many :users, through: :user_organisations
end
class User < ApplicationRecord
has_many :user_organisations, dependent: :destroy
has_many :organisations, through: :user_organisations
end
class UserOrganisation < ApplicationRecord
belongs_to :user
belongs_to :organisation
end
Problem
I want to get all users that belong to a specific organisation, excluding users which have a specific attribute and including or eager loading the joining UserOrganisation record.
At the moment I'm calling
class User < ApplicationRecord
scope :super_users, -> { where(super_user: true) }
end
#organistion.users.excluding(User.super_users)
I want to be able to reference values from the specific UserOrganistion.where(user_id: user.id, organisation_id: #organistion.id)
Is there a way of doing it this way around or do I need to do #organisation.user_organisations.joins(:users).merge(User.not_super_users)
I think you want do something like this:
SELECT u.*
FROM users u
JOIN user_organisations uo ON u.id = uo.user_id
JOIN organisations o ON o.id = uo.organisation_id
WHERE o.id = some_organisation_id
AND u.super_admin = false
and the equivalent AR query can be:
Organisation.find_by(id: some_organisation_id).users.where(admin: false)
or
Organisation.find_by(id: some_organisation_id).users.where.not(admin: true)

Rails 5 check if record exist in belongs_to relations?

I have 3 models Account, Plan and User (And I can not modify the relations model structure, but add scopes or methods)
Account
belongs_to :plan
Plan
belongs_to :user
User
has_may :plans
I want to know if EXISTS an account with a specific user_id
Account.exists?…….. //here is my problem
I would join the database tables by using joins which results in a INNER JOIN in SQL and than add a condition for the user_id in question:
Account.joins(plan: :user).where(users: { id: user_id }).exists?
Read about joins in the Rails Guides.
You can create indirect associations which link Account and User through the Plan model:
class Account < ApplicationRecord
belongs_to :plan
has_one :user, through: :plan
end
class Plan < ApplicationRecord
belongs_to :user
end
class User < ApplicationRecord
has_may :plans
has_many :accounts, through: :plans
end
This will let you query:
Account.joins(:user)
.where(users: { id: user_id })
.exists?
ActiveRecord will automatically handle joining through the plans table.
See the Rails guides:
The has_many :through Association
The has_one :through Association
Specifying Conditions on the Joined Tables

Eager load polymorphic associations

I have the following models:
class Conversation < ActiveRecord::Base
belongs_to :sender, foreign_key: :sender_id, polymorphic: true
belongs_to :receiver, foreign_key: :receiver_id, polymorphic: true
.
class Owner < ActiveRecord::Base
.
class Provider < ActiveRecord::Base
.
class Account < ActiveRecord::Base
has_one :provider, dependent: :destroy
has_many :owners, dependent: :destroy
So in a Conversation, sender can be an Owner or a Provider. With this in mind, I can make queries like:
Conversation.includes(sender: :account).limit 5
This works as intended. The problem is when I want to use a where clause in associated model Account. I want to filter conversations which associated account's country is 'US'. Something like this:
Conversation.includes(sender: :account).where('accounts.country' => 'US').limit 5
But this wont work, I get the error ActiveRecord::EagerLoadPolymorphicError: Cannot eagerly load the polymorphic association :sender
What is the correct way of doing this kind of query?
I've also tried to use joins, but I get the same error.
I've found myself a solution, in case anyone else is interested. I ended up using joins with a SQL query:
Conversation.joins("LEFT JOIN owners ON owners.id = conversations.sender_id AND conversations.sender_type = 'Owner'
LEFT JOIN providers ON providers.id = conversations.sender_id AND conversations.sender_type = 'Provider'
LEFT JOIN accounts ON accounts.id = owners.account_id OR accounts.id = providers.account_id").
where('accounts.country' => 'US').limit 5

has_one association with user and customer and rails view form

I've got the an has_one association:
has_one association user -> customer models
will the user have the customer_id or customer will have the user_id attribute?
other question: into my _form i'd like to have a select/option with all the users that hasn't associated with a customer which is the best way to do that?
thanks a lot.
The _id field is always in the model with the belongs_to, and refers to the other table name.
class Customer < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :customer
end
In this case, the customers table will have a user_id field.
For the second question, missing values are found in SQL using outer joins.
The SQL you want would be
select
from users
left outer join customers on users.id = customers.user_id
where customers.id is null
In ActiveRecord, add a scope to your User class.
In Rails 3.x:
class User < ActiveRecord::Base
has_one :customer
scope :missing_customer,
includes(:customer).where("customers.id is null")
end
In Rails 2.3.x:
class User < ActiveRecord::Base
named_scope :missing_customer,
{ :joins => "left outer join customers on users.id = customers.user_id",
:conditions => "customers.id is null" }
end

Ruby on rails querying with join and condition statement

I need to query joining tables without using the primary key(id).
class User < ActiveRecord::Base
has_one :participant
end
class Participant < ActiveRecord::Base
belongs_to :user
end
The User has 'id' and 'name'.
The Participant has 'user_id' which is User.id
I am trying to find the Participant.id by querying with User.name
What I have tried is,
participant_id = Participant.all :joins => :users, :conditions => {:name => "Susie"}
If you're just looking for a specific user's participant id, you could just go:
User.find_by_name("Susie").participant.id
Since your user has a has_one relation to Participant(which belongs to it -- so basically a one-to-one) you can just go call participant on user. ActiveRecord takes care of the join magicks for you
Try the following:
class User < ActiveRecord::Base
has_one :participant
end
class Participant < ActiveRecord::Base
belongs_to :user
scope :foo, lambda {|name|
joins(:users).
where("name = ?", name)
}
end
If you're taking user input you're going to want to probably fix joins so it uses sanitize_sql_array. See here also for some query goodness

Resources