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 Acco开发者_高级运维unt < 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.
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.
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
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.
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".
This gem set_as_primary solves the same issue but in a different way.
精彩评论