Rsync como excluir diretório .svn

No Railscasts número 149 que trata sobre Rails Engines (http://railscasts.com/episodes/149-rails-engines), é criado uma rake task para fazer a sincronização dos arquivos do plugin para o projeto principal.

Eu tive um problema nessa task por causa do SVN, eu uso ele para fazer o versionamento do meu projeto.

O problema é que os diretórios .svn são copiados do plugin para o projeto principal no momento do rsync, e isso gerá alguns problemas no SVN.

Para não serem mais sincados os diretórios .svn no momento do rsync eu adicionei o parâmetro –cvs-exclude que serve tanto para CVS como SVN.

1
2
3
4
5
6
7
8
# vendor/plugins/blogify/tasks/blogify_tasks.rake
namespace :blogify do
  desc "Sync extra files from blogify plugin."
  task :sync do
    system "rsync -ruv --cvs-exclude vendor/plugins/blogify/db/migrate db"
    system "rsync -ruv --cvs-exclude vendor/plugins/blogify/public ."
  end
end

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Linux at março 27th, 2009. No Comments.

Ruby on Rails como resolver A copy of … has been removed from the module tree but is still active!

Eu estou desenvolvendo um CMS em Ruby on Rails 2.3, um dos requisitos desse CMS é um alto grau de componentização em módulos.

Eu fiquei 1 semana pensando como poderia fazer isso da melhor forma no Rails, foi ae que eu descobri o Rails Engines no Rails 2.3, eu percebi que através dele eu conseguiria dividir a minha aplicação em módulos.

O Rails Engines permite embutir uma aplicação dentro da outra, para você entender melhor veja esse Railscasts: http://railscasts.com/episodes/149-rails-engines e http://rails-engines.org.

Eu consegui embutir uma aplicação dentro da outra e modularizar o funcionamento do meu CMS.

Tudo estava funcionando lindo e maravilhosamente na primeira requisição a página, por exemplo: http://localhost:3000/admin/node_types mas quando eu fiz a segunda requisição me deparei com essa mensagem de erro:

A copy of BackendController has been removed from the module tree but is still active!

E depois disso a página parou de funcionar e só aparecia essa mensagem de erro, fui atrás para descobrir o que era.

Pelo o que eu entendi o Rails carrega o conteúdo do plugin uma vez só, e depois faz o descarregamento das classes da memória, na segunda vez que você tenta acessar a classe ela não está mais na memória e dá problema.

No meu caso é a classe BackendController herdada pelo controlador do plugin Admin::NodeTypesController.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class Admin::NodeTypesController < BackendController
 
  # GET /admin/node_types
  # GET /admin/node_types.xml
  def index
    @node_types = NodeType.all
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render : xml => @node_types }
    end
  end
 
  # GET /admin/node_types/1
  # GET /admin/node_types/1.xml
  def show
    @node_type = NodeType.find(params[:id])
 
    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render : xml => @node_type }
    end
  end
 
  # GET /admin/node_types/new
  # GET /admin/node_types/new.xml
  def new
    @node_type = NodeType.new
 
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render : xml => @node_type }
    end
  end
 
  # GET /admin/node_types/1/edit
  def edit
    @node_type = NodeType.find(params[:id])
  end
 
  # POST /admin/node_types
  # POST /admin/node_types.xml
  def create
    @node_type = NodeType.new(params[:node_type])
 
    respond_to do |format|
      if @node_type.save
        flash[:notice] = 'Criado com sucesso.'
        format.html { redirect_to([:admin, @node_type]) }
        format.xml  { render : xml => @node_type, :status => :created, :location => @node_type }
      else
        format.html { render :action => "new" }
        format.xml  { render : xml => @node_type.errors, :status => :unprocessable_entity }
      end
    end
  end
 
  # PUT /admin/node_types/1
  # PUT /admin/node_types/1.xml
  def update
    @node_type = NodeType.find(params[:id])
 
    respond_to do |format|
      if @node_type.update_attributes(params[:node_type])
        flash[:notice] = 'Atualizado com sucesso.'
        format.html { redirect_to([:admin, @node_type]) }
        format.xml  { head : ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render : xml => @node_type.errors, :status => :unprocessable_entity }
      end
    end
  end
 
  # DELETE /admin/node_types/1
  # DELETE /admin/node_types/1.xml
  def destroy
    @node_type = NodeType.find(params[:id])
    @node_type.destroy
 
    respond_to do |format|
      format.html { redirect_to(admin_node_types_url) }
      format.xml  { head : ok }
    end
  end
end

Eu descobri duas soluções para resolver esse problema:

A primeira é fazer em que toda a requisição ao controlador Admin::NodeTypesController a classe BackendController será recarregada novamente adicionado load ‘backend_controller.rb’:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
load 'backend_controller.rb'
 
class Admin::NodeTypesController < BackendController
 
  # GET /admin/node_types
  # GET /admin/node_types.xml
  def index
    @node_types = NodeType.all
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render : xml => @node_types }
    end
  end
 
...

A segunda forma é dizer que a classe não deve ser descarregada, adicionando unloadable dentro da classe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Admin::NodeTypesController < BackendController
  unloadable
 
  # GET /admin/node_types
  # GET /admin/node_types.xml
  def index
    @node_types = NodeType.all
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render : xml => @node_types }
    end
  end
 
...

Essas soluções eu encontrei nos seguintes links:

Obs.: Eu coloquei um espaço onde aparece : xml, entre o : e xml, tive que fazer isso senão o wordpress fica adicionado imagens de smily no meio do código. Mesma coisa para : ok. erggg

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Ruby on Rails at março 26th, 2009. No Comments.

Ruby on Rails alias para rake db:migrate VERSION=0 no Linux

Eu uso muito o comando rake db:migrate VERSION=0 para desfazer todas as implementações no meu banco de dados quando estou trabalhando com Ruby on Rails, principalmente quando estou na fase de definição do banco de dados.

Para não ficar toda vez digitando rake db:migrate VERSION=0 eu criei um alias no Linux, agora quando eu digito dbzero ele faz a mesma coisa que o comando acima.

Para implementar esse alias é muito simples:

Edite o arquivo ~/.bashrc e no final do arquivo adicione o seguinte:

1
alias dbzero='rake db:migrate VERSION=0'

Salve a alteração.

Agora quando você abrir um novo terminal será carregado esse novo alias.

No diretório do seu projeto Rails basta digitar o comando dbzero e você vai ter o mesmo resultado.

Oba! Viva a economia de caracteres. ;-)

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Ruby on Rails at março 26th, 2009. No Comments.

Ruby on Rails estendendo as migrações com helpers

É muito comum termos nas migrações instruções sql para criar chaves estrangeiras e o rails não tem métodos para criar-las.

Por exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class CreateGameTeams < ActiveRecord::Migration
  def self.up
    create_table :game_teams do |t|
      t.references :team, :null => false
      t.references :game, :null => false
      t.timestamps
    end
 
    execute "ALTER TABLE game_teams ADD CONSTRAINT fk_game_team_teams FOREIGN KEY (team_id) REFERENCES teams (id) ON DELETE CASCADE ON UPDATE
 CASCADE"
    execute "ALTER TABLE game_teams ADD CONSTRAINT fk_game_team_games FOREIGN KEY (game_id) REFERENCES games (id) ON DELETE CASCADE ON UPDATE
 CASCADE"
  end
 
  def self.down
    drop_table :game_teams
  end
end

Para simplificar mais as coisas, é possível criar helpers e estender as funcionalidades das migrações, é isso que será feito para criar um método que gera as chaves estrangeiras (foreign key).

Faça o seguinte:

No diretório lib do projeto crie o arquivo migration_helpers.rb com o conteúdo abaixo:

1
2
3
4
5
6
7
8
9
module MigrationHelpers
 
  def foreign_key(from_table, from_column, to_table)
    constraint_name = "fk_#{from_table}_#{from_column}"
 
    execute %{alter table #{from_table} add constraint #{constraint_name} foreign key (#{from_column}) references #{to_table}(id)}
  end
 
end

Agora é possível adicionar esse método a qualquer migração acrescentando as linhas a seguir no início do arquivo de migração:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
require "migration_helpers"
 
class CreateGameTeams < ActiveRecord::Migration
 
  extend MigrationHelpers
 
  def self.up
    create_table :game_teams do |t|
      t.references :team, :null => false
      t.references :game, :null => false
      t.timestamps
    end
 
    foreign_key(:game_teams, :team_id, :teams)
    foreign_key(:game_teams, :game_id, :games)
  end
 
  def self.down
    drop_table :game_teams
  end
end

A linha require coloca a definição do módulo no código de migração e a linha extend adiciona os métodos do módulo MigrationHelpers à migração como métodos de classe.

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Ruby on Rails at março 24th, 2009. No Comments.

Ruby on Rails como fazer dois atributos da mesma classe apontarem para a mesma classe pai no ActiveRecord

Hoje estava programando um sistema de menus, onde cada item de menu pode ter vários outros itens, não existindo limite de subníveis.

Para conseguir obter essa relação e associação no banco de dados criei dois models BackendMenu e BackendMenuNode, com as seguintes migrações:

BackendMenu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class CreateBackendMenus < ActiveRecord::Migration
  def self.up
    create_table :backend_menus do |t|
      t.string  :title,     :null => false
      t.string  :path,      :null => false
      t.integer :weight,    :null => false, :default => 0
      t.boolean :is_active, :null => false, :default => false
      t.boolean :is_root,   :null => false, :default => false
      t.timestamps
    end
  end
 
  def self.down
    drop_table :backend_menus
  end
end

BackendMenuNode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CreateBackendMenuNodes < ActiveRecord::Migration
  def self.up
    create_table :backend_menu_nodes do |t|
      t.integer :root_id, :null => false
      t.integer :node_id, :null => false
      t.integer :weight,  :null => false, :default => 0
    end
 
    add_index(:backend_menu_nodes, [:root_id, :node_id], :unique => true)
    execute "ALTER TABLE backend_menu_nodes ADD CONSTRAINT fk_backend_menu_nodes_backend_menus_root FOREIGN KEY (root_id) REFERENCES backend_menus (id) ON DELETE CASCADE ON UPDATE CASCADE"
    execute "ALTER TABLE backend_menu_nodes ADD CONSTRAINT fk_backend_menu_nodes_backend_menus_node FOREIGN KEY (node_id) REFERENCES backend_menus (id) ON DELETE CASCADE ON UPDATE CASCADE"
  end
 
  def self.down
    drop_table :backend_menu_nodes
  end
end

Todos os itens de menu vão ficar cadastrados na tabela backend_menus e associação para descobrir os menus filhos será feito pela tabela backend_menu_nodes. A tabela backend_menu_nodes tem as colunas root_id que se referência ao pai e a coluna node_id que se referência aos menus filhos, desta forma um menu pode ter N itens.

Tanto a coluna root_id e node_id fazem referência a tabela backend_menus.

Para conseguir obter essa associação no ActiveRecord fiz o seguinte:

BackendMenu:

1
2
3
4
5
class BackendMenu < ActiveRecord::Base
  # associações
  has_many :nodes, :class_name => "BackendMenuNode", :foreign_key => "root_id"
  ...
end

BackendMenuNode:

1
2
3
4
5
6
class BackendMenuNode < ActiveRecord::Base
  # associações
  belongs_to :root, :class_name => "BackendMenu", :foreign_key => "root_id"
  belongs_to :node, :class_name => "BackendMenu", :foreign_key => "node_id"
  ...
end

Fazendo a relação acima eu consigo navegar pelo menu pai e os meus filhos.

Para imprimir o menu eu criei 3 helpers usando a recursividade:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
module BackendHelper
 
  # cria o menu do backend
  def menu(collection, class_name = "menu")
    content = content_tag :ul, :class => class_name do
      menu_items(collection)
    end
    content
  end
 
  # cria os items do menu
  def menu_items(collection)
    content = ""
    for item in collection
      if item.instance_of? BackendMenu
        content << item_nodes(item)
      else
        content << item_nodes(item.node)
      end
    end
    content
  end
 
  # cria os nós do item de menu
  def item_nodes(item)
    content = ""
    class_name = "leaf"
 
    if item.nodes.size > 0
      class_name = "collapsed"
      content << content_tag(:li, :class => class_name) do
        link_to(item.title, item.path) + menu(item.nodes, "menu hide")
      end
    else
      content << content_tag(:li, link_to(item.title, item.path), :class => class_name)
    end
    content
  end
 
end

No controlador eu faço o seguinte:

1
@backend_menus = BackendMenu.find :all, :conditions => { :is_root => true }, :order => 'weight'

Na view:

1
2
3
4
5
<!-- begin sidebar-left -->
<div id="sidebar-left">
  <%= menu(@backend_menus) %>
</div>
<!-- end sidebar-left -->

Se você quiser alguns menus de teste, usei a migração abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
class AddBackendMenus < ActiveRecord::Migration
  def self.up
    BackendMenu.delete_all
 
    # criação dos menus pais
    BackendMenu.create(:title => 'Principal',
      :path => 'principal',
      :weight => 1,
      :is_active => true,
      :is_root => true)
 
    BackendMenu.create(:title => 'Criar Conteúdo',
      :path => 'criar-conteudo',
      :weight => 2,
      :is_active => true,
      :is_root => true)
 
    BackendMenu.create(:title => 'Gerenciamento de Conteúdo',
      :path => 'gerenciamento-de-conteudo',
      :weight => 3,
      :is_active => true,
      :is_root => true)
 
    BackendMenu.create(:title => 'Site Construtor',
      :path => 'site-construtor',
      :weight => 4,
      :is_active => true,
      :is_root => true)
 
    BackendMenu.create(:title => 'Site Configuração',
      :path => 'site-configuracao',
      :weight => 5,
      :is_active => true,
      :is_root => true)
 
    BackendMenu.create(:title => 'Gerenciamento de Usuário',
      :path => 'gerenciamento-de-usuario',
      :weight => 6,
      :is_active => true,
      :is_root => true)
 
    BackendMenu.create(:title => 'Relatórios',
      :path => 'relatorios',
      :weight => 7,
      :is_active => true,
      :is_root => true)
 
    BackendMenu.create(:title => 'Ajuda',
      :path => 'ajuda',
      :weight => 8,
      :is_active => true,
      :is_root => true)
 
    # criação dos menus filhos
    BackendMenu.create(:title => 'Página',
      :path => 'criar-conteudo/pagina',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('criar-conteudo').id,
      :node_id => BackendMenu.find_by_path('criar-conteudo/pagina').id,
      :weight => 1)
 
    BackendMenu.create(:title => 'História',
      :path => 'criar-conteudo/historia',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('criar-conteudo').id,
      :node_id => BackendMenu.find_by_path('criar-conteudo/historia').id,
      :weight => 2)
 
    BackendMenu.create(:title => 'Comentários',
      :path => 'gerenciamento-de-conteudo/comentarios',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-conteudo').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/comentarios').id,
      :weight => 1)
 
    BackendMenu.create(:title => 'Ativos',
      :path => 'gerenciamento-de-conteudo/comentarios/ativos',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/comentarios').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/comentarios/ativos').id,
      :weight => 1)
 
    BackendMenu.create(:title => 'Teste',
      :path => 'gerenciamento-de-conteudo/comentarios/ativos/teste',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/comentarios/ativos').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/comentarios/ativos/teste').id,
      :weight => 1)
 
    BackendMenu.create(:title => 'Inativos',
      :path => 'gerenciamento-de-conteudo/comentarios/inativos',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/comentarios').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/comentarios/inativos').id,
      :weight => 2)
 
    BackendMenu.create(:title => 'Conteúdo',
      :path => 'gerenciamento-de-conteudo/conteudo',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-conteudo').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/conteudo').id,
      :weight => 2)
 
    BackendMenu.create(:title => 'Tipos de Conteúdo',
      :path => 'gerenciamento-de-conteudo/tipos-de-conteudo',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-conteudo').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/tipos-de-conteudo').id,
      :weight => 3)
 
    BackendMenu.create(:title => 'Publicação de RSS',
      :path => 'gerenciamento-de-conteudo/publicacao-de-rss',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-conteudo').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-conteudo/publicacao-de-rss').id,
      :weight => 4)
 
    BackendMenu.create(:title => 'Blocos',
      :path => 'site-construtor/blocos',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-construtor').id,
      :node_id => BackendMenu.find_by_path('site-construtor/blocos').id,
      :weight => 1)
 
    BackendMenu.create(:title => 'Formulários',
      :path => 'site-construtor/formularios',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-construtor').id,
      :node_id => BackendMenu.find_by_path('site-construtor/formularios').id,
      :weight => 2)
 
    BackendMenu.create(:title => 'Menus',
      :path => 'site-construtor/menus',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-construtor').id,
      :node_id => BackendMenu.find_by_path('site-construtor/menus').id,
      :weight => 3)
 
    BackendMenu.create(:title => 'Módulos',
      :path => 'site-construtor/modulos',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-construtor').id,
      :node_id => BackendMenu.find_by_path('site-construtor/modulos').id,
      :weight => 4)
 
    BackendMenu.create(:title => 'temas',
      :path => 'site-construtor/temas',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-construtor').id,
      :node_id => BackendMenu.find_by_path('site-construtor/temas').id,
      :weight => 5)
 
    BackendMenu.create(:title => 'Tradução',
      :path => 'site-construtor/traducao',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-construtor').id,
      :node_id => BackendMenu.find_by_path('site-construtor/traducao').id,
      :weight => 6)
 
    BackendMenu.create(:title => 'Idiomas',
      :path => 'site-configuracao/idiomas',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-configuracao').id,
      :node_id => BackendMenu.find_by_path('site-configuracao/idiomas').id,
      :weight => 1)
 
    BackendMenu.create(:title => 'Logs e Alertas',
      :path => 'site-configuracao/logs-e-alertas',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-configuracao').id,
      :node_id => BackendMenu.find_by_path('site-configuracao/logs-e-alertas').id,
      :weight => 2)
 
    BackendMenu.create(:title => 'Manutenção do Site',
      :path => 'site-configuracao/manuencao-do-site',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-configuracao').id,
      :node_id => BackendMenu.find_by_path('site-configuracao/manuencao-do-site').id,
      :weight => 3)
 
    BackendMenu.create(:title => 'Ações',
      :path => 'site-configuracao/acoes',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('site-configuracao').id,
      :node_id => BackendMenu.find_by_path('site-configuracao/acoes').id,
      :weight => 4)
 
    BackendMenu.create(:title => 'Regras de Acesso',
      :path => 'gerenciamento-de-usuario/regras-de-acesso',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-usuario').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-usuario/regras-de-acesso').id,
      :weight => 1)
 
    BackendMenu.create(:title => 'Permissões',
      :path => 'gerenciamento-de-usuario/permissoes',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-usuario').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-usuario/permissoes').id,
      :weight => 2)
 
    BackendMenu.create(:title => 'Regras',
      :path => 'gerenciamento-de-usuario/regras',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-usuario').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-usuario/regras').id,
      :weight => 3)
 
    BackendMenu.create(:title => 'Configurações de Usuários',
      :path => 'gerenciamento-de-usuario/configuracoes-de-usuarios',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-usuario').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-usuario/configuracoes-de-usuarios').id,
      :weight => 4)
 
    BackendMenu.create(:title => 'Usuários',
      :path => 'gerenciamento-de-usuario/usuarios',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('gerenciamento-de-usuario').id,
      :node_id => BackendMenu.find_by_path('gerenciamento-de-usuario/usuarios').id,
      :weight => 5)
 
    BackendMenu.create(:title => 'Entrada de Logs',
      :path => 'relatorios/entrada-de-logs',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('relatorios').id,
      :node_id => BackendMenu.find_by_path('relatorios/entrada-de-logs').id,
      :weight => 1)
 
    BackendMenu.create(:title => 'Erros de Acesso Negado',
      :path => 'relatorios/erros-de-acesso-negado',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('relatorios').id,
      :node_id => BackendMenu.find_by_path('relatorios/erros-de-acesso-negado').id,
      :weight => 2)
 
    BackendMenu.create(:title => 'Status',
      :path => 'relatorios/status',
      :is_active => true,
      :is_root => false)
    BackendMenuNode.create(:root_id => BackendMenu.find_by_path('relatorios').id,
      :node_id => BackendMenu.find_by_path('relatorios/status').id,
      :weight => 3)
  end
 
  def self.down
    BackendMenu.delete_all
  end
end

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Ruby on Rails at março 23rd, 2009. No Comments.

Ruby on Rails uma forma mais inteligente de organizar controladores e helpers

Estou trabalhando numa nova aplicação em Rails, ela é dividida em área administrativa e uma área vísivel a todos os visitantes da aplicação.

Inicialmente eu comecei com os controladores admin_controller.erb, home_controller.erb e o controlador padrão application_controller.erb, que é herdado pelos dois primeiros controladores.

application_controller.erb

1
2
3
4
5
6
7
8
9
10
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
 
class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
 
  # Scrub sensitive parameters from your log
  # filter_parameter_logging :password
end

admin_controller.erb

1
2
3
4
5
6
class AdminController < ApplicationController
 
  def index
  end
 
end

home_controller.erb

1
2
3
4
5
6
class HomeController < ApplicationController
 
  def index
  end
 
end

Mas eu quero deixar a minha aplicação mais simples e inteligente, a minha área administrativa vai ser grande, bem como o meu frontend.

Vão existir uma série de filtros e helpers que vão ser usados em comum por todos os diversos controladores da área administrativa e do frontend, do jeito que está hoje eu teria que colocar muito código no application_controller.erb, bem como no helper padrão application_helper.erb.

Desta forma eu decidi criar dois novos controladores backend_controller.erb e frontend_controller.erb, a minha ideia é fazer todos os controladores da área administrativa herdarem o backend_controller.erb, e todos os controladores do meu frontend herdarem o controlador frontend_controller.erb. Por sua vez os controladores backend_controller.erb e frontend_controller.erb herdarão o application_controller.erb, o que garante que a minha aplicação vai continuar funcionando corretamente.

Fazendo isso eu ganho um grau maior de componentização dos controladores, quando eu adicionar um filtro, método ou helper no backend_controller.erb ou frontend_controller.erb todos os controladores filhos deles já terão essa funcionalidade disponível.

Seguindo essa ideia eu fiz algumas alterações para implementar esse recurso:

Criei dois novos controladores:

backend_controller.erb

1
2
3
4
5
# Filtros adicionados nesse controlador serão aplicados em todos os controladores filhos
# De igual modo, todos os métodos adicionados estarão disponíveis para todos os controladores filhos
 
class BackendController < ApplicationController
end

frontend_controller.erb

1
2
3
4
5
# Filtros adicionados nesse controlador serão aplicados em todos os controladores filhos
# De igual modo, todos os métodos adicionados estarão disponíveis para todos os controladores filhos
 
class FrontendController < ApplicationController
end

Alterei os controladores abaixo, para herdarem os controladores criados acimas:

admin_controller.erb

1
2
3
4
5
6
class AdminController < BackendController
 
  def index
  end
 
end

home_controller.erb

1
2
3
4
5
6
class HomeController < FrontendController
 
  def index
  end
 
end

Fazendo isso eu consigo ganhar uma componentização muito grande, se eu adicionar alguma coisa no controlador application_controller.erb, ele está disponível tanto no admin como no frontend.

Adicionando algo no frontend_controller.erb estará disponível em todo o frontend e adicionando algo no backend_controller.erb estará disponível em todo o admin.

É possível melhorar mais ainda, vamos criar dois novos helpers:

backend_helper.rb

1
2
module BackendHelper
end

frontend_helper.rb

1
2
module FrontendHelper
end

Vou colocar esses helpers para serem carregados em todos os controladores que herdam backend_controller.rb e frontend_controller.erb:

backend_controller.rb

1
2
3
4
5
6
7
# Filtros adicionados nesse controlador serão aplicados em todos os controladores filhos
# De igual modo, todos os métodos adicionados estarão disponíveis para todos os controladores filhos
 
class BackendController < ApplicationController
  layout "admin"
  helper :backend
end

Acima eu aproveitei e adicionei o layout “admin.html.erb”, que será usado por todos as views da área administrativa.

frontend_controller.rb

1
2
3
4
5
6
# Filtros adicionados nesse controlador serão aplicados em todos os controladores filhos
# De igual modo, todos os métodos adicionados estarão disponíveis para todos os controladores filhos
 
class FrontendController < ApplicationController
  helper :frontend
end

Agora no application_controller.erb, comente a linha helper :all, para não carregar todos os helpers, só os que você precisa.

1
2
3
4
5
6
7
8
9
10
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
 
class ApplicationController < ActionController::Base
  # helper :all # include all helpers, all the time
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
 
  # Scrub sensitive parameters from your log
  # filter_parameter_logging :password
end

Pronto! ;-)

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Ruby on Rails at março 18th, 2009. No Comments.

Ruby on Rails Livros para Download

Alguns livros para download sobre Ruby on Rails:

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Ruby on Rails at março 18th, 2009. No Comments.

Ruby on Rails 2.3.2

Acabei de instalar o Rails 2.3.2.

Vou desenvolver um projeto grande usando ele, preciso estudar e ver as novidades dessa versão, tomará que tenha bastante coisas para agilizar e facilitar a minha vida.

;-)

Posted in Ruby on Rails at março 17th, 2009. No Comments.

Ruby on Rails como usar outro layout para uma action

Para usar outro layout em uma action específica em Ruby on Rails, é possível fazer o seguinte:

1
2
3
def index
  render :layout => "admin_login"
end

Onde “admin_login” é o layout que você deseja usar.

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Ruby on Rails at março 12th, 2009. No Comments.

Ruby on Rails 2.2.2 Instalando GEM MySQL no Ubuntu 8.10

Muitas pessoas estão com dificuldades para instalar o MySQL para ser usado com Ruby on Rails, eu também tive esse problema, por isso estou compartilhando a solução que eu encontrei.

Digite no terminal:

1
2
3
4
sudo apt-get install gcc
sudo apt-get install ruby-dev
sudo apt-get install libmysqlclient15-dev
sudo gem install mysql

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

Posted in Ruby on Rails at março 2nd, 2009. No Comments.

 Assinar RSS Feed