Hi,
I have a table containing system account types ("Income",
"Ordered",
"Available" etc) which are created as seed data during application
installation.
class InventoryAccountType < ActiveRecord::Base
has_many :inventory_accounts
enumerable_constant :normal_balance, :constants => [:debit, :credit]
validates_uniqueness_of :name
# system account types
def self.income
find_by_name("Income")
end
def self.ordered
find_by_name("Ordered")
end
def self.available
find_by_name("Available")
end
end
These account types represent system concepts that are referenced in
code elsewhere in application, for example:
class InventoryTransaction < ActiveRecord::Base
has_many :inventory_account_entries
validate :account_entries_balance
# locate new inventory
def self.create_inventory(product_sku, storage_location, quantity,
inventory_batch = nil)
# if no batch specified, create a new batch
if inventory_batch.nil?
inventory_batch = InventoryBatch.create(:product_sku =>
product_sku)
end
product_income_account = InventoryAccount.retrieve_by_type
(product_sku, InventoryAccountType.income)
available_product_location_account
InventoryAccount.retrieve_by_location(inventory_batch,
storage_location, InventoryAccountType.available)
account_transfer(product_income_account,
available_product_location_account, quantity)
end
end
Do you think this approach to hardcoding record lookups into the
InventoryAccountType model in such a way is good practice?
There may be other InventoryAccountTypes created by the user during
application usage but these would be only be managed and allocated to
by the user as general account transfers. Not by system core system
use cases such as creating new inventory as addressed by it own
methods in the model.
I have also added a "system" boolean column to the
InventoryAccountType table so as to know which types cannot be deleted
or edited.
I was also thinking of replacing the:
def self.available
find_by_name("Available")
end
...style methods for each system type with some of dynamic ruby method
that automatically creates a method for any database record that has
system == 1. This would save having to clutter the
InventoryAccountType model with multiple method definitions doing the
same thing.
Thanks in advance, Andrew.
Tom Z Meinlschmidt
2009-May-07 00:06 UTC
Re: Hardcode database record reference into model
hi,
I think you should use named_scope instead of this kind of access...
class InventoryAccountType < ActiveRecord::Base
named_scope :income, :conditions => {:name =>
''Income''}
named_scope :ordered, :conditions => {:name =>
''Ordered''}
end
you can use it the same way but you can chain scopes.. eg
data = InventoryAccountType.income.ordered
in your case (with def.self methods) is that not possible
tom
Andrew Edwards wrote:> Hi,
>
> I have a table containing system account types ("Income",
"Ordered",
> "Available" etc) which are created as seed data during
application
> installation.
>
> class InventoryAccountType < ActiveRecord::Base
>
> has_many :inventory_accounts
> enumerable_constant :normal_balance, :constants => [:debit, :credit]
>
> validates_uniqueness_of :name
>
> # system account types
>
> def self.income
> find_by_name("Income")
> end
>
> def self.ordered
> find_by_name("Ordered")
> end
>
> def self.available
> find_by_name("Available")
> end
>
> end
>
> These account types represent system concepts that are referenced in
> code elsewhere in application, for example:
>
> class InventoryTransaction < ActiveRecord::Base
>
> has_many :inventory_account_entries
> validate :account_entries_balance
>
> # locate new inventory
> def self.create_inventory(product_sku, storage_location, quantity,
> inventory_batch = nil)
>
> # if no batch specified, create a new batch
> if inventory_batch.nil?
> inventory_batch = InventoryBatch.create(:product_sku =>
> product_sku)
> end
>
> product_income_account = InventoryAccount.retrieve_by_type
> (product_sku, InventoryAccountType.income)
> available_product_location_account >
InventoryAccount.retrieve_by_location(inventory_batch,
> storage_location, InventoryAccountType.available)
>
> account_transfer(product_income_account,
> available_product_location_account, quantity)
> end
> end
>
> Do you think this approach to hardcoding record lookups into the
> InventoryAccountType model in such a way is good practice?
>
> There may be other InventoryAccountTypes created by the user during
> application usage but these would be only be managed and allocated to
> by the user as general account transfers. Not by system core system
> use cases such as creating new inventory as addressed by it own
> methods in the model.
>
> I have also added a "system" boolean column to the
> InventoryAccountType table so as to know which types cannot be deleted
> or edited.
>
> I was also thinking of replacing the:
>
> def self.available
> find_by_name("Available")
> end
>
> ...style methods for each system type with some of dynamic ruby method
> that automatically creates a method for any database record that has
> system == 1. This would save having to clutter the
> InventoryAccountType model with multiple method definitions doing the
> same thing.
>
> Thanks in advance, Andrew.
>
--
==============================================================================Tomas
Meinlschmidt, MS {MCT, MCP+I, MCSE, AER}, NetApp Filer/NetCache
www.meinlschmidt.com www.maxwellrender.cz www.lightgems.cz
===============================================================================
On Thursday 07 May 2009, Andrew Edwards wrote:> I have a table containing system account types ("Income", "Ordered", > "Available" etc) which are created as seed data during application > installation.The never-ending enumeration story. For my take on it see (without line break, with hyphen): http://www.schuerig.de/michael/blog/index.php/2009/04/02/simplistic- enums/ I notice that my caching mechanism would get in the way of your requirement to have "non-managed" enumeration values.> These account types represent system concepts that are referenced in > code elsewhere in application, for example: > > class InventoryTransaction < ActiveRecord::Base[snip] With the enums implementation linked above, I''m handling a similar case like this: class InventoryAccountType < ActiveRecord::Base has_many :inventory_accounts enumerates do |e| e.value :name => ''income'', :title => ''Income'' e.value :name => ''ordered'', :title => ''Ordered'' e.value :name => ''available'', :title => ''Available'' end end class InventoryAccount < ActiveRecord::Base belongs_to :inventory_account_type InventoryAccountType.each_name do |name| named_scope "of_#{name}_type", :joins => :inventory_account_type, :conditions => { :inventory_account_types => { :name => name } } end end Then you can do thinks like InventoryAccount.of_income_type.find(...) Without the trickery, you could define a parameterized scope like this class InventoryAccount < ActiveRecord::Base belongs_to :inventory_account_type named_scope :of_type, lambda { |type| :joins => :inventory_account_type, :conditions => { :inventory_account_types => { :name => type } } } end And use it as InventoryAccount.of_type(:income).find(...) Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/
Thanks Tom,
I''ve just tried using method_missing to generate the methods, but
thinking about it your named_scope suggestion might have future value,
chaining etc. Also, I think the named_scope might be a bit more self
documenting and helps enforce nothing gets missed or forgotten about.
# dynamically create lookup method for any system account type
def self.method_missing(method)
if account_type = find(:first, :conditions => { :name =>
method.to_s, :system_type => true })
account_type
else
super
end
end
Thanks, Andrew.
On 7 May, 01:06, Tom Z Meinlschmidt
<to...-ooGa/4BNRfSw0JuIXryQZA@public.gmane.org>
wrote:> hi,
>
> I think you should use named_scope instead of this kind of access...
>
> class InventoryAccountType < ActiveRecord::Base
> named_scope :income, :conditions => {:name =>
''Income''}
> named_scope :ordered, :conditions => {:name =>
''Ordered''}
> end
>
> you can use it the same way but you can chain scopes.. eg
>
> data = InventoryAccountType.income.ordered
>
> in your case (with def.self methods) is that not possible
>
> tom
>
>
>
>
>
> Andrew Edwards wrote:
> > Hi,
>
> > I have a table containing system account types ("Income",
"Ordered",
> > "Available" etc) which are created as seed data during
application
> > installation.
>
> > class InventoryAccountType < ActiveRecord::Base
>
> > has_many :inventory_accounts
> > enumerable_constant :normal_balance, :constants => [:debit,
:credit]
>
> > validates_uniqueness_of :name
>
> > # system account types
>
> > def self.income
> > find_by_name("Income")
> > end
>
> > def self.ordered
> > find_by_name("Ordered")
> > end
>
> > def self.available
> > find_by_name("Available")
> > end
>
> > end
>
> > These account types represent system concepts that are referenced in
> > code elsewhere in application, for example:
>
> > class InventoryTransaction < ActiveRecord::Base
>
> > has_many :inventory_account_entries
> > validate :account_entries_balance
>
> > # locate new inventory
> > def self.create_inventory(product_sku, storage_location, quantity,
> > inventory_batch = nil)
>
> > # if no batch specified, create a new batch
> > if inventory_batch.nil?
> > inventory_batch = InventoryBatch.create(:product_sku =>
> > product_sku)
> > end
>
> > product_income_account = InventoryAccount.retrieve_by_type
> > (product_sku, InventoryAccountType.income)
> > available_product_location_account > >
InventoryAccount.retrieve_by_location(inventory_batch,
> > storage_location, InventoryAccountType.available)
>
> > account_transfer(product_income_account,
> > available_product_location_account, quantity)
> > end
> > end
>
> > Do you think this approach to hardcoding record lookups into the
> > InventoryAccountType model in such a way is good practice?
>
> > There may be other InventoryAccountTypes created by the user during
> > application usage but these would be only be managed and allocated to
> > by the user as general account transfers. Not by system core system
> > use cases such as creating new inventory as addressed by it own
> > methods in the model.
>
> > I have also added a "system" boolean column to the
> > InventoryAccountType table so as to know which types cannot be deleted
> > or edited.
>
> > I was also thinking of replacing the:
>
> > def self.available
> > find_by_name("Available")
> > end
>
> > ...style methods for each system type with some of dynamic ruby method
> > that automatically creates a method for any database record that has
> > system == 1. This would save having to clutter the
> > InventoryAccountType model with multiple method definitions doing the
> > same thing.
>
> > Thanks in advance, Andrew.
>
> --
> ===========================================================================
===> Tomas Meinlschmidt, MS {MCT, MCP+I, MCSE, AER}, NetApp Filer/NetCache
>
> www.meinlschmidt.com www.maxwellrender.cz www.lightgems.cz
> ===========================================================================
====