O documento discute algumas limitações do Active Record no Rails 2 e formas de contorná-las, como usar gems para melhorar o suporte a constraints no banco de dados, mapear chaves compostas e SQLs arbitrários para objetos, e alternativas como o Sequel.
2. Algumas Limitações do AR no Rails 2
Uso de funções e constraints no banco é ignorado
Chaves compostas estão fora de questão
Não podemos encadear finds
Não podemos mapear SQLs arbitrários em objetos
3. Como conviver com o Rails 2
Melhorar o suporte a constraints no banco
gem install sexy_pg_constraints
config.active_record.schema_format = :sql
Ex.:
create_table :books do |t|
t.text :title, :null => false
t.text :isbn, :null => false
t.timestamps
end
constrain :books do |t|
t.title :alphanumeric => true, :length_within => 3..50
t.isbn :unique => true, :blacklist => %w(badbook1 badbook2)
end
5. Em último caso...
O comando execute nas migrations é seu amigo :)
Para isso não esqueça de utilizar:
config.active_record.schema_format = :sql
6. Chaves compostas
http://compositekeys.rubyforge.org/
gem install composite_primary_keys
require 'composite_primary_keys' # environment.rb
Ex.:
require 'composite_primary_keys'
class Book < ActiveRecord::Base
set_primary_keys :id, :isbn
end
Book.find(1, 'isbncode')
7. Chaves compostas
Também adiciona suporte a FKs compostas
E podemos criar rotas com chaves compostas, como:
/controller/show/123000,ISBN123456
8. Não podemos encadear finds
Usar named_scopes
Eles podem ser encadeados
Usar conditions:
Book.find(:all, :conditions => " id = 1 OR title ~* 'a' ")
Usar o find_by_sql:
Book.find_by_sql("SELECT * FROM books ... ")
9. Mapeando SQLs para objetos
Podemos usar o find_by_sql
Solução muito frágil para junções, projeções, uniões,
etc...
Para JOINs temos o :include e o :joins
Book.all(:include => :sales)
SELECT * FROM "books"
SELECT "sales.*" FROM "sales"
WHERE ("sales".book_id IN (1,2,3,4))
ORDER BY created_at asc)
10. Mapeando SQLs para objetos
Para JOINs temos o :include e o :joins
Book.all(:joins => :sales)
SELECT "books".*
FROM "books"
INNER JOIN "sales"
ON "books".id = "sales".book_id
11. Mapeando SQLs para objetos
Utilizar visões
Começamos pela migration:
execute "
CREATE OR REPLACE VIEW book_sales AS
SELECT
b.id AS book_id,
s.id as sale_id,
b.title, count(s.*)
FROM
books b JOIN sales s ON s.book_id = b.id"
12. Mapeando SQLs para objetos
Depois criamos um modelo para a nossa visão:
class BookSale < ActiveRecord::Base
belongs_to :book
belongs_to :sales
end
13. Extensões para o PG no AR
https://github.com/softa/activerecord-postgres-hstore
Suporte ao tipo HStore do PostgreSQL para dados com
atributos dinâmicos
https://github.com/tenderlove/texticle
Suporte ao mecanismo de FTS
Suporte ao módulo pg_trgm para comparação de
trigramas
https://github.com/funny-falcon/activerecord-postgresql-
arrays
Suporte ao tipo array de inteiros
https://github.com/afair/postgresql-cursor
Uso de cursores no PostgreSQL
14. Melhorias no Rails 3
O AR 3 agora entende o conceito de relações! (Arel)
Posso aplicar uma operação sobre um objeto que
representa uma relação e o retorno será uma nova relação
15. Por que migrar para o Rails 3?
Encadeamento de operações
Book.where('id = ?', 0).where("title ~ ? ", 'a')
Inclusive com JOINS
Book.where('books.id = ?', 0).joins(:sales)
Conversão de objeto relação para SQL
Book.where('books.id = ?', 0).joins(:sales).to_sql
Tudo carregado para arrays de forma "lazy"
Para mais info vejam:
http://m.onkey.org/2010/1/22/active-record-query-
interface
16. Por que migrar para o Rails 3?
Possibilita o uso de ORMs alternativos como o excelente
Sequel:
http://sequel.rubyforge.org/
O Sequel ainda é bem mais completo que o AR 3, um ORM
com a perspectiva de quem entende SQL.
Outra opção interessante é o DataMapper (esse fica para
outra palestra)
17. Algumas vantagens do Sequel
Permite operações como UNION, INTERSECT e EXCEPT
Suporta CTE (consultas com WITH e WITH RECURSIVE)
Permite mostrar todos os SQLs gerados pelo ORM
19. Utilizando o Sequel com o Rails 3
Adicionar ao Gemfile
gem 'sequel-rails'
Executar
bundle install
20. Utilizando o Sequel com o Rails 3
Modifique o arquivo config/application.rb de
...
require 'rails/all'
...
para
...
#require 'rails/all'
require "action_controller/railtie"
require "sequel-rails/railtie"
require "action_mailer/railtie"
require "rails/test_unit/railtie"
...
21. Utilizando o Sequel com o Rails 3
Qualquer plugin do rails que utilize diretamente o AR deve
ser trocado por um equivalente para o Sequel
Por exemplo:
Paperclip para sequel é a gem: sequel_paperclip
22. Diferenças entre Sequel e AR
Nomes de adptadores podem mudar (database.yml)
AR:
adapter: postgresql
Sequel
adapter: postgres
23. Diferenças entre Sequel e AR
Migration no AR:
create_table :menu_items do |t|
t.text :name, :null => false
t.text :description, :null => false
end
Migration no Sequel
create_table :menu_items do
primary_key :id
Text :name, :null => false
Text :description, :null => false
end
24. Diferenças entre Sequel e AR
Qual valor é inserido na coluna quando eu não informo
nenhum valor no método create?
AR
NULL
Sequel
DEFAULT
25. Diferenças entre Sequel e AR
Métodos find*
AR (procura por id)
MenuItem.find 1
Tenho métodos find_by_
Sequel (exige o campo e valor de busca)
MenuItem.find :id => 1
Não tenho métodos find_by
26. Plugins nativos do Sequel
RcteTree
Modelo de árvore usando RECURSIVE CTEs
UpdatePrimaryKey
Para usar chaves naturais
IdentityMap
Cria uma relação de 1-1 entre objetos e linhas do banco
LazyAttributes
Busca campos para o modelo sob demanda.
27. Extensões para o PG no Sequel
https://github.com/gucki/sequel_column_type_array
Tipos array de inteiro e de varchar no banco
https://github.com/jeremyevans/sequel_postgresql_triggers
Gatilhos em PL/pgSQL criados de forma transparente
para gerenciar: updated_at, created_at, cache de
contadores e cache de somas
https://github.com/jeremyevans/sequel_pg
Acelera comandos SELECT