Jay McGavren's Journal

2009-05-06

Notes from RailsConf - Rails 3: Step Off the Golden Path...

Hosted by Matt Aimonetti.

Rails philosophy:
	Convention over configuration
Merb philosophy:
	Performance
	Framework agnosticism
Rails 3 philosophy is also a merger:
	Performance
	Modularity
	Framework agnosticism
What you get:
	Public API (It was closed for Rails 2)
	Mountable apps (mount your blog app in your CMS app)
Default stack:
	ActiveRecord
	Test::Unit
	Prototype
	ERB
But, it's less opinionated:
	Other Javascript frameworks:
		jQuery
		MooTools
		ExtJS
		Yahoo!
	Other templating engines:
		Haml
	Other ORMs (turn DB records into objects):
		DataMapper
		Sequel
		CouchRest
	Other test frameworks:
		Cucumber
		RSpec
When to step off the golden path:
	If your templating, JS, ORM, or performance requirements differ.
	Otherwise, use the default stack- it's real-world tested.
Datamapper:
	Procrastination as a virtue:
		Lazy Loading - Don't pull fields until they're asked for specifically.
		Strategic Eager Loader
		ActiveRecord:
			Student.all.each.books.map {|b| b.name}
			select * from "students"
			select * from books where student_id = "1"
			select * from books where student_id = "2" #etc. This is slow!
		DataMapper:
			Student.all.each.books.map {|b| b.name}
			select id, name from students order by id
			select id, name, student_id from books where
				(student_id in (1, 2, 3, X)) order by id --Faster
	Multiple "repos" (databases)
		Config:
			production:
				adapter: mysql
				database: production-app
				host: localhost
				...
			repositories:
				nightly_backup:
					adapter: sqlite3
					database: shared/nightly.db
				weekly_backup:
					...
		Then set up a task to copy from DB to repo:
			Article.copy(:default, :nightly_backup, :created.gt => 1.day.ago)
		Legacy databases:
			class Page
				include DataMapper::Resource
				property :id, Serial
				property :name, String
				#Specify different fields when talking to legacy database:
				repository(:legacy) do
					property :name, String, :field => "title"
				end
			end
	Query::Path
		#Joins people with addresses, finds records where street column LIKE '%street%'
		Person.all("addresses.street.like" => "%street%")
	Many adapters:
		RDBMS
		file system
		IMAP
		YAML
		SalesForce
		REST APIs
		your API here - write your own.
Sequel
	High performance
	Sharding
	Prepared statements
	Highly customizable SQL statements
Hibernate
	Built in sharding
	ActionORM
	JRuby
	Many Java libraries for legacy databases
Non-RDBMS systems
	AppEngine::DataStore
	CouchRest for CouchDB
	Redis, Tokyo Cabinet, etc...
More customizations available:
	File structure (including very_flat)
	Custom router DSL
	Custom request handlers
		class Presentation < ActionController::Http
			def index
				self.response_body = "Hello!"
			end
		end
		Presentation.action(:index).call(Rack::MockRequest.env_for("/railsconf"))

Read more...
2009-05-06

Notes from RailsConf - Getting to Know Ruby 1.9...

Hosted by David A. Black

1.8.6:
	> Object.new.to_a
	[#<Object...>]
	> "onentwonthree".to_a
	["onen", "twon",...]
1.9:
	> (0..10).to_a
	[1, 2, ...]
	Above 1.8 items don't have .to_a, though.  After all, why *should* an object know how to wrap itself in an array?
	> Array(Object.new) #Array now has the responsibility.
	[#<Object...>]
1.9:
	> "abc".to_i
	0
	> Integer("abc")
	Exception
1.8:
	> {1, 2, 3, 4}
	Hash
1.9:
	> {1 =>2, 3 => 4}
	Have to use hash rockets.
1.8:
	> String.ancestors
	[Enumerable, String, Comparable, ...]
	> "1n2n3".each{|s| puts s}
	1
	2
	3
	> "abcndefnghi".map {|s| s.reverse }
1.9:
	String does not mix in Enumerable
	> "".each
	NoMethodError...
	> "abcndefnghi".lines.each {|l| puts l.upcase}
	> "abcndefnghi".each_line {|l| puts l.upcase} #Equivalent
	> "abcndefnghi".bytes.each {|l| puts l.upcase}
	> "abcndefnghi".code_points.each {|l| puts l}
1.9:
	> str = "Give me 100u20ac"
	"Give me 100<Euro symbol>"
	> str.bytes.to_a.size
	14
	> str.chars.to_a.size #Shorter than .bytes due to Unicode character.
	12
1.8:
	> str = "This isna three-nline string"
	str[6] #Gives the ordinal.  (Kinda hacky...)
	115
	> str[6, 1]
	"s"
1.9:
	> str = "Give me 100u20ac"
	> str[2] #Gives the character (I like this better).
	"v"
	> str[2].ord
	118
	> str[2, 1]
	"v"
	> str[2, 5]
	"ve me"
1.9:
	> h = {:one => 1, :two => 2}
	> h = {one: 1, two: 2, three: 3} #New hash separator!
1.9:
	> link_to "click", controller: "users" #That's a hash as the last argument, braces are optional.
1.8:
	> {1 => 2, 3 => 4, 5 => 6} #Non-deterministic, could give {5 => 6, 3 => 4}
1.9:
	> {5: 6, 1: 2}.each {|k, v| p "#{k}: #{v}"} #Order is deterministic.
	5: 6
	1: 2
1.9:
	Beware: Hash#sort still returns an Array of Arrays, not a re-ordered Hash.  That may change.
	Hash#select still returns a Hash.
1.9:
	Enumerable module has new methods.
	> a = (1 .. 10).to_a
	> a.each_slice(3) {|slice| p slice}
	[1, 2, 3]
	[4, 5, 6]
	...
	[10]
1.9:
	> a.each_cons(3) {|cons| p cons} #Moves result start by 1 index each time.
	[1, 2, 3]
	[2, 3, 4]
	[3, 4, 5]
1.9:
	> a.one? {|i| i == 2}
	false
	> a.all? {|i| i == 2}
	false
	> a.any? {|i| i == 2}
	true
1.9:
	> ('a'..'c').cycle(2)
	#<Enumerator>
	> ('a'..'c').cycle(2).to_a
	['a', 'b', 'c', 'a', 'b', 'c']
	.cycle with no args loops forever.  Fun, but dangerous.
1.8:
	> x = 1
	> [10, 20, 30].each {|x| puts x * 100}
	1000
	2000
	3000
	> x == 30
	true #WTF?  Why not 1?  Wasn't x in the block scoped only to the block?
	> [10, 20, 30].each {|@var| puts @var}
	10
	20
	30
	> @var
	30
1.9:
	> x = 1
	> [10, 20, 30].each {|x| puts x * 100}
	1000
	2000
	3000
	> x
	1 #There we go, it wasn't overwritten.
	[1, 2, 3].each {|@x|}
	SyntaxError: formal argument cannot be an instance variable.  (That's a good thing to me.)

Read more...
2009-05-05

RailsConf notes - Kevin Barnes - In Praise of Non-Fixtured data

Fixtures bad:
	Get highly unmanageable, especially when someone decides to import real data (:user_275, :user_276...)
	Live outside test.
	Can't change loaded values easily.
Factories good:
	Let you use sensible labels and tweak the created data.
	They reduce dependence on external data (manipulate values right in the test).
FactoryGirl:
	http://github.com/thoughtbot/factory_girl/tree/master
	spec/factories/first_model.rb second_model.rb...
	Code:
		Factory.define :user {|f| f.name 'Joe'; f.zip '34279'; f.association :employer}
		Factory(:user).should be_valid
		Factory(:user, :name => nil).should_not be_valid
	.association calls another factory (that you define) to generate associated model object.
Object Daddy:
	http://github.com/flogic/object_daddy/tree/master
	spec/exemplars/*_exemplar.rb
	Code:
		class User
			generator_for :name => 'Test User'
			generator_for :ssn, :start => '12343214' do {|prev| prev.succ}
		end
		@user = User.generate!
		@user.should be_valid
	[Barnes likes ObjectDaddy.  I don't 'cause of modificat
Others:
	machinist
	foundry
	fixjour

Read more...
2009-05-05

Notes from RailsConf - ActiveScaffold BoF session...

Thanks to Mike Gaffney and Kenney Ortmann for hosting this session, and for writing a cool framework!

http://activescaffold.com/

Install:
        script/plugin install
        git://github.com/activescaffold/active_scaffold.git
        Site says to pass -r rails-2.2 option; HEAD works fine for Rails 2.3.

Setting up a quick test app in Rails 2.3:
        Create app/views/layouts/application.html.erb:
                Ensure it contains a default HTML document.
                Ensure it has  in the body.
        Add these lines to the HEAD tag:
                
                
        Create a model with a few fields and a controller.
        On your controller, add:
                active_scaffold :model_name
        Go view the index for the model (no need to create index.html.erb, def
        index, etc.):
                You should have full CRUD, sorting by column, etc.

Customizing:
        ActiveScaffold.set_defaults {|config| ...} in your application
        controller.
        Model-specific settings in individual controllers.
        Override ActiveScaffold's default views by creating a special folder in
        your views directory.

Additional notes:
        Home page doesn't get updated as often as it should, but project is
        being actively maintained and used, and will support Rails 3.0 shortly
        after its release.
        For many-to-many relationships, you may need to have the view reference
        the join model.  See the mailing list.

Had this up and running in 10 minutes:

ActiveScaffold

Read more...
2009-04-22

Notes from Tomas Carillo on effective presentations...

Tomas Carillo spoke on speaking at Gangplank Academy Brownbag today. Here are my notes:

Read more...