We've got our basic has_many through: for Users and Companies.
class User < ActiveRecord::Base
has_many :company_users
has_many :companies, through: company_users
end
class CompanyUser < ActiveRecord::Base
belongs_to :user
belongs_to :company
validates_uniqueness_of :company_id, scope: :user_id
end
class Company < ActiveRecord::Base
has_many :company_users
has_many :users, through: company_users
end
Then we have this CompanyMethods
lib that adds a default_scope
to User (the klass.method_defined(:companies) is only called on User).
module CompanyMethods
def self.extended(klass)
klass.class_eval do
default_scope do
c_ids = Authorization.current_company_ids
includes(:companies).where(companies: { id: c_ids })
end
end
end
end
class User < ActiveRecord::Base
extends CompanyMethods
So when we call User.find_by_email('michael@widgetworks.com')
we get back only users that are scoped by Authorization.current_company_ids
.
Here's the sql:
SELECT DISTINCT `users`.id FROM `users` LEFT OUTER JOIN `company_users` ON `company_users`.`user_id` = `users`.`id` LEFT OUTER JOIN `companies` ON `companies`.`id` = `company_users`.`company_id` WHERE `companies`.`id` IN (4) AND `users`.`email` = 'michael@widgetworks.com' LIMIT 1
All this is fine and dandy for a lot of instances. But here's where it starts to get funky.
When another object, for example a CreditCard calls an association that goes through User, the companies.id
scope gets called on the child object.
class CreditCard < ActiveRecord::Base
has_one :user, through: :user_profile
has_many :orders, through: :user
end
class UserProfile < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
extends CompanyMethods
has_many :orders
end
Here's the sql that it generates:
SELECT `orders`.* FROM `orders` INNER JOIN `users` ON `orders`.`user_id` = `users`.`id` INNER JOIN `user_profiles` ON `users`.`id` = `user_profiles`.`user_id` WHERE `orders`.`company_id` IN (4) AND `companies`.`id` IN (4) AND `user_profiles`.`id` = 47717
credit_card.orders
throws an error because of it's SQL query is calling "companies
.id
IN (4)" on reservation
when it should only be calling it on user
.
I've been able to get around the problem with a hack of instead of using a through
association, I just wrote a method named reservations
on CreditCard.
class CreditCard < ActiveRecord::Base
has_one :user, through: :user_profile
def orders
user.orders
end
end
That pretty much fixes the problem, but it's not a great solution.
Aucun commentaire:
Enregistrer un commentaire