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...
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...
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...
Notes from RailsConf - ActiveScaffold BoF session...
Thanks to Mike Gaffney and Kenney Ortmann for hosting this session, and for writing a cool framework!
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:
Read more...Notes from Tomas Carillo on effective presentations...
Tomas Carillo spoke on speaking at Gangplank Academy Brownbag today. Here are my notes:
Read more...