Given the pain you'll experience when you start to navigate the byzantine requirements of PCI compliance, I think "best practices" in this area is not to handle payment processing in the first place.
At least, not within your application.
Stripe is an online payment processor geared toward developers. It's a breeze to accept credit card payments through their API, and it offloads responsibility (and liability) for PCI regulation issues to someone else. Which is a Good Thing.
There's even a Railscasts episode all about using Stripe to handle payments, and the stripe-rails gem will bootstrap the process for you.
Oh, and Stripe handles periodic billing (for subscriptions) for you.
Before you head down this road, I highly recommend taking a look at available technologies you might leverage. Although the code for payment processing is often fairly straightforward, the liability issues are massive.
P.S. I don't work for Stripe or anything. I just think their product/service is excellent, and a good match for your use case.
I think what you are looking for at a SQL conceptual level is a junction table (map, link, resolver, pivot are also common names for handling many to many relationships). These junction tables are generally intermediary tables; however, additional attributes can and are often added to them.
The intention of the stated pseudo schema is a bit murky, but I think what you intended is that items can require multiple skills; items can also require other items, each with their own required skills, possibly own requisite items, and so and so forth, to many levels deep. Beware of circular references in your [many-to-many] self-referencing relationships, such as what could happen in 'containerItemMaps'. The following pseudo schema reflects how I envision the OP intent:
items (itemId PK, itemName, weight, volume, price)
skillMaps ( (itemId, skillId) PK)
skills (skillId PK, skillName)
containerItemMaps ( (containerItemId, componentItemId) PK)
-- containerItemId is the parent/requiring item id
-- componentItemId is the child/required item id
ActiveRecord terminology suggests 'has_and_belongs_to_many' as the type of association a relationship in a data model to use in this situation. For more information you may want to look at the page at datamapper.org Associations. Specifically the sections titled 'Has, and belongs to many (Or Many-To-Many)' and 'Self referential many to many relationships'
Because I am not a ruby guy at this point, I can only muddle with ruby code to give an example, but this is my best approximation of what your item class would look like:
# revised
class Item
include DataMapper::Resource
property :id, Serial
property :name, String, :required => true
property :weight, Float
property :volume, Float
property :price, Float
has n, :componentMaps, :child_key => [:container_id]
has n, :components, self, :through => :componentMaps, :via => :component
has n, :skillMaps, :child_key => [:skill_id]
has n, :skills, :through => :skillMaps, :via => :skill
end
And the map table for self-referencing many to many items, eg.. required items:
#revised
class ComponentMap
include DataMapper::Resource
belongs_to :container, 'Item', :key => true
belongs_to :component, 'Item', :key => true
property :quantity, Integer, :default => 1
end
For completeness:
class SkillMap
include DataMapper::Resource
belongs_to :item, 'Item', :key => true
belongs_to :skill, 'Skill', :key => true
property :mastery, Enum[:none, :aprentice, :journeyman, :craftsman, :master ], :default => :none
end
class Skill
include DataMapper::Resource
property :id, Serial
property :name, String, :required => true
has n, :skillMap, :child_key =>[:skill_id]
end
Revisions:
Noting your concerns, I went and installed an interpruter and debugger to verify the code compiled and the emitted sql was more ideal. Originally, I only was going off cursory examination of documentation. The structures above should produce generally well-structured sql from the mappings.
No matter which fields and structures you use, and no matter which ORM you pick (datamapper or some other provider), you will want to run the code through the debugger and pay attention to the sql it emits as sometimes the mappings aren't necessarily what you might first expect.
A second note about the junction tables (skillMap and componentMap): note my inclusion of additional fields (quantity and mastery). These seem to be a natural fit for the kind of application originally described, even though not originally specified. In a recipe, some ingredients are common among many different combinations, however the quantity from recipe to recipe varies. For skills, like ingredients, the skill level needed to perform certain activities varies, and thus I added a mastery field to the junction table skillMap.
Of course, you probably want to add appropriate business rules and helper functions (for accessing the composition of collections programmattically such as adding and removing elements, adding and removing groups of elements, and so on).
Hopefully this demonstrates a bit better a reason why you may want to consider and use the junction table over a straight hash. Of course each specific application is different, and perhaps the ability to specify additional aspects of the relationship between items and skill and items and other items isnt needed in your case.
Having and utilizing the extra control in defining the relationships explicitly has many advantages over relying on a dynamic/magic mapping. In some cases, I feel it is really needed, and I think in the case of a many-to-many, this is demonstrated. For one-to-many, the relationship is easier to infer, and using a more dynamic method of generating the mappings (eg. has n, : <attribute group>, :through => Resource) would be acceptable.
Best Answer
You're currently working on the User model within ruby as you look down you code you can see
def function
end
That creates a function that exists within the User class, so in theory from most anywhere else in your application you could do User.some_function, you only use self.some_function from within the class.
There isn't any difference between using User.encrypt and self.encrypt except that its safer, self.function means only look inside the current class.
I think you're probably getting attributes and functions mixed up because you're not seeing the () at the end of function calls, you don't actually use those in ruby unless you passing parameters to the function.
Where you're mentioning username, password, email etc those are fields associated with the database and are attributes.
The concept to understand here is that the User model represents the association with the underlying database, you can(as you have there) add extra functionality to ensure the quality of the data going in for example:
That means that if ANYWHERE within you application you create a new user the model calls that function as part of the process of creating the record. Essentially by building functionality into models you can ensure that all data going into the database is treated in the same way.