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

4

8

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.

Circassia answered 6/4, 2011 at 18:37 Comment(0)
P
6

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.

Paediatrics answered 6/4, 2011 at 20:17 Comment(0)
B
4

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
Botanize answered 9/6, 2019 at 18:53 Comment(1)
Better answer, this approach allows to use relational mecanisms, such as accepts_nested_attributes_for :default_account_addressCroat
C
0

I don't know if this is best practice, however, I would just add an attribute "mainaddress" to the table and use just has_many/belongs_to in the relations. Into the account model I would put a function that fetches the main address using a simple query where mainaddress is true.

Chinchin answered 6/4, 2011 at 18:55 Comment(0)
F
0

Another idea is to use https://github.com/swanandp/acts_as_list and then treat default address as the top one, then, setting some address as default would be as simple as:

address.move_to_top if params[:set_as_default]

Especially if all you need is to show it the first in some list or combo box. Querying default address is also easy, since it always first in the scope of "position".

Frenum answered 21/11, 2013 at 18:11 Comment(1)
Or just timestamp set_as_default_at and then special scope, to make the latter winFrenum

© 2022 - 2024 — McMap. All rights reserved.