#238 Mongoid
- Download:
- source codeProject Files in Zip (109 KB)
- mp4Full Size H.264 Video (18.2 MB)
- m4vSmaller H.264 Video (12.1 MB)
- webmFull Size VP8 Video (28.3 MB)
- ogvFull Size Theora Video (22.7 MB)
Há alguns meses atrás no Episódio 194 [ver, ler] covered MongoDB e MongoMapper. MongoMapper é uma gema grande, mas agora existe uma alternativa chamada Mongoid que vale a pena considerar se você está pensando em usar MongoDB como o back-end de uma aplicação Rails. Uma das coisas que faz stand Mongoid fora é o seu site, que parece ótimo e que tem documentação detalhada. Mongoid é um projeto de outros projetos open-source que você pode aprender.
Instalando o MongoDB
Se você ainda não tem instalado em seu sistema o MongoDB a primeira coisa que você precisa fazer é acessar o página de downloads do MongoDB e baixar os arquivos apropriados. Se você estiver usando Mac OS X, então você pode instalar MongoDB atravez do Homebrew. Uma vez instalado, você pode verificar se está funcionando MongoDB visitando http://localhost:28017
. Se você ver uma página como a abaixo, em seguida, significa que tudo está funcionando corretamente.
Criando uma nova aplicação Rails utilizando o Mongoid
Agora que já temos o MongoDB instalado, vamos criar uma nova aplicação Rails 3 que usa Mongoid. Como é tradição de uma aplicações Rails de exemplo, esta será uma aplicação de blog.
$ rails new blog
A primeira coisa que precisamos fazer é adicionar a gema Mongoid ao Gemfile. No momento da versão escrita é a 2, que é a versão que o Rails 3 suporta, ainda está em beta, então vamos precisar especificar o número da versão.
source 'http://rubygems.org' gem 'rails', '3.0.1' gem 'sqlite3-ruby', :require => 'sqlite3' gem 'mongoid', '2.0.0.beta.19' gem 'bson_ext'
Precisamos também de adicionar o bson_ext
gem. BSON é uma versão binária do JSON e esta gema fornece algumas extensões C para acelerar a serialização Ruby BSON. Podemos, então, instalar as gema da maneira usual.
$ bundle install
Uma vez que as gemas tenham sido instaladas, precisaremos executar o gerador de configuração do Mongoid para que ele possa criar o arquivo de configuração YAML.
$ rails g mongoid:config
O arquivo padrão é mostrado abaixo. Podemos deixá-lo como ele é enquanto estamos desenvolvendo a nossa aplicação.
defaults: &defaults host: localhost # slaves: # - host: slave1.local # port: 27018 # - host: slave2.local # port: 27019 development: <<: *defaults database: blog_development test: <<: *defaults database: blog_test # set these environment variables on your prod server production: host: <%= ENV['MONGOID_HOST'] %> port: <%= ENV['MONGOID_PORT'] %> username: <%= ENV['MONGOID_USERNAME'] %> password: <%= ENV['MONGOID_PASSWORD'] %> database: <%= ENV['MONGOID_DATABASE'] %>
Tudo está no lugar agora para nós poder começar a desenvolver a nossa aplicação. Vamos começar criando um modelo Artigo
com os campos nome
e conteúdo
, e iremos usar o scaffolding do Rails para criar o controlador associado e visualização de código.
$ rails g scaffold article name:string content:text invoke mongoid create app/models/article.rb
Mongoid fornece geradores para os modelos modo que o gerador Mongoid o modelo é chamado quando um modelo é criado e, portanto, o ActiveRecord não é usado. Se abrirmos o arquivo do modelo, iremos ver que é uma classe simples foi incluida Mongoid::Document
.
class Article include Mongoid::Document field :name, :type => String field :content, :type => String end
Uma diferença é que esta classe vem a partir de uma classe model do ActiveRecord é que cada campo é explicitamente definido, junto com seu tipo. O tipo padrão é String
, para que possamos remover os tipos desta classe, se quisermos.
class Article include Mongoid::Document field :name field :content end
Agora a nossa aplicação está pronto para ser executada. Nós não precisamos executar qualquer banco de dados como migração do MongoDB, com o schema-lesse podemos passar todos os campos que preferimos em um documento. Se você visitar a página /articles
, iremos ver a página usual gerada pelo scaffold, e podemos criar um novo Artigo
, assim como nós, se tivéssemos um ActiveRecord como back-end.
Adicionando campos
Uma das grandes vantagens de se usar o schema-less como banco de dados, é que é bastante simples de adicionar novos campos ao modelo. Vamos dizer que se esqueceu de acrescentar uma data de publicação do Artigo
. Para adicionar um só precisamos modificar a classe do modelo.
class Article include Mongoid::Document field :name field :content field :published_on, :type => Date end
Para que possamos visualizar e modificar o campo da data de publicação, iremos modificar o código da view e adicionar o novo campo ao formulário.
<div class="field"> <%= f.label :name %><br /> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :published_on %><br /> <%= f.date_select :published_on %> </div> <div class="field"> <%= f.label :content %><br /> <%= f.text_area :content %> </div> <div class="actions"> <%= f.submit %> </div>
E também a view para a ação do show
.
<p id="notice"><%= notice %></p> <p> <b>Name:</b> <%= @article.name %> </p> <p> <b>Content:</b> <%= @article.content %> </p> <p> <b>Published:</b> <%= @article.published_on %> </p> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %>
Agora podemos editar o artigo que acabamos de criar e adicionar uma data de publicação.
Validações
O Mongoid utiliza o ActiveModel, o que significa que muitas das funcionalidades que usamos no ActiveRecord está disponível para nós aqui também, por exemplo validações, callbacks, dirty tracking, attr_accessible
, e assim por diante. Com isto, se torna mais fácil adicionar as validações de modelos como os ActiveRecord do Mongoid.
class Article include Mongoid::Document field :name field :content field :published_on, :type => Date validates_presence_of :name end
Se tentarmos criar um artigo sem um nome agora, iremos começar a ver os erros de validação o mesmo que veríamos por um modelo equivalente ao ActiveRecord.
Associações
Não podemos ter um blog sem comentários, então iremos criar um modelo para Comentário
ao longo associação, modo que cada artigo pode ter muitos comentários. Há duas maneiras para definir as associações com Mongoid. A primeira é através de uma associação de referência. Esta se comporta de maneira similar às relações entre tabelas no ActiveRecord e bancos de dados relacionais em que existem dois registros separados que estão relacionados através de uma coluna id
. A outra maneira é uma associação incorporado, o que significaria, neste caso, os comentários estão incorporados dentro do mesmo documento que o artigo.
Em quanto você está decidindo qual destas abordagens, é a utilização que você precisa se perguntar se você realmente necessita dos registros associados por ficar por conta própria ou se você vai sempre acessá-los através do seu modelo pai. Neste caso, só vamos sempre estar recebendo comentários através de seu artigo associado por isso vamos usar uma associação incorporado. Nós definimos o relacionamento na classe de Artigo
usando o método embeds_many
.
class Article include Mongoid::Document field :name field :content field :published_on, :type => Date validates_presence_of :name embeds_many :comments end
Em seguida, vamos gerar o modelo de Comentário
.
$ rails g model comment name:string content:text
Nesta nova classe Comentário
, podemos agora definir a sua relação com o Artigo
.
class Comment include Mongoid::Document field :name field :content embedded_in :article, :inverse_of => :comments end
Usamos embedded_in
para definir a relação de um comentário a um artigo. A opção inverse_of
é necessário dizer ao Mongoid que o comentário deve ser incorporado completamente.
A fim de criar comentários para cada artigo e vê-los vamos precisar criar um CommentsController
e algumas views, mas antes de fazermos isso iremos precisar alterar o arquivo de rotas. Para as associações incorporadas como esta, geralmente queremos usar rotas aninhadas como o objeto filho é sempre acessado através de seu pai e por isso iremos utilizar o nested do recurso comentários em artigos.
Blog::Application.routes.draw do resources :articles do resources :comments end end
Em seguida, iremos gerar o controller.
$ rails g controller comments
No controller iremos escrever uma criar
uma ação para que possamos criar novas observações para um artigo. Com esta ação irá encontrar um artigo com base no parâmetro article_id
, crie um comentário para este artigo e, em seguida redirecionar de volta para a página do artigo.
CommentsController < ApplicationController def create @article = Article.find(params[:article_id]) @comment = @article.comments.create!(params[:comment]) redirect_to @article, :notice => "Comment created!" end end
Finalmente, iremos adicionar algum código na view dos artigos, que irá mostrar os comentários de um artigo e permitir que os comentários sejam adicionados.
<% if @article.comments.size > 0 %> <h2>Comments</h2> <% for comment in @article.comments %> <h3><%= comment.name %></h3> <p><%= comment.content %></p> <% end %> <% end %> <h2>New Comment</h2> <%= form_for [@article, Comment.new] do |f| %> <p><%= f.label :name %> <%= f.text_field :name %></p> <p><%= f.text_area :content, :rows => 10 %></p> <p><%= f.submit %></p> <% end %>
Ao visitar a página de um artigo agora nós iremos ser capazes de criar um novo comentário e depois de ter submetido será mostrado abaixo do artigo.
Se dermos uma olhada no log do desenvolvimento, podemos ver as consultas do MongoDB. Quando criamos um comentário agora, essa consulta foi feita.
MONGODB blog_development['articles'].update({"_id"=>BSON::ObjectId('4cd01fa4a74209eacc000003')}, {"$push"=>{"comments"=>{"_id"=>BSON::ObjectId('4cd04c74a74209ecb4000002'), "name"=>"Eifion", "content"=>"I agree."}}})
As atualizações que consultam um modelo de artigo e acrescenta um novo comentário atribuir-lhe que os comentários não são armazenados separadamente. Isto significa que, se abrirmos o console do Rails e contar todos os comentários, teremos um resultado inesperado.
> Comment.count => 0
Os comentários que temos são incorporados em objetos e não estão disponíveis a nível global do documento. Para acessá-los, sempre temos que atravessar seu artigo associado.
> Article.first.comments.count => 1
Para chegar aos atributos de um comentário, nós sempre necessitamos começar esse comentário através de uma associação, como esta aplicação, os comentários são incorporados aos registros.
Tipo de associações de referências
Se queremos um registro associado que também esteja disponível como um documento separado, então iremos necessitar de um para criar uma associação de tipo de referência. Nós iremos demonstrar isso modificando o nosso pedido para que possamos associar cada artigo de um autor. Primeiro iremos gerar um scaffold para um modelo novo Autor
.
$ rails g scaffold author name:string
Antes de demonstrar associações vamos dar uma rápida olhada em um recurso interessante do Mongoid. Se nós adicionamos um método essencial para Mongoid classe de modelo que a key
> será usada como o id
para identificar esse modelo. Nós iremos fazer o nome do atributo a chave para o Autor
.
class Author include Mongoid::Document field :name key :name end
Se criarmos um autor, agora, quando estamos redirecionado para a página do autor, vamos ver o id
na URL.
Se vamos utilizar esse recurso, então iremos precisar de assegurar o campo que escolhemos para usar como uma chave não editável para que o documento tenha uma seqüência permanente como um id
que não vai mudar toda a vida do documento.
Voltar para associações de agora. Na classe Autor
usamos references_many
para definir o relacionamento com os artigos.
class Author include Mongoid::Document field :name key :name references_many :articles end
Então, no modelo de Artigo
que usamos o referenced_in
.
class Article include Mongoid::Document field :name field :content field :published_on, :type => Date validates_presence_of :name embeds_many :comments referenced_in :author end
Podemos agora usar essa associação como faríamos no ActiveRecord. Em nosso formulário para editar um artigo, podemos adicionar uma collection_select
para que possamos selecionar um autor quando criar ou atualizar um artigo.
<div class="field"> <%= f.label :author_id %><br /> <%= f.collection_select :author_id, Author.all, :id, :name %> </div>
Se modificarmos nosso artigo agora e selecionar um autor que vai pode ver que o autor do id
incorporado no artigo quando examiná-lo no console.
> Article.first => #<Article _id: 4cd01fa4a74209eacc000003, name: "Mongoid", content: "it's awesome!", published_on: 2010-11-02 00:00:00 UTC, author_id: "eifion-bedford">
Diferentemente da associação comentários, no entanto, podemos acessar o autor separadamente.
> Author.first => #<Author _id: eifion-bedford, name: "Eifion Bedford">
Isso é tudo para este episódio sobre Mongoid. Há muito que não temos tratado aqui, mas a documentação é bastante abrangente e irá dar-lhe quase tudo o que você precisa saber para usar o Mongoid e o MongoDB na sua aplicação Rails.