Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to specify a default record for a has_many relationship in rails

I have Accounts and AccountAddressess. An account can have many AccountAddressess and I would like to specify one as the "default_account_address", so in the Account table, I have a column named "default_account_address_id". Here is the current state of the models.

class Account < ActiveRecord::Base
  has_many :account_addresses
  belongs_to :default_account_address,
             :class_name => "AccountAddress",
             :inverse_of => :account_assigned_to_as_default
end

class AccountAddress < ActiveRecord::Base
  belongs_to :accounts
  has_one :account_assigned_to_as_default, 
          :class_name  => "Account", 
          :foreign_key => :default_account_address_id, 
          :inverse_of  => :default_account_address
end

This works fine except for the fact that @account.default_account_address returns an account address and @account.account_addresses returns an empty array.

So, the issue is that the default account address is not included in @account.account_addresses.

Any ideas on the best way to approach this issue? I considered habtm, but it doesn't seem appropriate. I considered using has_one :default_account_address, but this doesn't make sense because the default_account_address_id column is on the account table. Thanks.

like image 641
Shagymoe Avatar asked Apr 06 '11 18:04

Shagymoe


2 Answers

There is probably a better way, but here is something that came to mind:

class Account < ActiveRecord::Base
  has_many :account_addresses

  def default_address
    account_addresses.find_by_default true
  end
end

class AccountAddress < ActiveRecord::Base
  belongs_to :accounts
end

This of course assumes you have a boolean column named default in AccountAddress. I would probably add validation to AccountAddress that would check that there is only 1 AccountAddress marked as default for a given account_id. You could also create a method in AccountAddress that not only marks an address as default, but also unmarks all associated addresses for you.

Like I said, there is probably something better out there, but this should allow the default address to also show in @account.account_addresses.

like image 143
brettish Avatar answered Sep 29 '22 02:09

brettish


Another solution:

class Account < ActiveRecord::Base
  has_many :account_addresses
  has_one :default_account_address, -> { find_by_default true },
          class_name: 'AccountAddress'
end

class AccountAddress < ActiveRecord::Base
  belongs_to :accounts
end
like image 43
Corentin Geoffray Avatar answered Sep 29 '22 02:09

Corentin Geoffray