Alert control

Flex / Flex Builder, Flex Builder No Comments »

Todos componentes Flex podem chamar o método estatico show() da classe para abrir a caixa de diálogo modal pop up com uma mensagem e um título opcional, botões, e ícones. O exemplo seguinte mostra um controle Alert personalizado:

O controle Alert fecha quando você selecionar um botão no controle, ou pressionar a tecla de Escape.
O método Alert.show() tem a seguinte sintaxe:

public static show(

text:String,
title:String = null,
flags:uint = mx.controls.Alert.OK,
parent:Sprite = null,
clickListener:Function = null,
iconClass:Class = null,
defaultButton:uint = mx.controls.Alert.OK) : Alert

Este método retorna um objeto Alert control object.
A tabela seguinte descreve os argumentos do método show():

text (Requerido) Especifica o texto da mensagem da caixa de diálogo
title Especifica o título de caixa de diálogo. Se omitido, exibe uma barra de título em branco.
flags Especifica o botão(ões) para exibir no caixa de diálogo. As opções são como segue: Mx.controls.Alert.OK botão OK Mx.controls.Alert.YES botão SIM Mx.controls.Alert.NO botão NÂO Mx.controls.Alert.CANCEL botão CANCELA Cada opção é um valor bit e pode ser combinada com outras opções usando o operador “|”. Os botões aparecerão na ordem listadas aqui não importando a ordem que você especifica-os em seu código. O valor padrão é mx.controls.Alert.OK.
parent O objeto pai do controle Alert
clickListener Especifica o listener(ouvinte) para o evento clique dos botões. O objeto event passado para este manipulador é uma instância da classe CloseEvent. O objeto event contém o campo detail, que é fixado para a bandeira do botão que foi clicado (mx.controls.Alert.OK, mx.controls.Alert.CANCEL, mx.controls.Alert.YES, ou mx.controls.Alert.NO).
iconClass Especifica um ícone para exibir à esquerda do texto da mensagem na caixa de diálogo
defaultButton Especifica o botão padrão usando um dos valores válidos para o argumento flags. Iste é o botão que é selecionado quando o usuário apertar o Enter. O valor padrão é Alert.OK.
Apertando as teclas de fuga, o botão Cancel ou No da mesma maneira que se você o clicasse.

Para usar o controle Alert, você primeiro importa a classe Alert em sua aplicação. Então chame o método show(), como o exemplo seguinte mostra:

<?xml version="1.0"?>
<!-- controlsalertAlertSimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> 

<mx:Script>
          <![CDATA[
              import mx.controls.Alert;
          ]]>
</mx:Script> 

<mx:TextInput id="myInput" width="150" text=""/>
      <mx:Button id="myButton" label="Copy Text" click="myText.text = myInput.text;
      Alert.show('Text Copied!', 'Alert Box', mx.controls.Alert.OK);"/> 

      <mx:TextInput id="myText"/> 

</mx:Application>

Neste exemplo, selecionando o Botão o texto do TextInput é copiado para a TextArea, e exibe o Alerta.
Você também pode definir um evento listener(ouvinte) para o controle Button, como o exemplo seguinte mostra:

<?xml version=”1.0″?>
<!– controls\alert\AlertSimpleEvent.mxml –>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>

<mx:Script>

<![CDATA[

import mx.controls.Alert;

private function alertListener():void {
myText.text = myInput.text;
Alert.show(”Text Copied!”, “Alert Box”, Alert.OK);
}
]]>
</mx:Script>

<mx:TextInput id=”myInput”
width=”150″
text=”"/>
<mx:Button id=”myButton”
label=”Copy Text”
click=”alertListener();”/>
<mx:TextInput id=”myText”/>
</mx:Application>

NOTA
Depois da caixa de diálogo do método show()ser criada, O Flex continua com o processo de sua aplicação; não espera pelo usuário fechar o caixa de diálogo.

Dimensionando o controle Alert

O controle automaticamente muda as propriedades de tamanhos para ajustar seu texto, botões, e ícone. Você pode explicitamente mudar o tamanho de um Alert usando o objeto Alert retornado do método show(), como o exemplo seguinte mostra:

<?xml version=”1.0″?>
<!– controls\alert\AlertSize.mxml –>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>

<mx:Script>
<![CDATA[
import mx.controls.Alert;

// Define variable to hold the Alert object.
public var myAlert:Alert;

private function openAlert():void {
myAlert = Alert.show(”Copy Text?”, “Alert”,
Alert.OK | Alert.CANCEL);
// Set the height and width of the Alert control.
myAlert.height=150;
myAlert.width=150;
}
]]>
</mx:Script>

<mx:TextInput id=”myInput”
width=”150″
text=”"/>
<mx:Button id=”myButton”
label=”Copy Text”
click=”openAlert();”/>
<mx:TextInput id=”myText”/>
</mx:Application>

Neste exemplo, você fixa a propriedades altura e a largura do objeto Alert para tamanho do controle.

Usando event listeners com o Alert

O próximo exemplo adiciona um event listener ao controle da caixa de diálogo. Um event listener permite a você apresentar processo quando o usuário selecionar um botão do controle de Alerta. O event object passou para o event listenet é de tipo.
No próximo exemplo, você só copia o texto quando o usuário selecionar o botão OK no controle de Alerta:

<?xml version=”1.0″?>
<!– controls\alert\AlertEvent.mxml –>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>

<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;

private function alertListener(eventObj:CloseEvent):void {
// Check to see if the OK button was pressed.
if (eventObj.detail==Alert.OK) {
myText.text = myInput.text;
}
}
]]>
</mx:Script>

<mx:TextInput id=”myInput”
width=”150″
text=”" />
<mx:Button id=”myButton”
label=”Copy Text”
click=’Alert.show(”Copy Text?”, “Alert”,
Alert.OK | Alert.CANCEL, this,
alertListener, null, Alert.OK);’/>
<mx:TextInput id=”myText”/>
</mx:Application>

Neste exemplo, você define um event listener para o controle Alert. Dentro do corpo do event listener, você determina que botão foi apertado examinando a propriedade detail do objeto event. O objeto event é uma instância da classe CloseEvent. Se o usuário apertou o botão OK, copie o texto. Se o usuário apertou qualquer outro botão, ou apertou a tecla Esc, não copie o texto.

Especificando um icone para o Alert

Você pode incluir um ícone no controle que aparece à esquerda do Alerta. Este exemplo modifica o exemplo da seção prévia para adicionar a tag embed metadata para importar o ícone.

<?xml version=”1.0″?>
<!– controls\alert\AlertIcon.mxml –>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>

<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
[Embed(source=”assets/alertIcon.jpg”)]
[Bindable]
public var iconSymbol:Class;

private function alertListener(eventObj:CloseEvent):void {
// Check to see if the OK button was pressed.
if (eventObj.detail==Alert.OK) {
myText.text = myInput.text;
}
}
]]>
</mx:Script>

<mx:TextInput id=”myInput”
width=”150″
text=”"/>
<mx:Button id=”myButton”
label=”Copy Text”
click=’Alert.show(”Copy Text?”, “Alert”,
Alert.OK | Alert.CANCEL, this,
alertListener, iconSymbol, Alert.OK );’/>
<mx:TextInput id=”myText”/>
</mx:Application>

Traduzido da documentação oficial do ©Adobe ©Flex

RIA, É o melhor remédio!

Flex / Flex Builder, Flex Builder, Ruby on Rails No Comments »

Desde que a Internet apareceu em minha vida, ainda com o nome de BBS, venho estudando e me aprimorando desde então, já estudei muitos assuntos dentro da minha área, mas nunca ri tanto, quando conheci o Flex 2, já tinha instalado uma vez, mas a primeira vez que instalei, não consegui nem executá-lo (era o SDK).

Desisti! Depois de algum tempo, estudando na FGG (Faculdade Gratuita Google) o professor Search me apresentou o Flex 2 Builder, baixei alguns tutoriais, e comecei a bricar com ele, simplesmente apaixonante.

Minha satisfação então se completou quando conheci o curso de Flex on Rails que o Carlos Eduardo iria ministrar através do Treina TOM. Foi através dele que conheci mais ainda o poder do Flex.

Essa semana recebi um e-mail, curso de Flex pela e-Genial, só felicidade, com certeza serei uns dos primeiros a me inscrever. Quero ter um domínio completo sobre o Flex, e não perderia por nada um curso de Flex ministrado nada mais, nada menos por Fábio Terracini, um dos pioneiros com desenvolvimento em Flex no Brasil.

É claro, não poderia deixar de agradecer o meu amigo Carlos Eduardo por ser um dos principais, senão o mais, a contribuir para o crescimento da RIA aqui no Brasil.

RIA, faz bem pros olhos!

DBModelGem

Ruby on Rails No Comments »

O dbmodel gem aceita arquivos de modelo de dados de XML, chama generate model ou generate scaffold para tabelas com relacionamento, e insere relações (“has_many :beers”) em arquivos Model apropriado. A inserção de relacionamento em arquivos Model são arquivos existentes não destrutivos não são removidos e o código atual é mantido

Instalação:

Baixe DBDesigner 4.0. (O Workbench sucessor será lançado este ano) Carregue e instale

gem install dbmodel-0.1.0.gem –rdoc

O gem patch se você não estiver no Windows para lidar com caminhos corretamente. Brian Bugh forneceu o seguinte patch:

91c91
< modelfile = File.dirname(xmlfile) + File.join(”, ‘..’, ‘app’, ‘models’, table[’name’].singularize + ‘.rb’) — > modelfile = File.dirname(xmlfile) + ‘\..\app\models\\’ + table[’name’].singularize + ‘.rb’ 265c265 < require File.dirname(f) + File.join(”, ‘..’, ‘config’, ‘environment’) # Better way to do this? — > require File.dirname(f) + ‘/../config/environment’ # Better way to do this? 283c283 < if ex.message =~ /config#{File::SEPARATOR}environment/ — > if ex.message =~ /config\/environment/

Como usar:

Use DBDesigner para construir tabelas e especificar relações entre as mesmas. Etiquete as relações de maneira que o Rails compreenda, como has_many :cervejas ou has_and_belongs_to_many :coisas. Como o tempo você pode usar habtm :X em vez de has_and_belongs_to_many :X. Nota que você nunca precisará etiquetar um link belongs_to — relacionamento são definidos do ponto de vista da tabela, então o belongs_to é implícito na relação.
Salve seu modelo em um arquivo DBDesigner XML em sua pasta app/db. Então use o comando:

dbmodel mymodel.xml

Este gerará arquivos de modelo para todas as tabelas com relacionamento. Você pode escolher scaffolding por embedding tags dentro de seus comentários de tabelas.

Tradução do site: http://wiki.rubyonrails.com/rails/pages/DBModelGem

Chave Primária Composta

Ruby on Rails No Comments »

Porque

O RubyonRails não suporta chaves primárias compostas. Este software livre é uma extensão para a camada de banco de dados Rails – ActiveRecords – para aceitar chaves primárias compostas tão transparentemente quanto possível.
Qualquer script de Rubi usando ActiveRecords pode usar Chaves Primárias Composto com esta biblioteca.

Instalando

sudo gem install composite_primary_keys

Rails: Adicione a seguinte linha na parte inferior de seu environment.rb

require 'composite_primary_keys'

Script Ruby: Adicione a seguinte linha no topo de seu script

require 'rubygems'
require 'composite_primary_keys'

O Básico

Um modelo com chaves primárias compostas pareceria com …

class Membership < ActiveRecord::Base
  # set_primary_keys *keys - turns on composite key functionality
  set_primary_keys :user_id, :group_id
  belongs_to :user
  belongs_to :group
  has_many :statuses, :class => 'MembershipStatus', :foreign_key => [:user_id, :group_id]
end

Um modelo associado com um modelo de chave composto seria definido como …

class MembershipStatus < ActiveRecord::Base
  belongs_to :membership, :foreign_key => [:user_id, :group_id]
end

Isto é, associações podem incluir chaves compostas também. Bom.

Demonstração de Uso

Uma vez que você tem criados seus modelos para especificar chaves primárias compostas (como a classe Membership) e associações (como MembershipStatus#membership), você pode usar-las como qualquer modelo normal com associações.
Mas primeiro, verifique nossas chaves primárias.

MembershipStatus.primary_key # => "id"    # Chave Normal
Membership.primary_key  # => [:user_id, :group_id] # Chave composta
Membership.primary_key.to_s # => "user_id,group_id"

Agora nós queremos achar instâncias usando a mesma sintaxe que nós sempre usamos para ActiveRecords …

MembershipStatus.find(1)    # single id returns single instance
=> <MembershipStatus:0x392a8c8 @attributes={"id"=>"1", "status"=>"Active"}>
Membership.find(1,1)  # composite ids returns single instance
=> <Membership:0x39218b0 @attributes={"user_id"=>"1", "group_id"=>"1"}>

Usando Ruby on Rails? Você desejará seu seu helpers url_for para converter chaves compostas em strings e voltar novamente …

Membership.find(:first).to_param # => "1,1"

E então use a string ID dentro de seu controlador para achar o objeto novamente

params[:id] # => '1,1'
Membership.find(params[:id])
=> <Membership:0x3904288 @attributes={"user_id"=>"1", "group_id"=>"1"}>

Isto é, um ActiveRecord sustentando chaves compostas se comporta transparentemente ao longo de sua aplicação. Só como um ActiveRecord normal.

Outros Truques

Passe por uma lista de id composto para o achar método

Membership.find [1,1], [2,1]
=> [
  <Membership:0x394ade8 @attributes={"user_id"=>"1", "group_id"=>"1"}>,
  <Membership:0x394ada0 @attributes={"user_id"=>"2", "group_id"=>"1"}>
]

Perform #count operations

MembershipStatus.find(:first).memberships.count # => 1

Rotas com Rails

De Pete Sumskas:
Eu choquei-me com um problema que eu não vi mencionado nesta lista – e eu não vi quaisquer informações sobre ele na documentação de como eu devia fazer para trata-lo. O problema era que os URLs sendo gerado para ação do show (por exemplo) teve uma sintaxe como:
/controller/show/123000,Bu70
Para um PK de dois campos composto. A rota padrão não combinaria, então depois de descobrir como fazer a rota que eu adicionei:

  Map.connect ':controller/:action/:id ', :iD => /w+(,w+)*/

ao meu arquivo route.rb.

Que Banco de Dados?

Um suíte de testes da unidade foi executado nos bancos de dados seguintes sustentado por ActiveRecord:

Database

Sucesso do Teste

Retorno (since 0.8.0)

mysql YES ??? (Yes! or No…)
sqlite3 YES (new 0.8.0) ??? (Yes! or No…)
postgresql YES (new 0.8.0) ??? (Yes! or No…)
oracle YES (new 0.8.2) YES (Yes! or No…)
sqlserver ??? (I can help) ??? (Yes! or No…)
db2 ??? (I can help) ??? (Yes! or No…)
firebird ??? (I can help) ??? (Yes! or No…)
sybase ??? (I can help) ??? (Yes! or No…)
openbase ??? (I can help) ??? (Yes! or No…)
frontbase ??? (I can help) ??? (Yes! or No…)

Class ActionController::Base

Ruby on Rails No Comments »

Os controladores de ação são o centro de um pedido da web em Rails. Eles são compostos de uma ou mais ações que são executadas em pedido e então ou  num template ou redireciona para outra ação. Uma ação é definida como um método público no controlador, que estará automaticamente acessível para a web-server por Rails Routes.

Um simples controlador pode parecer com isto:

 class  GuestBookController < ActionController::Base
      def index
        @entries = Entry.find(:all)
      end

    def sign
        Entry.create(params[:entry])
        redirect_to :action =>  "index"
      end
    end

Actions, por padrão,  um modelo no diretório app/views correspondendo ao nome do controlador e ação depois de executar código na ação. Por exemplo, a ação index do GuestBookController iria  o modelo app/views/guestbook/index.rhtml por padrão depois de povoar a variável de instância @entries.
Diferentemente de index, a ação não sinalizará um modelo. Depois de apresentar seu propósito principal (criando uma nova entrada no Guest Book), inicia um redirecionamento. Este redireciona trabalhos retornando uma resposta externa "302 Moved" HTTP que leva o usuário para a ação index.
O index e sinal representam os dois arquétipos de ação básica usados em Controladores de Ação. Get-and-show e do-and-redirect. A maioria das ações são variações destes temas

Request

Request são processados pelo framework Action Controlador extraindo o valor da "chave de ação nos parâmetros request. Este valor devia segurar o nome da ação para ser apresentado. Uma vez que a ação foi identificada, os parâmetros request restante, a sessão (se uma está disponível), e o full request com todos os cabeçalhos HTTP ficam disponíveis para a ação por variáveis de instância. Então a ação é apresentada.
O objeto request está disponível com o request accessor e é principalmente usado por query para cabeçalhos HTTP. Estas queries são feitas acessando o hash de ambiente, como isto:

  def server_ip
    location = request.env["SERVER_ADDR"]
    render :text => "This server hosted at #{location}"
  end

Parameters

Todos os parâmetros request, se eles vêm de um GET ou POST request, ou do URL, estão disponíveis pelo método params que retorna um hash. Por exemplo, uma ação que era apresentada /weblog/list?category=All&limit=5 incluirá { "category" => "All", "limit" => 5 } em params.
É também possível construir hash de parâmetro dimensionais múltiplo especificando chaves usando parênteses, como:

  <input type="text" name="post[name]" value="david">
  <input type="text" name="post[address]" value="hyacintvej">

Um pedido originando-se de um form possuindo estas entradas incluirão { "post" => { "name" => "david", "address" => "hyacintvej" } }. Se a entrada de endereço foi nomeada "post[address][street]", O params teria incluído { "post" => { "address" => { "street" => "hyacintvej" } } }. Não há nenhum limite para a profundidade do alinhamento.

Sessions

As sessões permite que você armazene objetos entre pedidos. Isto é útil para objetos que não estão ainda prontos para ser persistidos, como objeto de Signup construido em um processo multi-paged, ou objetos que não muda muitos e são necessários o tempo todo, como objeto de Usuário para um sistema que exige login. A sessão não devia ser usada, porém, como um cache para objetos onde ele provavelmente podiam ser mudados. Ele normalmente trabalha demais para manter isso tudo sincronizados.
Você pode colocar objetos na sessão usando o método de sessão, que acessa um hash:

  session[:person] = Person.authenticate(user_name, password)

E recuperado novamente pelo mesmo hash:

  Hello #{session[:person]}

Para remover objetos da sessão, você pode remover qualquer um atribuindo uma chave única para NIL, como session[:person] = nil, ou você pode remover a sessão inteira com reset_session.
Por padrão, Seções são armazenadas no sistema de arquivo em RAILS_ROOT/tmp/sessions. Qualquer objeto pode ser colocado na sessão (desde que ele possa ser Disposto). Mas lembre que 1000 sessões ativas cada uma armazena um objeto de 50kb pode levar uma loja de 50MB no filesystem. Em outras palavras, pense cuidadosamente sobre tamanho e caching antes de recorrer para o uso da session no filesystem.
Uma alternativa para armazenar seções em disco é usar ActiveRecordStore para armazenar seções em seu banco de dados, que pode resolver problemas causados por armazenando de seções no sistema de arquivo e poder acelerar sua aplicação. Para usar ActiveRecordStore, descomente a linha:

  config.action_controller.session_store = :active_record_store

no seu environment.rb e execute o rake db:sessions:create.

Responses

Cada ação resulta em uma resposta, que possui os cabeçalhos e documentos para serem enviadas para o navegador usuário. O objeto de resposta real é automaticamente gerado pelo uso de renders e redireciona e não exige nenhuma intervenção de usuário.

Renders

O controlador de ação envia conteúdo para o usuário usando um de cinco métodos de renderização. A mais versátil e comum ser a renderização de um modelo. Incluído no Action Pack no Action View, que habilita renderização de modelos de ERb. Ele é automaticamente configurado. O controlador passa por objetos para a visão atribuindo variáveis de instância:

  def show
    @post = Post.find(params[:id])
  end

Que são então automaticamente disponível para a visão:

  Title: <%= @post.title %>

Você não tem que contar com a retribuição automatizada. Especialmente ações que podiam resultar na renderização de modelos diferentes usarão os métodos de renderização manual:

  def search
    @results = Search.find(params[:query])
    case @results
      when 0 then render :action => "no_results"
      when 1 then render :action => "show"
      when 2..10 then render :action => "show_many"
    end
  end

Leia mais sobre escrever ERb e construir templates em classes/ActionView/Base.html.

Redirects

Redirects são usados para mover de uma ação até outra. Por exemplo, depois da ação create, que armazena uma entrada de blog para um banco de dados, nós poderíamos mostrar ao usuário a nova entrada. Porque nós seguimos os princípios DRY (Don‘t Repeat Yourself), nós vamos reusar (e redirecionar para) uma ação de show que presumimos já ter sido criado. O código poderia parecer com isto:

  def create
    @entry = Entry.new(params[:entry])
    if @entry.save
      # The entry was saved correctly, redirect to show
      redirect_to :action => 'show', :id => @entry.id
    else
      # things didn't go so well, do something else
    end
  end

Neste caso, depois de salvar nossa nova entrada para o banco de dados, o usuário é redirecionado para o método show que é então executado.

Chamando múltiplos redirects ou renders

Uma ação devia concluir com um único render ou redirect. Tentando fazer qualquer um novamente resultará em um DoubleRenderError:

  def do_something
    redirect_to :action => "elsewhere"
    render :action => "overthere" # raises DoubleRenderError
  end

Se você precisar redirecionar na condição de algo, então não deixe de adicionar "and return" para parar a execução.

  def do_something
     redirect_to(:action => "elsewhere") and return if monkeys.nil?
     render :action => "overthere" # won’t be called unless monkeys is nil
   end

Active Record

Ruby on Rails No Comments »

Active Record

Enquanto eu trabalhava em uma parte de meu livro, eu mesmo achei em ./script/console e estava vendo alguns assuntos misteriosos quando eu usaria has_many e belongs_to.
Vamos ver dois modelos simples.

 

class Order < ActiveRecord::Base 
    belongs_to :customer 
  end 
class Customer < ActiveRecord::Base 
    has_many :orders 
  end 

Depois de alguns testes de registros

test_dev=# SELECT * FROM  customers;  
 id |      name      
  —-+—————- 
  1 | Robby 
  2 | Nigel 
  3 | Linus 
(3 rows) 
test_dev=# SELECT * FROM orders; 
   id | customer_id | amount 
  —-+————-+——– 
    1 |           1 |   12.00 
    2 |           3 |   12.00 
  (2 rows) 

Nada completamente louco continuando, certo?

<typo:code lang="ruby"> 
  Loading development environment. 
  >> Customer.destroy(3) 
  => {"name"=>"Linus", "id"=>"3"} 
  >>     

=# SELECT * FROM orders; 
   id | customer_id | amount 
  —-+————-+——– 
    1 |           1 |   12.00 
    3 |           3 |   12.00 
  (2 rows)

Espere um minuto! Eu só apago um cliente com um iD de 3!

Então, o que está errado com este argumento? Você pode pensar sobre alguns problemas potenciais que podiam acontecer de dados como isto? O registro tem um customer_id para um cliente que não existe. Isto é por que nós temos bancos de dados relacional em primeiro lugar, certo? :-)

Aqui está algo que eu aprendi hoje que eu sabia. O registro ativo permite que você passe pela declaração has_method a opção :dependent.

class Customer < ActiveRecord::Base 
  has_many :orders, :dependent => true 
end

O que é esta opção? Bem, de acordo com a documentação de AR, “:dependent – se fixado para true todo o objeto associado são destruídos ao lado deste objeto. Não pode ser fixado se :exclusively_dependent também está fixado.”
Em um nutshell, este trabalho ON DELETE CASCADE como é feito em PostgreSQL. Então, irá apagar as ordens associadas com o cliente que eu estava tentando destruir.
Até hoje, eu não tenho o hábito de usar o built-in constraints/triggers do PostgreSQL. Então, assim que eu fiz, este assunto surgiu e eu aprendi sobre :dependente.

test_dev# d orders
                                Table  "public.orders" 
    Column    |     Type       |                       Modifiers                        
————-+—————+————————————————
 id           | integer       | not null default 
 customer_id | integer       | nextval(’public.orders_id_seq’::text)
 amount       | numeric(10,2) | 

Indexes:
       "orders_pkey" PRIMARY KEY, btree (id)
  Foreign-key constraints:
       "orders_customer_id_fkey" FOREIGN KEY (customer_id) REFERENCES  customers(id)

test_dev=# ALTER TABLE orders DROP  CONSTRAINT orders_customer_id_fkey;
  ALTER TABLE 

RobbyOnRails:~/Programming/footest  robbyrussell$ ./script/console 
  Loading development environment.
  >> cust = Customer.create(:name  => ‘Jim’)
  => #<Customer:0×275373c  @new_record_before_save=true, @new_record=false,  @attributes={"name"=>"Jim", "id"=>5},  @errors=#<ActiveRecord::Errors:0×274fa88 @base=#<Customer:0×275373c  …>, @errors={}>>
  >> cust.orders.create(:amount  => ‘25.00′)
  => #<Order:0×274991c  @new_record=false, @attributes={"id"=>4,  "amount"=>"25.00", "customer_id"=>5},  @errors=#<ActiveRecord::Errors:0×2746dfc @base=#<Order:0×274991c …>,  @errors={}>>
  >>                

test_dev=# SELECT * FROM orders;
   id | customer_id | amount 
  —-+————-+——–
     1 |           1 |  12.00
     3 |           4 |  29.00
     4 |           5 |  25.00
  (3 rows)

Como você pode ver, eu mesmo coloco nas mãos Active Record quando eu executei o DROP CONSTRAINT. Então eu tentei executar o código no topo do post… e não funcionou.
De acordo com o docs, se você usar :dependent => true, devia apagar os registros da tabela estrangeira. Se não, devia fixar o valor do campo foriegn key para NULL na tabela estrangeira.
Basicamente, apresento estas duas queries SQL:

UPDATE orders SET customer_id = NULL  WHERE customer_id = 17; 

DELETE FROM customers  WHERE id = 17;

Então, os registros ainda estão no banco de dados para aquelas ordens, mas o cliente é excluído. Existem argumentos para e contra fazer este tipo de coisa… mas a habilidade de ter a opção é sempre boa. Em todo caso, Active Record não executaria a primeira query, ela está só excluindo da tabela clientes. Sem minha restrição, nenhum erro seria retornado do PostgreSQL e eu comecei a ter alguns dados ruins.
Imagine mostrar uma lista de pedidos e tentar exibir o nome do cliente associado com um pedido que não tem nenhum cliente linkado. Doh! Se o Active Record fixou o customer_id para NULO nós podemos pelo menos ter um pouco de lógica para trabalhar com ele sem ter que executar algumas queris de SQL para compreender que ordens tem e não tem clientes. (Nós queremos nossas aplicações com dados limpos!)
De qualquer maneira… Isto era um bug? O Active Record deve saber atualizar os registros para NULO neste caso? Eu figurei isto é devia ser manipulado esta tarefa, especialmente desde que era manipulado exclusão em cascata quando você passa :dependent como true.
Porém, eu prematuramente não quis postar um relatório de bug, então eu comecei a perguntar ao redor em #rubyonrails (irc.freenode.net). Pessoas fizeram um grupo de sugestões de como trabalhar com isto. Eu podia adicionar um método before_destroy em meu modelo, persiga o bug, (re)adicionei um gatilho ON DELETE à minha tabela (hah), etc. Aproximadamente, eu decidi que eu veria se eu pudesse perseguir o que acontece quando has_many for usado para um modelo em #destroy.
Depois de fazer alguns testes, eu postei um patch e um relatório de bug. (Por favor desconsidere meu primeiro patch… que não funcionou! Heh)
Agora que eu figurei este, eu estou indo contente adiciona minhas restrições atrás das minhas tabelas e volta a namorar. Este me lembrou de um post que eu tive alguns meses atrás quando eu mencionei que eu pensei que era melhor pôr algumas restrições e lógica no banco de dados. Eu também concordo que aquelas restrições deviam ser colocadas na camada de abstração, mas nós não podemos sempre pôr toda fé em nosso código, qualquer um. Alguns níveis de cheques não machuca. :-)
Isto era uma diversão pequena enigma que eu empreendi hoje. A moral da história? Se você tiver a habilidade de usar o builtin referential integrity do PostgreSQL e aqueles outros bancos de dados, poderia ser uma boa idéia fazer isso. As coisas são omitidas, pessoas logan para o banco de dados de muitas formas, e de programas diferentes.
ATUALIZAÇÃO: DHH respondeu para este post e forneceu um link que discute Banco de dados de Aplicação contra Banco de dados Integrado
Devia ser notado que existe uma distinção importante entre os dois métodos. Quando eu disse, “Coisas são omitidas, pessoas logan para o banco de dados de muitas formas, e de programas diferentes” eu basicamente estava descrevendo Banco de dados de Integração. Porém, eu também estava pensando sobre a possibilidade de alguém abrir seu GUI de MySQL ou PostgreSQL e manualmente removendo um registro em SQL claro. De acordo com o Banco de dados de Aplicação, no momento que você faz isto, você basicamente quebra este modelo e não pode esperar que sua aplicação seja completamente responsável pelos problemas que podem ou não podem acontecer. Neste momento, você precisaria olhar para sua aplicação em termos de Banco de dados de Integração. Por favor me corrija se eu estiver errado. :-)
Porém, com este argumento, minha primeira tentativa para mover para contar com AR teve uma solução secundário, mas ele era um fix fácil.
Apresentando o comando seguinte, eu estou movendo para um padrão de Banco de dados de Integração e isso devia ser reconhecido quando levando esta em consideração.

ALTER TABLE orders ADD CONSTRAINT  orders_customers_id_fkey 
     FOREIGN KEY (customer_id) REFERENCES customers (id) MATCH FULL; 

Ok, volte ao trabalho!
Uma vez mais. Use restrições! (Se você pode)… E graças ao DHH para fornecer o link e me motivando a fazer uma nota desta em minha entrada.
Tradução do Post colocado no site www.robbyonrails.com por Robby Russell

Patch Flex 2.0.1 para compatibilidade com o Flash CS3 Profissional

Flex / Flex Builder No Comments »

Este patch permite que o Flex SDK e Flex Builder use Swfs e Swcs criados pelo Flash Profissional CS3. Depois de se aplicar o patch você deve ser capaz de levar classes e símbolos compilados com Flash CS3 e compila-los em um aplicativo de Flex. Você também deve poder pegar classes e bibliotecas compiladas com Flex e usa-las num projeto do flash CS3

Flex SDK Instruções de instalação
O patch Flex 2.0.1 para compatibilidade com o Flash CS3 Profissional é oferecido como um arquivo zipado contendo os seguintes arquivos:

· swfkit.jar
· mxmlc.jar
· fdb.jar

Os arquivos .jar devem ser instalados manualmente:

Para atualizar o SDK no Windows, Macintosh e Unix:

1. Vá para o diretório \lib do Flex SDK, como:
2. C:\Flex_SDK_2\lib\
3. Faça backup dos arquivos de swfkit.jar, mxmlc.jar e fdb.jar.
4. Baixe o arquivo flex_201_patch_final.zip file.
5. Extraia o arquivo ZIP para um local temporário.
6. Copie swfkit.jar, mxmlc.jar e fdb.jar para o diretório \lib de sua instalação de Flex SDK

Flex Builder, instruções de instalação:
1. Feche Flex Builder.
2. Carregue swfkit.jar, mxmlc.jar, e fdb.jar para um local em seu drive.
3. Vá para sua pasta \lib da instalação do Flex Builder / Flex 2 SDK geralmente localizada aqui:
4. Windows -> Standalone: C:\Program Files\Adobe\Flex Builder 2\Flex SDK 2\lib
5. Windows Plugin: C:\Program Files\Adobe\Flex Builder 2 Plug-in\Flex SDK 2\lib
6. Mac Standalone: Applications/Adobe Flex Builder 2/Flex SDK 2/lib
7. Mac Plugin: Applications/Adobe Flex Builder 2 Plugin-in / Flex SDK 2/ li
8. Faça um backup dos arquivos swfkit.jar, mxmlc.jar, e fdb.jar.
9. Copie e cole os arquivos baixados swfkit.jar, mxmlc.jar, e fdb.jar no diretório /lib do SDK.
10. Clique Sim para substituir.
11. Vá para o diretório lib em \com.adobe.flexbuilder.flex_2.0.155577 plugin, normalmente localizado aqui:

Windows Standalone: C:\Program Files\Adobe\Flex Builder 2\plugins\com.adobe.flexbuilder.flex_2.0.155577\lib
Windows Plugin: eclipse\plugins\com.adobe.flexbuilder.flex_2.0.155577\lib
Mac Standalone : Applications/plugins/com.adobe.com.flex_2.0.155577/ib
Mac Plugin eclipse/plugins/com.adobe.flexbuilder.flex_2.0.155577/lib
Faça um backup de swfkit.jar, mxmlc.jar, e fdb.jar.
Copie e cole os arquivos descarregado swfkit.jar, mxmlc.jar, e fdb.jar no diretório plugin lib.
Clique Sim para substituir.

Avaliação de Aplicativos Modulares - Parte V

Flex / Flex Builder No Comments »

Usando eventos ModuleLoader

A classe ModuleLoader dispara vários eventos, inclusive setup, ready, loading, unload, progress, error, e urlChanged. Você pode usar estes eventos para localizar o progresso do processo loading, e descobrir quando um módulo foi descarregado ou quando o URL do target ModuleLoader mudou.

Usando o evento error

O evento error dá a você uma oportunidade de detectar uma falha quando um módulo não carregar por uma determinada razão. No exemplo seguinte, você pode carregar e descarregar um módulo usando os controles de Botão. Para ativar um evento error, mude o URL no TextInput para um módulo que não existe. O manipulador de erro exibe uma mensagem para o usuário e escreve a mensagem de erro para o log.

<?xml version=”1.0″?>

<!– modules/ErrorEventHandler.mxml –>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.*;
import mx.controls.Alert;

private function errorHandler(e:ModuleEvent):void {
Alert.show(”There was an error loading the module.” +
” Please contact the Help Desk.”);
trace(e.errorText);
}

public function createModule():void {
chartModuleLoader.url = ti1.text;
chartModuleLoader.loadModule();
}

public function removeModule():void {
chartModuleLoader.unloadModule();
}

]]>
</mx:Script>

<mx:Panel title=”Module Example”
height=”90%”
width=”90%”
paddingTop=”10″
paddingLeft=”10″
paddingRight=”10″
paddingBottom=”10″
>
<mx:HBox>
<mx:Label text=”URL:”/>
<mx:TextInput width=”200″ id=”ti1″ text=”ColumnChartModule.swf”/>
<mx:Button label=”Load” click=”createModule()”/>
<mx:Button label=”Unload” click=”removeModule()”/>
</mx:HBox>
<mx:ModuleLoader id=”chartModuleLoader” error=”errorHandler(event)”/>
</mx:Panel>
</mx:Application>

Usando o evento progress

Você pode usar o evento progress para localizar o progresso de um módulo à medida que ele carrega. Quando você adicionar um listener para o evento de progress, Flex chama aquele listener em intervalos regulares durante o processo de carregamento do módulo. Todo tempo o listener é chamado, você pode olhar para a propriedade bytesLoaded do evento. Você pode comparar esta ao bytesTotal para conseguir uma porcentagem de conclusão.
O exemplo seguinte reporta o nível de conclusão durante o carregamento do módulo. Também produz uma barra de progresso simples que mostra a usuários e fecha ao terminar de carregar.

<?xml version=”1.0″?>
<!– modules/SimpleProgressEventHandler.mxml –>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import flash.events.ProgressEvent;
import mx.modules.*;

[Bindable]
public var progBar:String = “”;

[Bindable]
public var progMessage:String = “”;

private function progressEventHandler(e:ProgressEvent):void {

progBar += “.”;
progMessage =
“Module ” +
Math.round((e.bytesLoaded/e.bytesTotal) * 100) +
“% loaded”;
}

public function createModule():void {
chartModuleLoader.loadModule();
}

public function removeModule():void {
chartModuleLoader.unloadModule();
progBar = “”;
progMessage = “”;
}

]]>
</mx:Script>

<mx:Panel title=”Module Example”
height=”90%”
width=”90%”
paddingTop=”10″
paddingLeft=”10″
paddingRight=”10″
paddingBottom=”10″
>
<mx:HBox>
<mx:Label id=”l2″ text=”{progMessage}”/>
<mx:Label id=”l1″ text=”{progBar}”/>
</mx:HBox>

<mx:Button label=”Load” click=”createModule()”/>
<mx:Button label=”Unload” click=”removeModule()”/>

<mx:ModuleLoader
id=”chartModuleLoader”
url=”ColumnChartModule.swf”
progress=”progressEventHandler(event)”
/>
</mx:Panel>
</mx:Application>

Você também pode conectar um carregador de módulo para um controle ProgressBar. O exemplo seguinte cria um componente personalizado para o ModuleLoader que inclui um ProgressBar. O ProgressBar exibe o progresso do módulo carregando.

<?xml version=”1.0″?><!– modules/MySimpleModuleLoader.mxml –><mx:ModuleLoader xmlns:mx=”http://www.adobe.com/2006/mxml”>    <mx:Script>        <![CDATA[                   private function clickHandler():void {                if (!url) {                    url=”ColumnChartModule.swf”;                }                loadModule();            }               ]]>    </mx:Script>

    <mx:ProgressBar        id=”progress”        width=”100%”        source=”{this}”    />    <mx:HBox width=”100%”>      <mx:Button        id=”load”        label=”Load”        click=”clickHandler()”      />      <mx:Button        id=”unload”        label=”Unload”        click=”unloadModule()”      />      <mx:Button        id=”reload”        label=”Reload”        click=”unloadModule();loadModule();”      />    </mx:HBox></mx:ModuleLoader>

Você pode usar este módulo em um aplicativo simples, como o exemplo seguinte mostra:

<?xml version=”1.0″?><!– modules/ComplexProgressEventHandler.mxml –><mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” xmlns:local=”*”>

    <mx:Panel title=”Module Example”        height=”90%”        width=”90%”        paddingTop=”10″        paddingLeft=”10″        paddingRight=”10″        paddingBottom=”10″    >               <mx:Label text=”Use the buttons below to load and unload               the module.”/>        <local:MySimpleModuleLoader id=”customLoader”/>    </mx:Panel>

</mx:Application>

Este exemplo não muda a propriedade de tag do ProgressBar para todos os eventos. Por exemplo, se você carregar e então descarrega o módulo, a propriedade de tag permanece em “CARREGAR 100%”. Ajustar a tag corretamente, você deve definir outros manipuladores de evento para os eventos de ModuleLoader, como unload e error.

Avaliação de Aplicativos Modulares - Parte IV

Flex / Flex Builder No Comments »

Carregando e descarregando módulos

Para carregar e descarregar módulos você usa o métodos load() e unload() da classe ModuleLoader. Estes métodos não tem nenhum parâmetro; O ModuleLoader carrega ou descarrega o módulo que combina o valor da propriedade de uRL atual.
O exemplo seguinte carrega e descarrega o módulo quando você clicar o botão

<?xml version=”1.0″?><!– modules/ASModuleLoaderApp.mxml –><mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>    <mx:Script>        <![CDATA[        import mx.modules.*;

        public function createModule(m:ModuleLoader, s:String):void {            if (!m.url) {                m.url = s;                return;            }            m.loadModule();        }

        public function removeModule(m:ModuleLoader):void {            m.unloadModule();        }        ]]>    </mx:Script>

    <mx:Panel title=”Module Example”        height=”90%”        width=”90%”        paddingTop=”10″        paddingLeft=”10″        paddingRight=”10″        paddingBottom=”10″    >        <mx:TabNavigator id=”tn”            width=”100%”            height=”100%”            creationPolicy=”auto”        >            <mx:VBox id=”vb1″ label=”Column Chart Module”>                             <mx:Button                    label=”Load”                    click=”createModule(chartModuleLoader, l1.text)”                />                <mx:Button                    label=”Unload”                    click=”removeModule(chartModuleLoader)”                />                <mx:Label id=”l1″ text=”ColumnChartModule.swf”/>                <mx:ModuleLoader id=”chartModuleLoader”/>                                         </mx:VBox>

            <mx:VBox id=”vb2″ label=”Form Module”>                <mx:Button                    label=”Load”                    click=”createModule(formModuleLoader, l2.text)”                />                <mx:Button                    label=”Unload”                    click=”removeModule(formModuleLoader)”                />                <mx:Label id=”l2″ text=”FormModule.swf”/>                <mx:ModuleLoader id=”formModuleLoader”/>            </mx:VBox>        </mx:TabNavigator>    </mx:Panel></mx:Application>

Fixando o local de um ModuleLoader ativa um chamada para o método loadModule(),
também. Isto acontece quando você primeiro criar um ModuleLoader com a
propriedade de uRL fixa.
Também acontece se você mudar o valor daquela propriedade.
O exemplo seguinte carrega os módulos sem chamar o método
loadModule() porque a propriedade de uRL é fixada na tag <mx:ModuleLoader>:

<?xml version="1.0"?><!– modules/URLModuleLoaderApp.mxml –><mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>    <mx:Panel        title=”Module Example”        height=”90%”        width=”90%”        paddingTop=”10″        paddingLeft=”10″        paddingRight=”10″        paddingBottom=”10″    >

        <mx:Label width=”100%” color=”blue”            text=”Select the tabs to change the panel.”/>

        <mx:TabNavigator id=”tn”            width=”100%”            height=”100%”            creationPolicy=”auto”        >            <mx:VBox id=”vb1″ label=”Column Chart Module”>                <mx:Label id=”l1″ text=”ColumnChartModule.swf”/>                <mx:ModuleLoader url=”ColumnChartModule.swf”/>            </mx:VBox>

            <mx:VBox id=”vb2″ label=”Form Module”>                <mx:Label id=”l2″ text=”FormModule.swf”/>                <mx:ModuleLoader url=”FormModule.swf”/>            </mx:VBox>

        </mx:TabNavigator>    </mx:Panel></mx:Application>

Quando você carregar um módulo, o Flex assegura que existe só uma cópia de um módulo carregado, não importa quantas vezes você chama load() para aquele módulo.

Os módulos são carregados na child do aplicativo atual. Você pode especificar um aplicativo diferente usando a propriedade applicationDomain da classe ModuleLoader.

Quando duas classes do mesmo nome mas implementações diferentes são carregadas, o primeiro carregado é o que será usado.

Carregando módulos de diferentes servidores

Para carregar um módulo de um servidor em um aplicativo que roda em um servidor diferente, você deve estabelecer uma confiança entre o módulo e o aplicativo que vai carrega-lo.

Para permitir acesso através de domínios:

Em seu aplicativo, você deve chamar o método allowDomain() e especificar o target do domínio que carrega o módulo. Então, especifique o domínio no manipulador de evento preinitialize de seu aplicativo para assegurar que o aplicativo é instalado antes do módulo ser carregado.

1. No arquivo de domínio cruzado do servidor remoto onde seu módulo está, adicione uma entrada que especifica o servidor em que o aplicativo que carregará está rodando.

2. Carregue o arquivo cross-domain no servidor remoto no evento preinitialize de seu aplicativo.

3. No módulo carregado, chame o método allowDomain() de forma que pode comunicar com o carregador

O seguinte exemplo mostra o método init() do aplicativo carregado.

public function setup():void {    Security.allowDomain(”remoteservername”);    Security.loadPolicyFile(”http://remoteservername/crossdomain.xml”);    var request:URLRequest = new URLRequest(”http://remoteservername        /crossdomain.xml”);    var loader:URLLoader = new URLLoader();    loader.load(request);}

O seguinte exemplo mostra módulo carregado do método init():

public function initMod():void {    Security.allowDomain(”loaderservername”);}

O seguinte exemplo mostra o cross-domain que reside no servidor remoto:

<!-- crossdomain.xml file located at the root of the server --><cross-domain-policy>    <allow-access-from domain=”loaderservername” to-ports=”*”/></cross-domain-policy>

Avaliação de Aplicativos Modulares - Parte III

Flex / Flex Builder No Comments »

Compilando Módulos

Você compila o módulo como você compilaria qualquer aplicativo do Flex usando o comando mxmlc do compilador ou o compilador do Flex Builder. O comando seguinte é o mais simples comando mxmlc:
mxmlc MyModule.mxml
O resultado é um arquivo SWF que você carrega em seu aplicativo como um módulo. Você não pode executar o arquivo SWF do módulo como um aplicativo Flash independente ou executá-lo em uma janela do Browser. Deve ser carregado por um aplicativo flex como um módulo.


Controlando o tamanho do módulo

O tamanho do módulo varia baseado nos componentes e classes que são usadas no módulo. Por padrão, um módulo inclui todo código do framework que seus componentes dependem, que podem fazer módulos serem grandes ligando classes que sobrepõem com as classes do aplicativo.
Para reduzir o tamanho dos módulos, você pode instruir o módulo para externalizar classes que são incluídas pelo aplicativo. Este inclui classes personalizada e classes de frameworks. O resultado é que o módulo só inclui a classe que requer, enquanto o código framework e outro dependências são incluídas no aplicativo.
Para externalizar classes de frameworks, você gera um linker report do aplicativo que carrega os módulos, usando p comando mxmlc. Você entá usando este repot como entrada para a carga externa dos módulos na opção do compilador


Para criar um linker report:
1. Gere o linker report:
mxmlc -link-report=report.xml MyApplication.mxml
2. Compile o arquivo SWF da aplicação:
mxmlc MyApplication.mxml
3. Compile o módulo:
mxmlc -load-externs=report.xml MyModule.mxml


Recompilando módulos

Você deve recompilar os módulos se você fizer mudanças. Recompilando o aplicativo principal não ativa um recompilação dos módulos. Semelhantemente, se você mudar o arquivo de aplicativo, você não tem que recompilar os módulos, a menos que você faça mudanças que poderia afetar o linker report ou código comum.

NOTA: Se você externalizar o módulo de dependências usando a opção externa de carga, seu módulo não poderia ser compatível com versões futuras de Flex de Adobe. Você pode ter que recompilar o módulo. Para assegurar que um aplicativo de Flex futuro pode usar um módulo, compile aquele módulo com todas as classes requeridas. Isto também se aplica a aplicativos que você carrega dentro de outros aplicativos