ehannes
ehannes

Reputation: 509

Rails - has_one association to one of two possible models

A question about Rails association, where a has_one association is to one of two possible models. Like a polymorphic association, but the other way around.

So I have two different kinds of bank accounts, both belongs to UserConfig:

class SwedishBankAccount
  belongs_to :user_config
end

class ForeignBankAccount
  belongs_to :user_config
end

The question is how to manage this in my UserConfig. It should have a has_one association to either SwedishBankAccount OR ForeignBankAccount, but not to both.

Upvotes: 2

Views: 1765

Answers (4)

ehannes
ehannes

Reputation: 509

Having an association to an abstract class, as zishe was suggesting, was unfortunately no good idea (see comments on that answer). Vishal JAIN's answer will work, but I think it will make it harder to get a correct picture of the architecture because of the change of ownership.

I ended up having associations to both types of bank accounts. An ugly solution, but it was the best I could come up with. If anyone else have a better idea, please share your thoughts! :)

class UserConfig < ActiveRecord::Base
  has_one :swedish_bank_account
  has_one :foreign_bank_account

  enum bank_account_type [:swedish_bank_account, foreign_bank_account]

  # Returns bank account of type determined by bank_account_type.
  # Returns nil if no account is associated.
  def bank_account
    return swedish_bank_account if swedish_bank_account?
    return foreign_bank_account if foreign_bank_account?
  end
end

Upvotes: 1

Vishal Jain
Vishal Jain

Reputation: 1940

You can use ploymorphic relationship. Add target_id and target_type column in UserConfig model

class UserConfig < ActiveRecord::Base
  belongs_to :target, :polymorphic => true
end

Then you just use for model SwedishBankAccount As

class SwedishBankAccount < ActiveRecord::Base
  has_one :user_config, :as => :target
end

And in model ForeignBankAccount As

class ForeignBankAccount < ActiveRecord::Base
  has_one :user_config, :as => :target
end

Upvotes: 2

Alexander Kireyev
Alexander Kireyev

Reputation: 10825

You can create abstract class BankAccount for this models:

class BankAccount < ActiveRecord::Base
  self.abstract_class = true
  belongs_to :user_config
end

class SwedishBankAccount < BankAccount
end

class ForeignBankAccount < BankAccount
end

class UserConfig < ActiveRecord::Base
  has_one :bank_account
end

Here will be no table for BankAccount, but you can put there common parts of your models.

Upvotes: 1

saadlulu
saadlulu

Reputation: 1395

you can create a new model called account with user_id being a primary key "no duplicates" and an account_id that points to his record in either ForeignBankAccount or SweditshBankAccount.

This way you will make sure no users will have more than 1 account at a time.

Upvotes: 0

Related Questions