@@ -0,0 +1,317 @@ |
||
| 1 |
+# API |
|
| 2 |
+ |
|
| 3 |
+Neste documento vou explicar como criar uma **API** (Application Programming Interface) para um aplicativo **Rails**. Vou começar criando uma **API** simples, depois mostrando como criar versões dela, depois vou mostrar como criar um sistema de tokens para adicionar segurança e por ultimo vou criar um sistema de autenticação de usúarios via oAuth. |
|
| 4 |
+ |
|
| 5 |
+## Criando uma API basica |
|
| 6 |
+ |
|
| 7 |
+Em Qualquer controlador do rails, é possivel criar uma resposta em **JSON** além da resposta em **HTML**. |
|
| 8 |
+ |
|
| 9 |
+<pre><code class="ruby"> |
|
| 10 |
+class ProductsController < ApplicationController |
|
| 11 |
+ def index |
|
| 12 |
+ @products = Products.all |
|
| 13 |
+ respond_to do |format| |
|
| 14 |
+ format.html |
|
| 15 |
+ format.json { render json @products }
|
|
| 16 |
+ end |
|
| 17 |
+ end |
|
| 18 |
+end |
|
| 19 |
+</code></pre> |
|
| 20 |
+ |
|
| 21 |
+Ao entrar na página ```http://localhost:300/products.json```, você vai receber um arquivo em **JSON** com o conteúdo dos produtos. |
|
| 22 |
+ |
|
| 23 |
+## Criando rotas para a API |
|
| 24 |
+ |
|
| 25 |
+Para criar uma rota como ```http://localhost:3000/api```, modifique o arquivo ```config/rountes.rb``` |
|
| 26 |
+ |
|
| 27 |
+ Store::Application.routes.draw do |
|
| 28 |
+ namespace :api do |
|
| 29 |
+ # /api/... API:: |
|
| 30 |
+ namespace :api, defaults: {format: 'json'} do
|
|
| 31 |
+ namespace :v1 do |
|
| 32 |
+ resources :products |
|
| 33 |
+ end |
|
| 34 |
+ namespace :v2 do |
|
| 35 |
+ resources :products |
|
| 36 |
+ end |
|
| 37 |
+ end |
|
| 38 |
+ end |
|
| 39 |
+ |
|
| 40 |
+ resources :products |
|
| 41 |
+ root to: 'products#index' |
|
| 42 |
+ end |
|
| 43 |
+ |
|
| 44 |
+## O Controlador da API |
|
| 45 |
+ |
|
| 46 |
+Cria o arquivo ```/app/controllers/api/v1/products_controller.rb```: |
|
| 47 |
+ |
|
| 48 |
+ module Api |
|
| 49 |
+ module V1 |
|
| 50 |
+ class ProductsController < ApplicationController # ou API::BaseController |
|
| 51 |
+ |
|
| 52 |
+ # Hacks para que certos atributos continuem `backword compatiple` |
|
| 53 |
+ # Aqui estamos modificando a funcionalidade da classe neste controlador |
|
| 54 |
+ class Product < ::Product |
|
| 55 |
+ def as_json(options = {})
|
|
| 56 |
+ super.merge(released_on released_at.to_date) |
|
| 57 |
+ end |
|
| 58 |
+ end |
|
| 59 |
+ |
|
| 60 |
+ respond_to :json |
|
| 61 |
+ |
|
| 62 |
+ def index |
|
| 63 |
+ respond_with Product.all |
|
| 64 |
+ end |
|
| 65 |
+ |
|
| 66 |
+ def show |
|
| 67 |
+ respond_with Product.find(params[:id]) |
|
| 68 |
+ end |
|
| 69 |
+ |
|
| 70 |
+ def create |
|
| 71 |
+ respond_with Product.cerate(params[:product]) |
|
| 72 |
+ end |
|
| 73 |
+ |
|
| 74 |
+ def update |
|
| 75 |
+ respond_with Product.update(params[:id], params[:product]) |
|
| 76 |
+ end |
|
| 77 |
+ |
|
| 78 |
+ def destroy |
|
| 79 |
+ respond_with Product.destroy(params[:id]) |
|
| 80 |
+ end |
|
| 81 |
+ end |
|
| 82 |
+ end |
|
| 83 |
+ end |
|
| 84 |
+ |
|
| 85 |
+## Usando accept headers para versão da API |
|
| 86 |
+ |
|
| 87 |
+Em vez de usar um endereço como ```http://localhost:3000/api/v1/```, alguns sites como o [github](http://github.com) usam o **accept header** para especificar a versão do API. |
|
| 88 |
+ |
|
| 89 |
+Para configurar as rotas para ceitar o **accept header**, modifique o arquivo ```config/rountes.rb``` |
|
| 90 |
+ |
|
| 91 |
+ require 'api_constraints' |
|
| 92 |
+ |
|
| 93 |
+ Store::Application.routes.draw do |
|
| 94 |
+ namespace :api, defaults: {format: 'json'} do
|
|
| 95 |
+ scope module: :v1, constraints: ApiContraints.new(version: 1) do |
|
| 96 |
+ resources :products |
|
| 97 |
+ end |
|
| 98 |
+ scope module: :v2, constraints: ApiConstraints.new(version: 2, default: true) do |
|
| 99 |
+ resources :products |
|
| 100 |
+ end |
|
| 101 |
+ end |
|
| 102 |
+ |
|
| 103 |
+ resources :products |
|
| 104 |
+ root to: 'products#index' |
|
| 105 |
+ end |
|
| 106 |
+ |
|
| 107 |
+Depois no arquivo ```lib/api_constraints.rb```: |
|
| 108 |
+ |
|
| 109 |
+ class ApiConstraints |
|
| 110 |
+ def initialize(options) |
|
| 111 |
+ @version = options[:version] |
|
| 112 |
+ @default = options[:default] |
|
| 113 |
+ end |
|
| 114 |
+ |
|
| 115 |
+ def matches?(req) |
|
| 116 |
+ @default || req.headers['Accept'].include?("application/vnd.example.v#{@version}")
|
|
| 117 |
+ end |
|
| 118 |
+ end |
|
| 119 |
+ |
|
| 120 |
+Agora ao visitar a url ```http://localhost:3000/api/products```, você vai acessar o **API** v2 e receber o arquivo em **JSON**. |
|
| 121 |
+ |
|
| 122 |
+Para acessar outra versão da **API** via *curl* no *terminal*: |
|
| 123 |
+ |
|
| 124 |
+``` curl -H 'Accept: application.vnd.example.v1' http://localhost:3000/api.products ``` |
|
| 125 |
+ |
|
| 126 |
+## Autenticação basica |
|
| 127 |
+ |
|
| 128 |
+O jeito mas simples de restringir acesso ao **API** é usando a autenticação basica provida pelo **rails**. |
|
| 129 |
+ |
|
| 130 |
+ |
|
| 131 |
+No arquivo ```/app/controllers/api/v1/products_controller.rb```: |
|
| 132 |
+ |
|
| 133 |
+ module Api |
|
| 134 |
+ module V1 |
|
| 135 |
+ class ProductsController < ApplicationController |
|
| 136 |
+ http_basic_authenticate_with name: "admin", password: "secret" |
|
| 137 |
+ respond_to :json |
|
| 138 |
+ ... |
|
| 139 |
+ |
|
| 140 |
+Para testar, no terminal, digite o comando: |
|
| 141 |
+ |
|
| 142 |
+<pre><code class="bash"> |
|
| 143 |
+ $ curl http://localhost:3000/api/products |
|
| 144 |
+ HTTP Basic: Access denied. |
|
| 145 |
+ |
|
| 146 |
+ $ curl http://localhost:3000/api/products -I |
|
| 147 |
+ HTTP/1.1 401 Unauthorized |
|
| 148 |
+ WWW-Authenticate: Basic realm="Application" |
|
| 149 |
+ Content-Type: text/html; charset=utf-8 |
|
| 150 |
+ ... |
|
| 151 |
+ |
|
| 152 |
+ $ curl http://localhost:3000/api/products -u 'admin:secret' |
|
| 153 |
+ JSON response |
|
| 154 |
+ ... |
|
| 155 |
+</code></pre> |
|
| 156 |
+ |
|
| 157 |
+## Access Token |
|
| 158 |
+ |
|
| 159 |
+Em vez de usar um sistema de autenticação, podemos restringir acesso a API requerindo um **token de acesso**. Se na chamada para o API o cliente não enviar o **token**, o acesso será negado. |
|
| 160 |
+ |
|
| 161 |
+Primeiro vamos criar um modelo para guardar os **tokens**. Execute o comando: |
|
| 162 |
+ |
|
| 163 |
+ ```rails generate model api_key access_token``` |
|
| 164 |
+ |
|
| 165 |
+É possivel tb adicionar outras colunas como ```user_id``` para guardar o dono do **token**, ou ```expires_at``` para destruir chaves antigas ou a colona ```role``` para adicionar permissões diferentes para cada **token**. |
|
| 166 |
+ |
|
| 167 |
+Em seguida vamos modificar o modelo em ```app/models/api_key.rb```. Quando um novo *api_key* for criado, ele vai gerar um número randomico unico para está chave. |
|
| 168 |
+ |
|
| 169 |
+ class ApiKey < ActiveRecord::Base |
|
| 170 |
+ before_create :generate_access_token |
|
| 171 |
+ |
|
| 172 |
+ private |
|
| 173 |
+ |
|
| 174 |
+ def generate_access_token |
|
| 175 |
+ begin |
|
| 176 |
+ self.access_token = SecureRandom.hex |
|
| 177 |
+ end while self.class.exists?(access_token: access_token) |
|
| 178 |
+ end |
|
| 179 |
+ end |
|
| 180 |
+ |
|
| 181 |
+Para testar, entre no [console](rails_console.md) e digite o comando: ```ApiKey.create!```. Isso vai gerar um novo **access_token** com um número hexadecimal unico. |
|
| 182 |
+ |
|
| 183 |
+Agora vamos restringir o acesso ao **API** modificando o controlador. No arquivo ```/app/controllers/api/v1/products_controller.rb```: |
|
| 184 |
+ |
|
| 185 |
+ module Api |
|
| 186 |
+ module V1 |
|
| 187 |
+ class ProductsController < ApplicationController |
|
| 188 |
+ before_filter :restrict_access |
|
| 189 |
+ respond_to :json |
|
| 190 |
+ |
|
| 191 |
+ ... |
|
| 192 |
+ |
|
| 193 |
+ private |
|
| 194 |
+ |
|
| 195 |
+ def restrict_access |
|
| 196 |
+ api_key = ApiKey.find_by_access_token(params[:access_token]) |
|
| 197 |
+ head :unauthorized unless api_key |
|
| 198 |
+ end |
|
| 199 |
+ end |
|
| 200 |
+ end |
|
| 201 |
+ end |
|
| 202 |
+ |
|
| 203 |
+ |
|
| 204 |
+Para acessar o **API** com o **access_token**, podemos utilizar a seguinte url: |
|
| 205 |
+ |
|
| 206 |
+```http://localhost:3000/api/products?access_token=c576f0136149a2e2d9127b3901015545``` |
|
| 207 |
+ |
|
| 208 |
+Este metodo não é muito seguro, por que as pessoas podem copiar e colar os codigos de acesso junto com a url sem querer. Para melhorar este exemplo, vamos passar o **access_token** atravez de um parametro no *head* do *request* para o servidor. |
|
| 209 |
+ |
|
| 210 |
+Vamos mudar de novo o arquivo ```/app/controllers/api/v1/products_controller.rb```: |
|
| 211 |
+ |
|
| 212 |
+ def restrict_access |
|
| 213 |
+ authenticate_or_request_with_http_token do |token, options| |
|
| 214 |
+ ApiKey.exists?(access_token: token) |
|
| 215 |
+ end |
|
| 216 |
+ end |
|
| 217 |
+ |
|
| 218 |
+Para testar, no terminal vamos accessar de novo a url do **API** mas desta vez passando o **access_token** junto com o *header*: |
|
| 219 |
+ |
|
| 220 |
+```curl http://localhost:3000/api/products -H 'Authorization: Token token="c576f0136149a2e2d9127b3901015545"'``` |
|
| 221 |
+ |
|
| 222 |
+## Autenticação de usuários com OAuth |
|
| 223 |
+ |
|
| 224 |
+A questão das soluções anteriores é que estamos criando um sistema de autenticação global. Não temos como saber exatamente qual usuário está acessando a **API**. Então se você necessista de autenticação de usuário via o **API**, o jeito mais comum para fazer isso é utilizando o [OAuth2](http://oauth.net/2/). |
|
| 225 |
+ |
|
| 226 |
+> **OAauth** é um protocolo aberto para autorização segura de um **API** de um jeito simples e comum para aplicativos *web*, *mobile* e *desktop*. |
|
| 227 |
+ |
|
| 228 |
+O protocolo **OAuth** foi criado pela equipe do twitter e várias outras empresas adotaram e usam o protocolo como o Google, Facebook e GitHub. Ele é utilizado para que um aplicavo possa acessar informações de outro aplicativo através da autorização de um usúario. |
|
| 229 |
+ |
|
| 230 |
+O *gem* [doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) serve para simplificar a criação de um serviço de **OAuth** em um aplicativo *rails*. |
|
| 231 |
+ |
|
| 232 |
+### Configurando o DoorKeeper |
|
| 233 |
+ |
|
| 234 |
+Primeiro, mude para ```false``` a configuração ```whitelist_attributes``` no arquivo ```config/application.rb```: |
|
| 235 |
+ |
|
| 236 |
+ config_active_record.whitelist_attributes = false |
|
| 237 |
+ |
|
| 238 |
+Depois no ```gemfile``` adicione no fim: |
|
| 239 |
+ |
|
| 240 |
+ gem 'doorkeeper' |
|
| 241 |
+ |
|
| 242 |
+Execute o comando ```bundle install``` para instalar o *gem* e depois rode os comandos para instalar o **doorkeeper** e migrar o banco de dados: |
|
| 243 |
+ |
|
| 244 |
+ rails g doorkeeper:install |
|
| 245 |
+ rake db:migrate |
|
| 246 |
+ |
|
| 247 |
+Varias novos arquivos e tabelas no banco de dados vão ser criados. Em seguida modifique o arquivo ```config/initializers/doorkeeper.rb```: |
|
| 248 |
+ |
|
| 249 |
+ DoorKeeper.configure do |
|
| 250 |
+ |
|
| 251 |
+ resource_owner_authenticator do |routes| |
|
| 252 |
+ #raise "Please configure doorkeeper" |
|
| 253 |
+ # Put your resource owner authentication logic here |
|
| 254 |
+ # If you want to use named routes from your app you need |
|
| 255 |
+ # to call them on routes object eg. |
|
| 256 |
+ # routes.new_user_session_path |
|
| 257 |
+ User.find_by_id(session[:user_id]) || redirect_to(routes.new_user_session_url) |
|
| 258 |
+ end |
|
| 259 |
+ |
|
| 260 |
+ ... |
|
| 261 |
+ |
|
| 262 |
+ |
|
| 263 |
+### Repositorios |
|
| 264 |
+ |
|
| 265 |
+* [doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) - Doorkeeper is an OAuth 2 provider for Rails and Grape |
|
| 266 |
+* [ionic-doorkeeper](https://github.com/emilsoman/ionic-doorkeeper) - Sample ionic app that authenticates with a Rails API protected with Doorkeeper |
|
| 267 |
+ |
|
| 268 |
+### Links |
|
| 269 |
+ |
|
| 270 |
+* [OAuth Implicit Grant with Grape, Doorkeeper and AngularJS](http://codetunes.com/2014/oauth-implicit-grant-with-grape-doorkeeper-and-angularjs/) |
|
| 271 |
+* [How can I pre-authorize a client app for my user on my oauth provider that uses doorkeeper?](http://stackoverflow.com/questions/11129676/how-can-i-pre-authorize-a-client-app-for-my-user-on-my-oauth-provider-that-uses) |
|
| 272 |
+* [Using Resource Owner Password Credentials flow](https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Resource-Owner-Password-Credentials-flow) |
|
| 273 |
+* [Doorkeeper + Devise](http://morodeercoding.blogspot.ru/) |
|
| 274 |
+* [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) |
|
| 275 |
+ |
|
| 276 |
+ |
|
| 277 |
+## Criando um API com o Grape gem |
|
| 278 |
+ |
|
| 279 |
+### Repositorios |
|
| 280 |
+ |
|
| 281 |
+* [grape](https://github.com/intridea/grape) - An opinionated micro-framework for creating REST-like APIs in Ruby. |
|
| 282 |
+* [wine_bouncer](https://github.com/antek-drzewiecki/wine_bouncer) - A Ruby gem that allows Oauth2 protection with Doorkeeper for Grape Api's |
|
| 283 |
+* [grape-doorkeeper](https://github.com/fuCtor/grape-doorkeeper) - Integration Grape with Doorkeeper* |
|
| 284 |
+ |
|
| 285 |
+### Links |
|
| 286 |
+ |
|
| 287 |
+* [Build Great APIS with Grape](http://www.sitepoint.com/build-great-apis-grape/) |
|
| 288 |
+* [Introduction to building APIs with Grape](http://codetunes.com/2014/introduction-to-building-apis-with-grape/) |
|
| 289 |
+* [Building RESTful API using Grape in Rails](http://funonrails.com/2014/03/building-restful-api-using-grape-in-rails/) |
|
| 290 |
+* [OAuth 2.0 Tutorial: Protect Grape API with Doorkeeper](http://blog.yorkxin.org/posts/2013/11/05/oauth2-tutorial-grape-api-doorkeeper-en/) |
|
| 291 |
+* [authenticate grape api with doorkeeper](http://stackoverflow.com/questions/26472217/authenticate-grape-api-with-doorkeeper) |
|
| 292 |
+* [Grape API authentication using Devise Auth Token](http://funonrails.com/2014/03/api-authentication-using-devise-token/) |
|
| 293 |
+ |
|
| 294 |
+## Autenticação apenas com o Devise |
|
| 295 |
+ |
|
| 296 |
+### Links |
|
| 297 |
+ |
|
| 298 |
+* [APIs with Devise](http://soryy.com/blog/2014/apis-with-devise/) |
|
| 299 |
+* [API JSON authentication with Devise](https://gist.github.com/jwo/1255275) |
|
| 300 |
+ |
|
| 301 |
+## API Reference |
|
| 302 |
+ |
|
| 303 |
+* [A Well Designed API Approach](https://www.airpair.com/rest/posts/a-well-designed-api-approach) |
|
| 304 |
+ |
|
| 305 |
+ |
|
| 306 |
+ |
|
| 307 |
+----------------- |
|
| 308 |
+ |
|
| 309 |
+[Index](index.md) |
|
| 310 |
+ |
|
| 311 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 312 |
+ |
|
| 313 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 314 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 315 |
+<script> |
|
| 316 |
+ hljs.initHighlightingOnLoad(); |
|
| 317 |
+</script> |
@@ -1,9 +1,65 @@ |
||
| 1 |
-# Links |
|
| 1 |
+# Links e URLs |
|
| 2 | 2 |
|
| 3 |
-Em um **View**, para criar um **link** utilize a função ```link_to```. |
|
| 3 |
+## links |
|
| 4 | 4 |
|
| 5 |
-## Exemplo |
|
| 5 |
+Em um **View**, para criar um **link** utilize a função ```link_to```. Essa função gera uma tag ```<a>``` em HTML. |
|
| 6 |
+ |
|
| 7 |
+#### Exemplo |
|
| 6 | 8 |
|
| 7 | 9 |
<%= link_to("click here", {:action => 'index'}) %>
|
| 8 | 10 |
|
| 9 |
-<a class="btn btn-mini" href="readme.md">voltar</a> |
|
| 11 |
+## URLs |
|
| 12 |
+ |
|
| 13 |
+Para gerar apenas uma URL, utilize o comando ```url_for```. |
|
| 14 |
+ |
|
| 15 |
+ |
|
| 16 |
+### Opções |
|
| 17 |
+ |
|
| 18 |
+* ```:anchor``` - Especifica o *anchor* na url. Pode ser usada para ir direto a um *ID* na proxima pagina. |
|
| 19 |
+* ```:only_path``` - Boolean que especifica se o metodo deve retornar apenas a URL ou todas as informações (protocol, host, port). |
|
| 20 |
+* ```:format``` - Adiciona uma extensão ao final da URL |
|
| 21 |
+ |
|
| 22 |
+### Exemplos de URLs |
|
| 23 |
+ |
|
| 24 |
+ # http://www.example.com/posts |
|
| 25 |
+ url_for :controller => 'posts', :action => 'index' |
|
| 26 |
+ |
|
| 27 |
+ # http://www.example.com/posts/5 |
|
| 28 |
+ url_for :controller => 'posts', :action => 'index', :id => 5 |
|
| 29 |
+ |
|
| 30 |
+ # http://www.example.com/posts/5/edit |
|
| 31 |
+ url_for :controller => 'posts', :action => 'edit', :id => 5 |
|
| 32 |
+ |
|
| 33 |
+ # http://www.example.com/posts.xml |
|
| 34 |
+ url_for :controller=>'posts', :action=>'index', :format=>:xml |
|
| 35 |
+ |
|
| 36 |
+### namespace |
|
| 37 |
+ |
|
| 38 |
+Se você estiver usando um *namespace*, é possivel gerar uma url do seguinte jeito: |
|
| 39 |
+ |
|
| 40 |
+ namespace :admin do |
|
| 41 |
+ resources :products |
|
| 42 |
+ end |
|
| 43 |
+ then you can: |
|
| 44 |
+ |
|
| 45 |
+ url_for([:admin, @product]) |
|
| 46 |
+ and: |
|
| 47 |
+ |
|
| 48 |
+ url_for([:edit, :admin, @product]) |
|
| 49 |
+ |
|
| 50 |
+----------------- |
|
| 51 |
+## Informações adicionais |
|
| 52 |
+ |
|
| 53 |
+* [Rails routing - RailsGuides](http://guides.rubyonrails.org/routing.html) |
|
| 54 |
+ |
|
| 55 |
+----------------- |
|
| 56 |
+ |
|
| 57 |
+[Index](index.md) |
|
| 58 |
+ |
|
| 59 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 60 |
+ |
|
| 61 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 62 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 63 |
+<script> |
|
| 64 |
+ hljs.initHighlightingOnLoad(); |
|
| 65 |
+</script> |
@@ -1,5 +1,7 @@ |
||
| 1 | 1 |
# Postgres |
| 2 | 2 |
|
| 3 |
+## Configuração do BD para projeto Rails |
|
| 4 |
+ |
|
| 3 | 5 |
Para criar um banco de dados postgres primeiro faça o login no banco de dados: |
| 4 | 6 |
|
| 5 | 7 |
``$ psql --username=admin`` |
@@ -45,3 +47,10 @@ Por ultimo configure o arquivo ``database.yml `` com as informações de login e |
||
| 45 | 47 |
pool: 5 |
| 46 | 48 |
username: admin |
| 47 | 49 |
password: password1 |
| 50 |
+ |
|
| 51 |
+## Outros comandos |
|
| 52 |
+ |
|
| 53 |
+* ``\l`` - Listar bancos de dados |
|
| 54 |
+* ``\c database_name`` - selecionar banco de dados |
|
| 55 |
+* ``\d`` - Listar tabelas de um banco de dados |
|
| 56 |
+* ``DROP TABLE table_name`` - Deletar uma tabela de um banco de dados |
@@ -182,4 +182,22 @@ Neste exemplo vamos criar um log de edição das páginas do sistema. |
||
| 182 | 182 |
belongs_to :editor, :class_name => "User", :foreign_key => "user_id" |
| 183 | 183 |
end |
| 184 | 184 |
|
| 185 |
-#### Traversing |
|
| 185 |
+#### Traversing |
|
| 186 |
+ |
|
| 187 |
+ |
|
| 188 |
+----------------- |
|
| 189 |
+## Informações adicionais |
|
| 190 |
+ |
|
| 191 |
+* [A Rule of Thumb for Strong Parameters](http://patshaughnessy.net/2014/6/16/a-rule-of-thumb-for-strong-parameters) |
|
| 192 |
+ |
|
| 193 |
+----------------- |
|
| 194 |
+ |
|
| 195 |
+[Index](index.md) |
|
| 196 |
+ |
|
| 197 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 198 |
+ |
|
| 199 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 200 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 201 |
+<script> |
|
| 202 |
+ hljs.initHighlightingOnLoad(); |
|
| 203 |
+</script> |
@@ -0,0 +1,24 @@ |
||
| 1 |
+# Terminal/Bash |
|
| 2 |
+ |
|
| 3 |
+ |
|
| 4 |
+* ```TAB``` - Autocompleta o atual comando |
|
| 5 |
+* ```!!``` - Repedir o ultimo comando |
|
| 6 |
+* ```control-r``` - Buscar por um comando anterior |
|
| 7 |
+* ```source ~/bash.profile``` - Recarrega o *bash.profile* na atual aba do terminal. Util para quando você está editando susas preferencias. |
|
| 8 |
+* ```$EDITOR``` variavel que determina qual editor de texto o terminal deve usar. |
|
| 9 |
+ |
|
| 10 |
+#### Links |
|
| 11 |
+ |
|
| 12 |
+* [Know your tools](http://www.spacecowboyrocketcompany.com/2015/02/know-your-tools/) |
|
| 13 |
+ |
|
| 14 |
+----------------- |
|
| 15 |
+ |
|
| 16 |
+[Index](index.md) |
|
| 17 |
+ |
|
| 18 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 19 |
+ |
|
| 20 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 21 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 22 |
+<script> |
|
| 23 |
+ hljs.initHighlightingOnLoad(); |
|
| 24 |
+</script> |
@@ -0,0 +1,70 @@ |
||
| 1 |
+# Console |
|
| 2 |
+ |
|
| 3 |
+## Configurações |
|
| 4 |
+ |
|
| 5 |
+O arquivo ```~/.irbrc``` serve para configurar o console. Ele fica no root da pasta de usuário no sistema operacional. Esse arquivo funciona como um arquvo de *.rb* comum e vai ser rodado toda vez que o IRB iniciar. |
|
| 6 |
+ |
|
| 7 |
+Para editar ou criar esse arquivo, digite no terminal: |
|
| 8 |
+ |
|
| 9 |
+```pico ~/.irbrc``` |
|
| 10 |
+ |
|
| 11 |
+Para sair do editor **pico** aperte **ctrl + x** para fechar o arquivo e confirme que quer salvar e o nome do arquivo apertando **enter**. |
|
| 12 |
+ |
|
| 13 |
+## Truques |
|
| 14 |
+ |
|
| 15 |
+### HIRB |
|
| 16 |
+ |
|
| 17 |
+O HIRB serve para melhorar a visualização do *ActiveRecord*. Ele muda o jeito como o IRB mostra os dados retornados para o usuário, criando uma tabela que pode ser customizada. |
|
| 18 |
+ |
|
| 19 |
+Muito util para poder visualizar os dados do que você está fazendo no console do rails e não ficar precisando caçar as informações perdidas dentro de um *hash* gigante. |
|
| 20 |
+ |
|
| 21 |
+#### Instalação |
|
| 22 |
+ |
|
| 23 |
+Adicione ao ```/Gemfile```: |
|
| 24 |
+ |
|
| 25 |
+ gem 'hirb' |
|
| 26 |
+ |
|
| 27 |
+Depois adicione ao arquivo ```~/.irbrc``` as seguintes configurações: |
|
| 28 |
+ |
|
| 29 |
+ require 'hirb' |
|
| 30 |
+ Hirb.enable |
|
| 31 |
+ |
|
| 32 |
+### Wirble |
|
| 33 |
+ |
|
| 34 |
+O wirble é um **gem** que serve para melhorar o *console* do rails. |
|
| 35 |
+ |
|
| 36 |
+#### Instalação |
|
| 37 |
+ |
|
| 38 |
+Adicione ao ```/Gemfile```: |
|
| 39 |
+ |
|
| 40 |
+ gem 'wirble' |
|
| 41 |
+ |
|
| 42 |
+Depois adicione ao arquivo ```~/.irbrc``` as seguintes configurações: |
|
| 43 |
+ |
|
| 44 |
+ begin |
|
| 45 |
+ require 'wirble' |
|
| 46 |
+ # init wirble |
|
| 47 |
+ Wirble.init |
|
| 48 |
+ # enable color |
|
| 49 |
+ Wirble.colorize |
|
| 50 |
+ Wirble::Colorize::DEFAULT_COLORS |
|
| 51 |
+ rescue LoadError => err |
|
| 52 |
+ $stderr.puts "Couldn't load Wirble: #{err}"
|
|
| 53 |
+ end |
|
| 54 |
+ |
|
| 55 |
+#### Links |
|
| 56 |
+ |
|
| 57 |
+* [Mais informações](http://pablotron.org/software/wirble/) |
|
| 58 |
+* [Readme.md](http://pablotron.org/software/wirble/README) |
|
| 59 |
+ |
|
| 60 |
+----------------- |
|
| 61 |
+ |
|
| 62 |
+[Index](index.md) |
|
| 63 |
+ |
|
| 64 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 65 |
+ |
|
| 66 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 67 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 68 |
+<script> |
|
| 69 |
+ hljs.initHighlightingOnLoad(); |
|
| 70 |
+</script> |
@@ -1,8 +1,10 @@ |
||
| 1 | 1 |
# Cucumber |
| 2 | 2 |
|
| 3 |
-Behavior driven development |
|
| 3 |
+*Behavior driven development* |
|
| 4 | 4 |
|
| 5 |
-### Instalação |
|
| 5 |
+O Cucumber é um framework de alto nivel para criação de testes baseado em historias de interações de usuários. Sua grande vantagem é que os testes são escritos em uma lingua comum como o inglês (ou outras linguas utilizando plugins). |
|
| 6 |
+ |
|
| 7 |
+## Instalação |
|
| 6 | 8 |
|
| 7 | 9 |
1- no arquivo ```Gemfile```: |
| 8 | 10 |
|
@@ -29,11 +31,27 @@ Uma pasta chamada ```app/features``` foi criada. |
||
| 29 | 31 |
5- Para rodar o cucumber, utilize o comando rake: ```$ cucumber features -n``` |
| 30 | 32 |
|
| 31 | 33 |
|
| 32 |
-### Features |
|
| 34 |
+## Como funciona |
|
| 33 | 35 |
|
| 34 | 36 |
1. Cenario |
| 35 | 37 |
2. Feature |
| 36 | 38 |
3. Steps |
| 37 | 39 |
4. Background |
| 38 | 40 |
5. Paths |
| 39 |
-6. Factories |
|
| 41 |
+6. Factories |
|
| 42 |
+ |
|
| 43 |
+#### Links |
|
| 44 |
+ |
|
| 45 |
+* [RailsCast Cucumber Tutorial](https://www.evernote.com/l/AALzqmI0XeBD7rP9wL83vkSYnKMwjdSvduA) [(local version)](evernote:///view/124245/s2/f3aa6234-5de0-43ee-b3fd-c0bf37be4498/f3aa6234-5de0-43ee-b3fd-c0bf37be4498/) |
|
| 46 |
+ |
|
| 47 |
+----------------- |
|
| 48 |
+ |
|
| 49 |
+[Index](index.md) |
|
| 50 |
+ |
|
| 51 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 52 |
+ |
|
| 53 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 54 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 55 |
+<script> |
|
| 56 |
+ hljs.initHighlightingOnLoad(); |
|
| 57 |
+</script> |
@@ -0,0 +1,26 @@ |
||
| 1 |
+# Devise Invitable |
|
| 2 |
+ |
|
| 3 |
+O gem [devise_invitable](https://github.com/scambra/devise_invitable) serve para estender a funcionalidade do devise para possibilitar a criação de usuários através de convites. |
|
| 4 |
+ |
|
| 5 |
+#### Links |
|
| 6 |
+ |
|
| 7 |
+* [Using Devise Invitable](http://aaronmiler.com/blog/using-devise-invitable/) |
|
| 8 |
+* [Customizing for different Invite use cases](https://github.com/scambra/devise_invitable/wiki/Customizing-for-different-Invite-use-cases-(emails-etc.)) |
|
| 9 |
+* [The best way to approach handling invitations of existing users](https://github.com/scambra/devise_invitable/issues/506) |
|
| 10 |
+* [Devise invitable: invite existing user](http://stackoverflow.com/questions/18226102/devise-invitable-invite-existing-user) |
|
| 11 |
+* [Overide mailer in devise_invitable?](http://www.ciiycode.com/06izzgPPqqPQ/overide-mailer-in-deviseinvitable) |
|
| 12 |
+* [Devise Invitable optional custom message](http://stackoverflow.com/questions/9841700/devise-invitable-optional-custom-message) |
|
| 13 |
+* [How do I delete an invitation with devise_invitable?](http://stackoverflow.com/questions/19646175/how-do-i-delete-an-invitation-with-devise-invitable) |
|
| 14 |
+* [How to override devise invitable actions](http://stackoverflow.com/questions/18191010/how-to-override-devise-invitable-actions) |
|
| 15 |
+ |
|
| 16 |
+----------------- |
|
| 17 |
+ |
|
| 18 |
+[Index](index.md) |
|
| 19 |
+ |
|
| 20 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 21 |
+ |
|
| 22 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 23 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 24 |
+<script> |
|
| 25 |
+ hljs.initHighlightingOnLoad(); |
|
| 26 |
+</script> |
@@ -0,0 +1,170 @@ |
||
| 1 |
+# Faye |
|
| 2 |
+ |
|
| 3 |
+[Faye](http://faye.jcoglan.com/) é um sistema para subscrever e enviar mensagens baseado no protocolo *Bayeux* (Pub/Sub). O **Faye** providencia um **servidor** de mensagens para ser usado com *node.js* ou *Ruby* além de uma biblioteca em *Javascript* para os **clientes** que funciona em todos os browsers modernos. |
|
| 4 |
+ |
|
| 5 |
+## Instalação |
|
| 6 |
+ |
|
| 7 |
+Primeiro instale o gem executando o comando: ```gem install faye``` |
|
| 8 |
+ |
|
| 9 |
+Adicione o **faye** e o servidor **thin** ao gemfile: |
|
| 10 |
+ |
|
| 11 |
+ gem 'faye' |
|
| 12 |
+ gem 'thin' |
|
| 13 |
+ |
|
| 14 |
+Em seguida rode o comando ```bundle install``` para instalar os *gems*. |
|
| 15 |
+ |
|
| 16 |
+Crie o arquivo ```faye.ru``` na raiz da pasta do projeto. Este arquivo vai inicializar o servidor **faye**. |
|
| 17 |
+ |
|
| 18 |
+ require 'faye' |
|
| 19 |
+ Faye::WebSocket.load_adapter('thin')
|
|
| 20 |
+ faye_server = Faye::RackAdapter.new(:mount => 'faye', :timeout => 45) |
|
| 21 |
+ run faye_server |
|
| 22 |
+ |
|
| 23 |
+Depois rode o seguinte comando para inicializar o servidor: |
|
| 24 |
+ |
|
| 25 |
+```rackup faye.ru -s thin -E product``` |
|
| 26 |
+ |
|
| 27 |
+Para fazer os dois servidores iniciarem juntos em *development*, modifique o arquivo ```Procfile```: |
|
| 28 |
+ |
|
| 29 |
+ web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb |
|
| 30 |
+ faye: rackup faye.ru -s thin -E production |
|
| 31 |
+ |
|
| 32 |
+Depois execute o comando ```foreman start``` para iniciar o servidor |
|
| 33 |
+ |
|
| 34 |
+O servidor **faye** vai iniciar em ```0.0.0.0:9292```. Este servidor vai estar servidondo um arquivo *javascript* que precisa ser adicionado no layout da página no rails: |
|
| 35 |
+ |
|
| 36 |
+ <%= javascript_include_tag :defaults, "http://localhost:9292/faye.js" %> |
|
| 37 |
+ |
|
| 38 |
+ |
|
| 39 |
+Em seguida, vamos criar a função para subscrever e enviar mensagens para o servidor. Abra o arquivo ```app/assets/javascripts/application.js```: |
|
| 40 |
+ |
|
| 41 |
+ $(function() {
|
|
| 42 |
+ var faye = new Faye.Client('http://localhost:9292/faye');
|
|
| 43 |
+ faye.subscribe("messages/new", function(data){
|
|
| 44 |
+ alert(data); |
|
| 45 |
+ }); |
|
| 46 |
+ }); |
|
| 47 |
+ |
|
| 48 |
+Para fazer um teste, é possivel enviar uma mensagem via **curl**. Primeiro entre ná página no navegador, depois no terminal execute o comando: |
|
| 49 |
+ |
|
| 50 |
+``` curl http://localhost:9292/faye -d 'message={"channel":"/messages/new", "data":"hello" }'```
|
|
| 51 |
+ |
|
| 52 |
+Ao executar esse comando, o navegador ira receber uma mensagem com o conteúdo do comando. |
|
| 53 |
+ |
|
| 54 |
+## Exemplo: Chat |
|
| 55 |
+ |
|
| 56 |
+Adicione um *view* com uma lista e um formulário para novas mensagens: |
|
| 57 |
+ |
|
| 58 |
+ <ul id="chat"> |
|
| 59 |
+ <%= render @messages %> |
|
| 60 |
+ </ul> |
|
| 61 |
+ |
|
| 62 |
+ <%= form_for Message.new, remote => true do |f| %> |
|
| 63 |
+ <%= f.text_field :content %> |
|
| 64 |
+ <%= f.submit "Send" %> |
|
| 65 |
+ <% end %> |
|
| 66 |
+ |
|
| 67 |
+Crie mais um *view* com o nome de ```create.js.erb``` para resposta do servidor em *JSON*: |
|
| 68 |
+ |
|
| 69 |
+ <% broadcast "/messages/new" do %> |
|
| 70 |
+ $("#chat").append("<%= escape_javascript render(@message) %>");
|
|
| 71 |
+ <% end %> |
|
| 72 |
+ $("#new_message")[0].reset();
|
|
| 73 |
+ |
|
| 74 |
+Toda vez que uma mensagem for enviada pela página e criada no servidor, o bloco de codigo dentro da função ```broadcast``` vai ser enviado via o faye para todos os clientes que estão assinando este canal. |
|
| 75 |
+ |
|
| 76 |
+Agora precisamos criar a função ```broadcast```. No arquivo ```app/helpers/application_helper.rb``` adicione a função: |
|
| 77 |
+ |
|
| 78 |
+ module ApplicationHelper |
|
| 79 |
+ def broadcast(channel, &block) |
|
| 80 |
+ message = { :channel => channel, :data => capture(&block)}
|
|
| 81 |
+ uri = URI.parse("http://localhost:9292/faye")
|
|
| 82 |
+ Net::HTTP.post_form(uri, :message => message.to_json) |
|
| 83 |
+ end |
|
| 84 |
+ end |
|
| 85 |
+ |
|
| 86 |
+Pelo fato de estarmos usando a biblioteca **Net:HTTP**, precisamos requerer ela em algum lugar do aplicativo rails. Um bom lugar para se fazer isso é no arquivo ```config/application.rb```. |
|
| 87 |
+ |
|
| 88 |
+ require "rails/all" |
|
| 89 |
+ require "net/http" |
|
| 90 |
+ |
|
| 91 |
+Por ultimo temos que fazer uma mudança no arquivo ```app/assets/javascripts/application.js```. Em vez de um alerta, o navegador precisa executar o codigo que for recebido do servidor **faye**: |
|
| 92 |
+ |
|
| 93 |
+ $(function() {
|
|
| 94 |
+ var faye = new Faye.Client('http://localhost:9292/faye');
|
|
| 95 |
+ faye.subscribe("messages/new", function(data){
|
|
| 96 |
+ eval(data); |
|
| 97 |
+ }); |
|
| 98 |
+ }); |
|
| 99 |
+ |
|
| 100 |
+Agora ao enviar uma mensagem no formulário da página, todas as instancias abertas da página iram receber a modificação instantaneamente. |
|
| 101 |
+ |
|
| 102 |
+## Segurança |
|
| 103 |
+ |
|
| 104 |
+É necessário criar um protocolo de segurança, se não qualquer um pode tentar enviar uma mensagem via **curl** para o servidor e rodar *javascript* em todos os clientes que estnao subscrevendo ao sistema do **Faye**. |
|
| 105 |
+ |
|
| 106 |
+Para resolver isso, precisamos criar uma extenção no servidor **Faye** para lidar com a segurança. Veja mais informações [aqui](http://faye.jcolan.com/ruby.html). |
|
| 107 |
+ |
|
| 108 |
+Basicamente vamos criar uma nova classe que vai conter funções para mensagens entrando e saindo do servidor. Cada uma dessas funções vai fazer um cheque e se algo estiver errado a função levanta um *erro*. Depois criamos uma instancia dessa classe e adicionamos ela como uma extenção do servidor **Faye**. |
|
| 109 |
+ |
|
| 110 |
+Primeiro vamos criar um **token** que vai ser enviado junto com as mensagens pelo servidor. Se a mensagem não conter o **token**, o servidor vai levantar um erro. |
|
| 111 |
+ |
|
| 112 |
+No arquivo ```config/application.yml``` adicione uma nova **env variable**: |
|
| 113 |
+ |
|
| 114 |
+ FAYE_SECRET_OKEN: 12345678901234567890 |
|
| 115 |
+ |
|
| 116 |
+Depois precisamos modificar a função **broadcast** em ```app/helpers/application_helper.rb```: |
|
| 117 |
+ |
|
| 118 |
+ module ApplicationHelper |
|
| 119 |
+ def broadcast(channel, &block) |
|
| 120 |
+ message = { :channel => channel, :data => capture(&block), ext => {:auth_token => env['FAYE_SECRET_OKEN']}}
|
|
| 121 |
+ uri = URI.parse("http://localhost:9292/faye")
|
|
| 122 |
+ Net::HTTP.post_form(uri, :message => message.to_json) |
|
| 123 |
+ end |
|
| 124 |
+ end |
|
| 125 |
+ |
|
| 126 |
+Por último, no arquivo ```faye.ru``` precisamos criar a classe que vai lidar com a autenticação: |
|
| 127 |
+ |
|
| 128 |
+ require 'faye' |
|
| 129 |
+ |
|
| 130 |
+ class ServerAuth |
|
| 131 |
+ def incoming(message, callback) |
|
| 132 |
+ if message['channel'] !~ %r{^/meta/}
|
|
| 133 |
+ if message['ext']['auth_token'] != env['FAYE_SECRET_OKEN'] |
|
| 134 |
+ message['error'] = 'Invalid authentication token' |
|
| 135 |
+ end |
|
| 136 |
+ end |
|
| 137 |
+ callback.call(message) |
|
| 138 |
+ end |
|
| 139 |
+ end |
|
| 140 |
+ |
|
| 141 |
+ faye_server = Faye::RackAdapter.new(:mount => 'faye', :timeout => 45) |
|
| 142 |
+ faye_server.add_extension(ServerAuth.new) |
|
| 143 |
+ run faye_server |
|
| 144 |
+ |
|
| 145 |
+Ao reiniciar o servidor e tentar enviar uma nova mensagem via **curl** sem o token de autenticação, vamos receber um erro: |
|
| 146 |
+ |
|
| 147 |
+ $ curl http://localhost:9292/faye -d 'message={"channel":"/messages/new", "data":"hello" }
|
|
| 148 |
+ HTTP/1.1 400 Bad Request |
|
| 149 |
+ Content-Type: application/json |
|
| 150 |
+ Connection: close |
|
| 151 |
+ Server: thin 1.2.11 codename Bat-Shit Crazy |
|
| 152 |
+ content-Length: 11 |
|
| 153 |
+ |
|
| 154 |
+Mas ao enviar a mensagem atravez da página em rails, a autenticação vai funcionar e a mensagem vai ser recebida por todos que estão subscrevendo a página. |
|
| 155 |
+ |
|
| 156 |
+## Outros recursos |
|
| 157 |
+ |
|
| 158 |
+ |
|
| 159 |
+ |
|
| 160 |
+----------------- |
|
| 161 |
+ |
|
| 162 |
+[Index](index.md) |
|
| 163 |
+ |
|
| 164 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 165 |
+ |
|
| 166 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 167 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 168 |
+<script> |
|
| 169 |
+ hljs.initHighlightingOnLoad(); |
|
| 170 |
+</script> |
@@ -2,15 +2,14 @@ |
||
| 2 | 2 |
|
| 3 | 3 |
## Instalação do [Font Custom](http://fontcustom.com/) |
| 4 | 4 |
|
| 5 |
-1. Primeiro instale o [XQuartz](https://xquartz.macosforge.org) |
|
| 5 |
+Primeiro instale o [XQuartz](https://xquartz.macosforge.org) |
|
| 6 | 6 |
|
| 7 |
-2. Rode os seguintes comandos para instalar a ferramenta: |
|
| 8 |
- |
|
| 9 |
-```bash |
|
| 7 |
+Depois rode os seguintes comandos para instalar a ferramenta: |
|
| 8 |
+ |
|
| 10 | 9 |
brew install fontforge --with-python |
| 11 | 10 |
brew install eot-utils |
| 12 | 11 |
gem install fontcustom |
| 13 |
-``` |
|
| 12 |
+ |
|
| 14 | 13 |
|
| 15 | 14 |
## Utilização |
| 16 | 15 |
|
@@ -21,4 +20,16 @@ Para criar um arquivo de configuração, rode o comando ```fontcustom config /pa |
||
| 21 | 20 |
## Links |
| 22 | 21 |
|
| 23 | 22 |
* [FontCustom](http://fontcustom.com/) |
| 24 |
-* [FontCustom GitHub Page](https://github.com/FontCustom/fontcustom/) |
|
| 23 |
+* [FontCustom GitHub Page](https://github.com/FontCustom/fontcustom/) |
|
| 24 |
+ |
|
| 25 |
+----------------- |
|
| 26 |
+ |
|
| 27 |
+[Index](index.md) |
|
| 28 |
+ |
|
| 29 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 30 |
+ |
|
| 31 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 32 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 33 |
+<script> |
|
| 34 |
+ hljs.initHighlightingOnLoad(); |
|
| 35 |
+</script> |
@@ -91,6 +91,10 @@ Para ver informações sobre uma tag: |
||
| 91 | 91 |
|
| 92 | 92 |
```git show v1.4``` |
| 93 | 93 |
|
| 94 |
+Ao usar o comando ```git push```, as **tags** não são transferidas junto com o resto do projeto. É necessario transferir cada **tag** separadamente. Exemplo: |
|
| 95 |
+ |
|
| 96 |
+```git push origin v1.4``` |
|
| 97 |
+ |
|
| 94 | 98 |
### Links |
| 95 | 99 |
|
| 96 | 100 |
- [12 curated git tips and workflow](http://durdn.com/blog/2012/12/05/git-12-curated-git-tips-and-workflows/) |
@@ -27,7 +27,8 @@ |
||
| 27 | 27 |
22. [Helpers](helpers.md) |
| 28 | 28 |
23. [SimpleForm](SimpleForm.md) |
| 29 | 29 |
24. [Nested Model Forms](nested_model.md) |
| 30 |
-25. [Autenticação de usuários com o Devise](devise.md) |
|
| 30 |
+25. [Devise](devise.md) |
|
| 31 |
+26. [Devise Invitable](devise_invitable.md) |
|
| 31 | 32 |
26. [Upload de arquivos com o CarrierWave](CarrierWave.md) |
| 32 | 33 |
27. [jQuery File Upload](jQuery_file_upload.md) |
| 33 | 34 |
28. [Testes](testes.md) |
@@ -37,5 +38,10 @@ |
||
| 37 | 38 |
32. [Funções de tempo](time_ago.md) |
| 38 | 39 |
33. [Font Custom](fontcustom.md) |
| 39 | 40 |
33. [Mailer](mailer.md) |
| 41 |
+34. [Console](console.md) |
|
| 42 |
+35. [Resque](resque.md) |
|
| 43 |
+36. [Bash](bash.md) |
|
| 44 |
+37. [Faye](faye.md) |
|
| 45 |
+38. [API](API.md) |
|
| 40 | 46 |
|
| 41 | 47 |
*[Links de referencia](links_referencias.md)* |
@@ -40,6 +40,23 @@ Vamos agora criar uma novo metodo para enviar um email de boas vindas aos usuár |
||
| 40 | 40 |
end |
| 41 | 41 |
end |
| 42 | 42 |
|
| 43 |
+## Criando um view |
|
| 44 |
+ |
|
| 45 |
+Crie os seguintes arquivos para os *Views*: |
|
| 46 |
+ |
|
| 47 |
+* ```app/views/user_mailer/welcome_email.html.erb``` |
|
| 48 |
+* ```app/views/user_mailer/welcome_email.text.erb``` |
|
| 49 |
+ |
|
| 50 |
+Esses arquivos correspondem as duas versões do email, uma em HTML e outra em texto. As duas são enviadas e o programa em que o usuário está lendo o email decide qual versão mostrar. |
|
| 51 |
+ |
|
| 52 |
+#### Links |
|
| 53 |
+ |
|
| 54 |
+* [ActionMailer Basics - RailsGuides](http://guides.rubyonrails.org/action_mailer_basics.html) |
|
| 55 |
+ |
|
| 56 |
+----------------- |
|
| 57 |
+ |
|
| 58 |
+[Index](index.md) |
|
| 59 |
+ |
|
| 43 | 60 |
<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
| 44 | 61 |
|
| 45 | 62 |
<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
@@ -2,7 +2,7 @@ |
||
| 2 | 2 |
|
| 3 | 3 |
Rails **gem** para simplificar o manuseio de varios modelos associados em um único formulario. Ele faz isso de um jeito discreto utilizando *jQuery*. |
| 4 | 4 |
|
| 5 |
-#### Instalação |
|
| 5 |
+## Instalação |
|
| 6 | 6 |
|
| 7 | 7 |
Adicione o **gem** no ```gemfile``` e rode o comando ```$ bundle install```: |
| 8 | 8 |
|
@@ -20,9 +20,31 @@ Inclua o *JavaScript* gerado no layout: |
||
| 20 | 20 |
|
| 21 | 21 |
<%= javascript_include_tag :defaults, "nested_form" %> |
| 22 | 22 |
|
| 23 |
-#### Utilização |
|
| 23 |
+## Utilização |
|
| 24 | 24 |
|
| 25 |
-#### Links |
|
| 25 |
+Escrever... |
|
| 26 | 26 |
|
| 27 |
-- [nested_form (GitHub)](https://github.com/ryanb/nested_form) |
|
| 28 |
-- [Dynamic Nested Forms in Rails 3 (madebydna blog)](http://blog.madebydna.com/all/code/2010/10/07/dynamic-nested-froms-with-the-nested-form-gem.html) |
|
| 27 |
+----------------- |
|
| 28 |
+ |
|
| 29 |
+## Informações adicionais |
|
| 30 |
+ |
|
| 31 |
+- [Working with nested forms and a many-to-many association in Rails 4](http://www.createdbypete.com/articles/working-with-nested-forms-and-a-many-to-many-association-in-rails-4/) |
|
| 32 |
+- [Dynamic Nested Forms in Rails 3 (madebydna blog)](http://blog.madebydna.com/all/code/2010/10/07/dynamic-nested-froms-with-the-nested-form-gem.html) |
|
| 33 |
+- [ActiveRecord nested attributes](http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for) |
|
| 34 |
+ |
|
| 35 |
+## Recursos |
|
| 36 |
+ |
|
| 37 |
+- [ryanb/nested_form](https://github.com/ryanb/nested_form) - ruby gem para simplificar o processo de criação de nested forms |
|
| 38 |
+ |
|
| 39 |
+ |
|
| 40 |
+----------------- |
|
| 41 |
+ |
|
| 42 |
+[Index](index.md) |
|
| 43 |
+ |
|
| 44 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 45 |
+ |
|
| 46 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 47 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 48 |
+<script> |
|
| 49 |
+ hljs.initHighlightingOnLoad(); |
|
| 50 |
+</script> |
@@ -0,0 +1,17 @@ |
||
| 1 |
+# Resque |
|
| 2 |
+ |
|
| 3 |
+ |
|
| 4 |
+ Resque.enqueue(WorkerName, vars) |
|
| 5 |
+ |
|
| 6 |
+ |
|
| 7 |
+----------------- |
|
| 8 |
+ |
|
| 9 |
+[Index](index.md) |
|
| 10 |
+ |
|
| 11 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 12 |
+ |
|
| 13 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 14 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 15 |
+<script> |
|
| 16 |
+ hljs.initHighlightingOnLoad(); |
|
| 17 |
+</script> |
@@ -46,4 +46,14 @@ Exitem varios tipos de testes: |
||
| 46 | 46 |
- Rcov |
| 47 | 47 |
- Autotest |
| 48 | 48 |
|
| 49 |
-<hr><a class="btn btn-mini" href="readme.md">voltar</a> |
|
| 49 |
+----------------- |
|
| 50 |
+ |
|
| 51 |
+[Index](index.md) |
|
| 52 |
+ |
|
| 53 |
+<!-- Highlight syntax for Mou.app, insert at the bottom of the markdown document --> |
|
| 54 |
+ |
|
| 55 |
+<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script> |
|
| 56 |
+<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/github.min.css"> |
|
| 57 |
+<script> |
|
| 58 |
+ hljs.initHighlightingOnLoad(); |
|
| 59 |
+</script> |