Fixtures are database independent written in YAML. There is one file per model. They live in test/fixtures
.
Can be generated by an ERB.
In Ruby some methods have a question mark (?) that ask a question like include? that ask if the object in question is included, this then returns a true/false.
In general, methods that end in ! indicate that the method will modify the object it's called on. Ruby calls these "dangerous methods" because they change state that someone else might have a reference to. Here's a simple example for strings:
Speical column names:
- created_at
- updated_at
- lock-version -- support for optimistic locking
- type -- for Single Table Inheritence
- (association_name)_type -- Polymorphic associations
- (table_name)_count - Used to cache the number of objects in a relation.
TODO -- https://github.com/bbatsov/ruby-style-guide TODO -- https://github.com/airbnb/javascript
TODO
Need to be registered in the ActiveRecord Model
3.1 Creating an Object
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit/after_rollback
3.2 Updating an Object
before_validation
after_validation
before_save
around_save
before_update
around_update
after_update
after_save
after_commit/after_rollback
3.3 Destroying an Object
before_destroy
around_destroy
after_destroy
after_commit/after_rollback
Use cases:
- Destroying related objects.
- Validating constraints before commiting to DB
- Pub/sub (I can only assume)
In Rails, the state of the database is managed via rake
. This allows for decoupling of database language from database schema. And an easy way for individual contributors to keep their databases in sync.
Notable files:
db/schema.rb
config/database.yml
Migrations (at least the ones generated by ActiveRecord::Migration
) as reversible. You can make your own migraitions reversible by adding an up
and down
method.
Create migrations with:
$ bin/rails generate migration AddPartNumberToProducts part_number:string:index
If the migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" and is followed by a list of column names and types then a migration containing the appropriate add_column and remove_column statements will be created
HABTM == Has and belongs to many relatinoships. You can create one with
create_join_table :products, :categories
You can manage indexes, column types and lengths, and foreign keys via Migrations..
You can execute arbitraty SQL when needed. Great power, great responsibility, right?
Product.connection.execute('UPDATE
productsSET
price=
free WHERE 1')
Execute Migrations as follows:
$ bin/rake db:migrate
or roll them back:
$ bin/rake db:rollback
Set up the database with
rake db:setup
or db:drop db:setup
Active models is a library that allows you to build various patterns from Active Record into non-Active Record based Ruby objects. A la carte style baby!
Support for
- custom prefixes and sufficeses on methods of the class.
- active record style callbacks
- conversation between types
- dirtying objects (ie.
ActiveModel::Dirty
means itd needs to be saved to persistence layer) ActiveModel::Validations
- naming (ie. singular vs plural, routing, internationalization support)
- serialization
- translation
- lint testing
ActiveModel::SecurePassword
support
If you're manipulating data before passing it to the model, you could create your own getter and setters.
a la
@user = User.new(params[:user])
@user.first_name, @user.last_name = params[:user][:full_name].split(" ", 2)
should be
def full_name=(value)
self.first_name, self.last_name = value.to_s.split(" ", 2)
end
Rails has support for i18n translations if you maintain a YAML file of ttranslations.
- Devise
- Pundit
- Slim
- Active Model Serializers
- Rspec
- Guard
- SimpleCov
- RbEnv
Devise is an authentication solution for Rails. It handles encryption / storage of passwords, confirmiation emails, reset password emails, registrations, remembering users, basic sign in metrics, and acccount locking!
Pundit handles authorization.
Pundit is built around policies ( stored in app/policies
). Policies are ruby classes that manage what permissions a user (usually) has.
Templating system for views. Elegant way for containing ruby logic and html inline
AMS brings some conventions into JSON generation.
Composed of serializers and adapters:
- Serializers describe which attributes and relationships should be seialized.
- Adapters describe how attributes / relationships should be serialized
In controllers, if you use render :json
, Rails will search for the serializer (ie. ActiveModel::Serializer.config.adapter = ActiveModel::Serializer::Adapter::JsonApi
) and use it.
Rspec is a gem that allows you to write tests around use cases that the business can describe. It's been described as a BDD testing framework.
Run tests with
rspec hash_spec.rb
An Example test, built around a hash class:
`` `describe Hash do before do @hash = Hash.new({:hello => 'world'}) end
it "should return a blank instance" do Hash.new.should == {} end
it "hash the correct information in a key" do @hash[:hello].should == 'world' end end
### Guard
Guard is a command line tool that can trigger events on file system modifications. Can be configured to run tests and/or regenerate docs based upon a `Guardfile`.
### SimpleConv
SimpleConv is a code coverage analylsis tool for Ruby. It gives both source file level coverage views and statistical:


# Misc
[Dry Principle](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself) -- Don't repeat yourself. Every piece of knowledge must have asingle, unambiliguious authoriatative representation in the system. Put another way
* A modification of any single element of a system doe snot require q change in other logically unrelated elements.
* Conversely, elements that *are* logically related change predictably and uniformly.
* By convention, heavy reliance on methods, subroutines (sometimes stubbed via code generators)
Other languages don't encourage duplicate code per say, but DRY is meant to be extreme in that anything that *could* be duplication (functions declared seperately in headers / bodies, seperate declaration of database tables / objects) are automated away using teh framework.
[Behaviour Driven Development](http://en.wikipedia.org/wiki/Behavior-driven_development) -- Combines TDD with ideas from domain-driven design. Output is a shared process that software dev and management teams and use to collab on software dev.
[Domain Driven Design](http://en.wikipedia.org/wiki/Domain-driven_design) --
* Place the project's primary focus on the domain.
* Base complex designs on model of domain
* Initiating a reative collaboration between technical and domain experts to iteratively refine a conceptual model to address domain problemes.
Domain - can be an existing business. New idea. It's a subject matter you're building software around.
### RbEnv
RBEnv is a ruby version manager that allows teammates to have multiple apps running different versions of ruby. The ruby version dependancy lives in your app, so upgrades/rollbacks are atomic. It's *one thing well* is switching between ruby versions.
RBenv works by intercepting Ruby commands and passing them to shim (note: shims are small libraries that intercept calls and maybe change arguments) executables in your `PATH`. Here's an example rbenv shim path: `~/.rbenv/shims`
*Rehashing* is a process that maintains the the shims in that directory.
RBEnv manages several executables which would have been stored in a common dir like `/usr/bin`, like `gem`,`rake`,`rails`, `ruby` and more..
#### Rbenv vs rvm
Rvm has been called the 'most hated, but most used' version manager. Rvm was first to market, but manages rubies globally, potentially causing conflicts between projects.
## [Mike's DDD talk](https://www.youtube.com/watch?v=B7pXxMJAze0)
--
Over time, your domain grows. More team members. Things slow down, there are more defects. You end up a with a large monolithic app and it'ts hard to get anything done.
DDD addresses the faact that software becomes complex quickly.
## Mike's topics
1. Defining the domain.
2. Communicating the domain
3. Relationships between models
4. Aggregates
5. Data access
6. Value Objects
7. Domain Services
### Defining the domain.
Brainstorm -- Comes up with the relational model.
Then you refine via asking questions.
* [ie. whhats the difference between a developer and a company?](http://bits.owocki.com/image/3b1y2R3z1d0V/Image%202015-05-07%20at%209.50.13%20AM.png) -- Instead of developer, lets call them a seller.
* Whats the diff between a version and a release? Release is a better word.
* Comments vs Reviews
Communicating the domain
Roles in a room:
* Domain expert - should object to terms or structures that are awkward or inadequate to convey domain understanding.
* Software Expert - should watch for ambiguity or inconsistency that'll trip up design.
Uniquitious llanguage -- a common rigorous langauge between developers and users. Should be common across
user, product owneer, domain expert, tester, designer, developer, code
Risk of doing this is that langauge is fragmented and translations have to happen in order for team members to talk to each other.
3. Relationships
* [Customer is primary because a customer would (in transactional database) need to know how many apps they have](http://bits.owocki.com/image/3e1M0q2L3Q2C/Image%202015-05-07%20at%209.55.49%20AM.png)
* Look for was to reduce relationships. Find the ones that need to be there, not just hte ones that can be there.
[Actions that can be taken should be built into their own methods](http://bits.owocki.com/image/1M3Y0x3e2b13/Image%202015-05-07%20at%209.58.45%20AM.png) <== complexity will be built into (and managed within) this method
4. Aggregate -- A pattern in which a cluster of domain objects can be treated as a single unit. One component object will be aggregate root (also a domain object), the root ensures the integrity of the aggregate as a whole. Aggregates are the basic element of transfer of data storage. [Mikes example](http://bits.owocki.com/image/2r3n172u1S0j/Image%202015-05-07%20at%2010.02.09%20AM.png)
5. Data Access
* Use [scopes](http://bits.owocki.com/image/1a2e3P392u2u/Image%202015-05-07%20at%2010.03.18%20AM.png)
* Fig Leafs -- privatizes the where clasue so that developers remember that they should only use WHERE clauses in scopes.
Aggregate roots ar the domains only point of entry for data access.
[In mikes example, structure your subfolders in model dir by aggregate root](http://bits.owocki.com/image/432j3F2W0z2o/Image%202015-05-07%20at%2010.06.29%20AM.png)
6. Value Objects
Two types of domain objects
* Entity -- A thing (customer)
* Value object -- Describes a thing (Name)
Entities are
* unique independent of attributes
* has a lifecycle
* can change statete
Whereas Value objects can be
* immutable
* dont reference anything
* avoid design complexities of entites
As you define your model, values should fall into place around entities.
[Mikes example](http://bits.owocki.com/image/3S1p3A080O1R/Image%202015-05-07%20at%2010.11.26%20AM.png)
How to manage value objects in code (in mikes example, at least)
* Doesnt inherit from anything
* Attributes are read only
* override `:eql?`
* Factory methods (a la `next_major_version` in example)
3 ways to persist value objects
1. Inline on entities table
2. Serialized on entities table
3. In it's own table ([youd have to make it readonly though](http://bits.owocki.com/image/0G3L0S2U1u2Q/Image%202015-05-07%20at%2010.17.34%20AM.png)[2](http://bits.owocki.com/image/1D1u1j442R0C/Image%202015-05-07%20at%2010.17.51%20AM.png))
7. Domain Services
Domain Services -- What if you need to process a transaction between aggregates? That's what domain services are for!
If you gift an app in Mike's example app store, you
1. Charge the gifter
2. Assign access rights to the giftee
We'll write a domain service that handles this!
[Code Example of a GiftApp](http://bits.owocki.com/image/040R0d0m1r33/Image%202015-05-07%20at%2010.20.37%20AM.png)
Lives in a `app/services/` directory. [screenshot](http://bits.owocki.com/image/1r2I3q3g0x3D/Image%202015-05-07%20at%2010.21.10%20AM.png)
#Best practies
10k feet
* Pull Request Code Review
* CI
* Test-driven
* DRY
* Package your code into gems and plug-ins.
* API-drive your code
1k feet
* Style guide
* Fat model, skinny controller
* Implement built-in Ruby Duck Typing Methods (ie. `user.to_s`)
Lists from around the web:
* http://www.sitepoint.com/10-ruby-on-rails-best-practices/
#Resource List
## Books
* Domain Driven Design by Eric Evans
* Clean Ruby by Jim Gay