0

We've got our basic has_many through: for Users and Companies.

class User < ActiveRecord::Base
  extends CompanyMethods
  has_many :company_users
  has_many :companies, through: company_users

  has_many :orders
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:

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

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

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.

Miriam H.
  • 671
  • 2
  • 8
  • 25
  • Maybe I'm misunderstanding something, but it looks like there are 2 different User {} models defined with the same name. Is this just for the example? – Elvn Apr 13 '15 at 21:18
  • @ValerieAsensio Sorry. That was just for example. Hopefully it's clearer now. – Miriam H. Apr 13 '15 at 21:41

0 Answers0