Вы находитесь на странице: 1из 48

Table of Contents

1. Introduccin
2. Ruby
i. Cdigo y sintaxis
i. Nombramientos
ii. Colecciones
iii. Operadores logicos
iv. Literales
v. Idiomas
vi. Multilinea
vii. Comentarios y anotaciones
i. Anotaciones
viii. Modulos clases y variables
ix. Excepciones
x. Cadenas de caracteres
3. Ruby on Rails
i. Engines (Balloom)
ii. Assets
iii. Modelos
iv. Controladores
v. Vistas
vi. Seguridad
vii. Helpers
4. Navegadores
5. SEO
6. Bibliografia
Introduccin
Este libro es una recopilacin de buenas practicas a la hora de programar que han sido extraidos de
varios posts, libros, pginas externas y conocimientos que el autor ha tenido a lo largo de su carrera.

En la seccin de Bibliografa, podrs encontrar los enlaces de las paginas en donde se ha extraido la
mayor parte de informacin contenida en este libro asi como tambien muchos enlaces de interes.
Ruby
Ruby es un lenguaje multiplataforma, interpretado y orientado a objetos. Ruby fue diseado por
Yukihiro Matsumoto ('Matz') en 1993, con el Principio de la Menor Sorpresa: Matz dice "quera
minimizar mi frustracin mientras programo, y eso conllevaba minimizar mi esfuerzo. Este es el
principal objetivo de Ruby. Quiero divertirme mientras programo. Despus de lanzar Ruby y probarlo
mucha gente, ellos me dijeron que sentan lo mismo que yo. Ellos fueron los que acuaron el trmino
de "Principio de Menor Sorpresa".

En el ao 2004 hubo un boom en el inters por Ruby, debido a Ruby on Rails: el entorno para
desarrollo web de David Heinemeier Hansson.

El lenguaje de programacin Ruby permite la metaprogramacin, de la cual Rails hace uso, lo que
resulta en una sintaxis que muchos de sus usuarios encuentran muy legible.
Cdigo y Sintaxis

Codificacin de archivos

Todo archivo de que contenga codigo ruby debe ser guardado con codificacion UTF-8 y de preferencia
usar saltos de linea UNIX.

Argumentos

Evitar el uso de la coma despues del ltimo argumento de un mtodo o del ltimo elemento de un
array o Hash.

# bad
some_method(size, count, color, )
my_array = [1, 2, 3,]

# good
some_method(size, count, color)
my_array = [1, 2, 3]

Omitir parentesis a la hora de listar argumentos que son parte de una DSL interna (Rake, Rails,
RSpec) o de metodos con status "keyword", de lo contrario utilizar parentesis.

class Person
attr_reader :name, :age

# omitted
end

temperance = Person.new('Temperance', 30)


temperance.name

puts temperance.age

x = Math.sin(y)
array.delete(e)

bowling.score.should == 0

Evitemos el uso de argumentos con el mismo nombre de attibutos de la clase


class Foo
attr_accessor :options

# ok
def initialize(options)
self.options = options
# both options and self.options are equivalent here
end

# bad
def do_something(options = {})
unless options[:when] == :later
output(self.options[:message])
end
end

# good
def do_something(params = {})
unless params[:when] == :later
output(options[:message])
end
end
end

Redireccion de salidas

Utilizar $stdout / $stderr / $stdin en vez de STDOUT / STDERR / STDIN . ya que los valors presedidos
de $ son variables globales y no constantes

Saltos de Linea

Usar salto de linea para separar deficiones de metodos y clases, asi como tambien para separar la
logica en parrafos, ademas para separar los modificadores de acceso de una clase (public,
protected private) y para terminar un archivo con una nueva linea.
class MyAwesomeClass
def some_method
data = initialize(options)

data.manipulate!

data.result
end

def some_method
result
end

protected

def some_protected_method
end

private

def some_private_method
end

end

Indentacion

Todos los metodos, bloques, condiciones, etc deben de ir correctamente indentados y dicha tabulacion
debe de ser de 2 espacios en vez de tabs.

Los when dentro de un case no se indentan.

case
when song.name == 'Misty'
puts 'Not again!'
when song.duration > 120
puts 'Too long!'
when Time.now.hour > 21
puts "It's too late"
else
song.play
end

Cuando asignamos el resultado de una expresion condicional, indentarlo debajo de la variable.


kind =
case year
when 1850..1889 then 'Blues'
when 1890..1909 then 'Ragtime'
when 1910..1929 then 'New Orleans Jazz'
when 1930..1939 then 'Swing'
when 1940..1950 then 'Bebop'
else 'Jazz'
end

result =
if some_cond
calc_something
else
calc_something_else
end

Espacios en blanco
Cuando usar espacios en blanco como separador?

Usar espacios alrededor de: operadores, bloques

Despues de: la coma, y punto y coma

sum = 1 + 2
a, b = 1, 2
[1, 2, 3].each { |e| puts e }
class FooError < StandardError; end

Cuando evitar espacios en blanco como separador?

Alrededor de: Hashes, Arrays, Interpolaciones,un rango, parentesis y el operador exponente

Antes de: un salto de linea, al principio de una linea en blanco

Despues de: una negacion (!)

hash = {one: 1, two: 2}

array = [1, 2, 3]

interpolation = "esto es una cadena #{variable}"

if !something
(1..10).each { |i| puts i }
end
Nombramientos

Idenficadores

Usar idenficadores en ingles

# bad - identifier using non-ascii characters


= 1_000

# bad - identifier is a Bulgarian word, written with Latin letters (instead of Cyrillic)
zaplata = 1_000

# good
salary = 1_000

CamelCase

Deben de empezar un una letra Mayuscula y la separacin de mltiples palabras debe de ser
concatenadas pero con la primera letra de la siguiente palabra en Mayscula.

Uso: Se debe usar en la declaracion de nombres de clases y modulos.

SCREAMING_SNAKE_CASE

El nombre se escribe todo en Mayusculas y la separacion de mltiples palabras debe de ser


concatenadas con un guin bajo _

Uso: se debe usar a la hora de declarar constantes

snake_case

El nombre se escribe todo en minusculas y la separacion de mltiples palabras debe de ser


concatenadas con un guin bajo _

Uso: Se debe usar en la declaracion de nombres de metodos, variables, archivos y directorios.


Colecciones

Hashes

Es preferible usar la sintanxis de ruby 1.9 para la declaracion de hashes { a: :b } en vez de { :a => :b
}.

Tratar de no mezclar la syntaxis de ruby 1.9 con la anterior.

# bad
{ a: 1, 'b' => 2 }

# good
{ :a => 1, 'b' => 2 }

Usar Hash#key? en vez de Hash#has_key? y Hash#value? en vez de Hash#has_value? . Los metodos


largos se consideran deprecados.

# bad
hash.has_key?(:test)
hash.has_value?(value)

# good
hash.key?(:test)
hash.value?(value)

Puedes usar Hash#fetch cuando necesites que una llave este presene o asignarle un valor por
defecto cuando no este.

heroes = { batman: 'Bruce Wayne', superman: 'Clark Kent' }


# bad - if we make a mistake we might not spot it right away
heroes[:batman] # => "Bruce Wayne"
heroes[:supermann] # => nil

# good - fetch raises a KeyError making the problem obvious


heroes.fetch(:supermann)

# good - fetch return a values when the hash doesnt have the key
heroes.fetch(:supermann, true)

# very good - fetch return a values when the hash doesnt have the key, blocks are lazy evaluated, so only triggered in c
heroes.fetch(:supermann) { true }

Usar Hash#values_at para retornar varios valores a la vez


# bad
email = data['email']
nickname = data['nickname']

# good
email, username = data.values_at('email', 'nickname')

Arrays

Utilizar Array#join en vez de Array#* con una cadena de texto como argumento.

# bad
%w(one two three) * ', '
# => 'one, two, three'

# good
%w(one two three).join(', ')
# => 'one, two, three'

Usar [*var] or Array() en vez de una comparacion explicitar con la clase Array cuando queremos
tratar una variable como si fuera un array.

# bad
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }

# good
[*paths].each { |path| do_something(path) }

# good (and a bit more readable)


Array(paths).each { |path| do_something(path) }
Operadores logicos
Es preferible utlizar && y || en vez de or y and . Hay que recordar que hay diferencia entre && ||
y and or .

foo = :foo
bar = nil

a = foo and bar


# => nil
a
# => :foo

a = foo && bar


# => nil
a
# => nil

Nota: Como regla puedes usar && y || para expresiones booleanas y and y or para control de
flujo:

# Expresion booleana
if some_condition && some_other_condition
do_something
end

# Control de flujo
document.saved? or document.save!

Tratemos de evitar la igualacion explicita de tipo y mejor utilizemos uno de los varios metodos que
ruby ya nos ofrece.

# bad
Array === something
(1..100) === 7
/something/ === some_string

# good
something.is_a?(Array)
(1..100).include?(7)
some_string =~ /something/

Nunca utilizar una asigncion como valor de retorno o como condicion


#bad
if v = array.grep(/foo/)
do_something(v)
...
end

# good
v = array.grep(/foo/)
if v
do_something(v)
...
end

Condiciones de una sola linea.

# bad
while some_condition
do_something
end

if some_condition
do_something
end

# good
do_something while some_condition
do_something if some_condition

Evitar el uso del then en condiciones multilinea

# bad
if some_condition then
# body omitted
end

# good
if some_condition
# body omitted
end

Utilizar el operador ternario en condiciones de una sola linea.

# bad
result = if some_condition then something else something_else end

# good
result = some_condition ? something : something_else

Evitar el uso de operadores terniarios anidados, usar el if en estos casos.


# bad
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else

# good
if some_condition
nested_condition ? nested_something : nested_something_else
else
something_else
end

Evitar el uso de de if / else al final de bloques

# bad
10.times do
# multi-line body omitted
end if some_condition

# good
if some_condition
10.times do
# multi-line body omitted
end
end

No ocupar un unless con un else , es mejor cambiar la expresion a su forma positiva.

# bad
unless success?
puts 'failure'
else
puts 'success'
end

# good
if success?
puts 'success'
else
puts 'failure'
end

No usar el do en en condiciones while / until que son multilinea


# bad
while x > 5 do
# body omitted
end

until x > 5 do
# body omitted
end

# good
while x > 5
# body omitted
end

until x > 5
# body omitted
end

Ocupar until en vez de while para condiciones negativas

# bad
do_something while !some_condition

# good
do_something until some_condition

Utilizar Kernel#loop para loops infinitos

# bad
while true
do_something
end

until false
do_something
end

# good
loop do
do_something
end

Utilizar break en lugar de begin / end / while o begin / end / until


# bad
begin
puts val
val += 1
end while val < 0

# good
loop do
puts val
val += 1
break unless val < 0
end

Utilizar rangos o Comparable#between? en vez de comparaciones logicas complejas

# bad
do_something if x >= 1000 && x <= 2000

# good
do_something if (1000..2000).include?(x)

# good
do_something if x.between?(1000, 2000)

Se recomienda el uso de metodos de predicado en vez de == (las comparaciones numericas se


puede usar el == )

# bad
if x % 2 == 0
end

if x % 2 == 1
end

if x == nil
end

# good
if x.even?
end

if x.odd?
end

if x.nil?
end

if x.zero?
end

if x == 0
end

Utilizar next en vez de una condicion dentro de un loop .


# bad
[0, 1, 2, 3].each do |item|
if item > 1
puts item
end
end

# good
[0, 1, 2, 3].each do |item|
next unless item > 1
puts item
end
Literales
Preferir el parentesis como delimitador de un literal con excepcion de %r ya que hay expresiones
regulares que hace uso de parentesis.

#bad
%Q[Joe said: "Frank said: "#{what_frank_said}""]
%Q+Joe said: "Frank said: "#{what_frank_said}""+

#good
%Q(Joe said: "Frank said: "#{what_frank_said}"")

Se recomienda el uso de literal en numeros largos, esto mejora mucho su lectura

# bad - how many 0s are there?


num = 1000000

# good - much easier to parse for the human brain


num = 1_000_000

Utilizar %w para crear un Array de palabras.

# bad
STATES = ['draft', 'open', 'closed']

# good
STATES = %w(draft open closed)

Nota: la diferencia entre %w y %W es que el que esta en mayuscula crea un Array de string con
comillas doble (el cual permite intepolacion) mientras que el otro no.

Utilizar %i para crear un Array de simbolos.

# bad
STATES = [:draft, :open, :closed]

# good
STATES = %i(draft open closed)

Utilizar %Q para cadenas de texto de una sola linea o aun mejor utilizar su alias %()
# bad (no interpolation needed)
%(<div class="text">Some text</div>)
# should be '<div class="text">Some text</div>'

# bad (no double-quotes)


%(This is #{quality} style)
# should be "This is #{quality} style"

# bad (multiple lines)


%(<div>\n<span class="big">#{exclamation}</span>\n</div>)
# should be a heredoc.

# good (requires interpolation, has quotes, single line)


%(<tr><td class="name">#{name}</td>)

Nota: la diferencia entre %q y %Q es que el que esta en mayuscula crea un String con comillas
doble (el cual permite intepolacion) mientras que el otro no.

Evitar el uso de %x al menos que deseas escapar comando con ``

# bad
date = %x(date)

# good
date = `date`
echo = %x(echo `date`)

Utilizar %r solo para expresiones regular con mas de una /

# bad
%r(\s+)

# still bad
%r(^/(.*)$)
# should be /^\/(.*)$/

# good
%r(^/blog/2011/(.*)$)

Evitar el %s es mas legible utilizar :"some string" y ademas permite interpolacion


Idiomas
Existen algunos idiomas en ruby que son bastantes utilizados por la comunidad en vez de expresin
mas verbosas.

Entre las cuales estn:

El ||= para asignaciones cortas evaluando si existe o no, asignandole el valor solo si no existe.

@user ||= User.find(params[:id])

El &&= para asignaciones cortas evaluando si existe y asignndole el nuevo valor.

@user.name &&= @user.name.downcase

Smbolo a proc :

array.map(&:upcase)

Bloques

La convencion para bloques de una sola linea es usando las llaves {} y para los de multiples lineas es
usando el do / end .

Cadenas

A la hora de concatenar cadenas es recomendable usar interpolacion en vez de suma de cadenas


osea "mi nombre es: #{name}" en vez de "mi nombre es:" + name.to_s .
Multilinea
Si los argumentos de un metodo necesitan ser declarados en varias lineas, colocarlos uno debajo de
otro con la misma indentacion.

# starting point (line is too long)


def send_mail(source)
Mailer.deliver(to: 'bob@example.com', from: 'us@example.com', subject: 'Important message', body: source.text)
end

# bad (double indent)


def send_mail(source)
Mailer.deliver(
to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end

# good
def send_mail(source)
Mailer.deliver(to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end

# good (normal indent)


def send_mail(source)
Mailer.deliver(
to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text
)
end

Evitar el uso de \ para indicar el salto de linea en expresiones que no sean concatenacion de cadenas

# bad
result = 1 - \
2

# good (but still ugly as hell)


result = 1 \
-2

long_string = 'First part of the long string' \


' and second part of the long string'

Declaracion de arrays en multiples lineas


# bad - single indent
menu_item = ['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam']

# good
menu_item = [
'Spam',
'Spam',
'Spam'
]
Comentarios y anotaciones
Evitar los comentarios de bloque

# bad
=begin
comment line
another comment line
=end

# good
# comment line
# another comment line

Utilizar un espacio despues de #

Los comentarios de mas de una palabra son Capitalizados

# counter
counter += 1 # Increments counter by one.
Anotaciones
Las anotaciones deben de ser escritas una linea por encima del codigo relevante y despues de la
palabra clave debe utilizarse el : seguido de un espacio de separacion. Si la anotacion abarca
multiple lineas, las lineas subsiguientes deben de ir corectamente indentadas.

# FIXME: This has crashed occasionally since v3.2.1. It may


# be related to the BarBazUtil upgrade.
def bar
baz(:quux)
end

Existen varias palabras clave que podemos utilizar en las anotaciones.

TODO: se utiliza para explicar que hace falta o se agregara mas adelante
FIXME: Indica codigo que necesita ser reparado
OPTIMIZE: Indica codigo lento o ineficiente que puede causar problemas de rendimiento
HACK: Se utiliza para indicar codigo con practicas "questionables" y que deberia de ser
refactorizado
REVIEW: Se utiliza para nota que deberia de confirmarse si el codigo funciona como deberia

Se pueden usar mas palabras claves pero estas deberian estar documentada en el archivo README
Modulos clases y variables

Modulos

A la hora de definir modulos, se recomienda el uso de la palabra clave module_function y debajo de


esta declara todos los metodos publicos de clase

module MyModule
module_function

def do_something
end
end

MyModule.do_something

Clases

Estructura de clases.
class Person
# extend and include go first
extend SomeModule
include AnotherModule

# inner classes
CustomErrorKlass = Class.new(StandardError)

# constants are next


SOME_CONSTANT = 20

# afterwards we have attribute macros


attr_reader :name

# followed by other macros (if any)


validates :name

# public class methods are next in line


class << self
def some_method
end
end

# followed by public instance methods


def some_method
end

# protected and private methods are grouped near the end


protected

def some_protected_method(arg1, agr2)


end

private

def some_private_method
end
end

Utilizar :: solamente para llamar constantes (esto incluye classes y modulos) o para llamar
contructores, ejemplo.

# bad
SomeClass::some_method
some_object::some_method

# good
SomeClass.some_method
some_object.some_method
SomeModule::SomeClass::SOME_CONST
SomeModule::SomeClass()

Mtodos

Los metodos deben definirse en minsculas , separadas por guiones bajos (snakecase) y con un
nombre claro que indica su funcin, preferiblemente incluir algn verbo.
Asi mismo utilizar parentesis en la definicion de metodo solo cuando hay argumentos de lo
contrario no utilizar parentesis

En ruby todos lo mtodos son publicos por defecto, para declarar mtodos protected o private,
estos deben de ser declarados debajo de las palabras clave protected y private ademas deben ir
correctamente identados, ejemplo:

def some_public_method
end

protected

def some_procted_method(arg1, arg2)


end

private

def some_private_method
end

A la hora de crear metodos sin cuerpo, declararlos en una sola linea, ejemplo.

# Classes
# bad
class FooError < StandardError
end

# okish
class FooError < StandardError; end

# good
FooError = Class.new(StandardError)

# methods

# good
def no_op; end

Deprecar metodos si estos ban ya no van a ser utilizado en proximas version, ejemplo

def old_method
warn "DEPRECATED METHOD: 'old_method', please use 'new_method' instead"
end

Los nombres de los metodos que retornan un booleano deben de terminar con un signo de
interrogacion

def active?
active == 1
end

Los metodos potencialmente peligros que modifcan la instancia de la clase o que se deben utilizar
con cuidado deben de llevar el signo de admiracion cuando haya una version segura de este metodo.

# bad - there is no matching 'safe' method


class Person
def update!
end
end

# good
class Person
def update
end
end

# good
class Person
def update!
end

def update
end
end

Metodos de clase: Es preferible utilizar el bloque class << self que self.method_name para mtodos
de clase.

def self.metodo_estatico
end

class << self


def metodo_estatico
end
end

Evitar el uso de return , utilizarlo solo cuando es requerido explicitamente.

# bad
def some_method(some_arr)
return some_arr.size
end

# good
def some_method(some_arr)
some_arr.size
end

Variables.

Al igual que los metodos las variables deben de ser utlizar snakecase, ademas de eso no deben ser
palabras demasiadas largas, las variables demasiada cortas o de una sola letra solo deben de ser
usadas para indicar iteradores, como por ejemplo las variable de un loop , each .

Asi mismo todas las variables internas propias de la clase deben de ser precedidas de una @ al igual
que las y las variables internas estticas (no utilizar @@ para las variables estaticas).
Ejemplo de variables de clase ( @@ ) y del por que no usarlas ya que producen efectos no deseados.

class Shared
@@name = "Shared"

def self.name= name


@@name = name
end
def self.name
@@name
end
end

class Brother < Shared

end

class Sister < Shared

end

Brother.name
=> "Shared"

Sister.name = "Sister"
=> "Sister"

Brother.name
=> "Sister"

Ejemplo de los diferentes tipos de variables


# variable global
$foo = 5

class MyAwesomeClass
# variable de clase
@@shared = ""

# variable de instancia de clase


@family_name = ""

def initialize
# variable de instancia
@name = ""
end

def self.foo
$foo
end

def config
# variable local
cfg = YAML::load(File.open("#{Rails.root.to_s}/config/application.yml"))
if cfg
do_something_with_config(cfg)
end
end
end

Evitemos el uso de self cuando no es requerido

# bad
def ready?
if self.last_reviewed_at > self.last_updated_at
self.worker.update(self.content, self.options)
self.status = :in_progress
end
self.status == :verified
end

# good
def ready?
if last_reviewed_at > last_updated_at
worker.update(content, options)
self.status = :in_progress
end
status == :verified
end

No usar punto y coma para separar definicion de multiples variables o para imprimirlas.
# bad
puts 'foobar';

puts 'foo'; puts 'bar'

# good

puts 'foobar'

puts 'foo'
puts 'bar'
Excepciones
No utilizar el rescue con la clase Exception, ya que esto podria rescatar errores que no son
recuperables como: SyntaxError, LoadError, Interrupt, etc.

#bad
begin
foo
rescue Exception => e
logger.warn "Unable to foo, will ignore: #{e}"
end

#good

begin
foo
rescue => e
logger.warn "Unable to foo, will ignore: #{e}"
end

# also good
begin
# an exception occurs here

rescue StandardError => e


logger.warn "Unable to foo, will ignore: #{e}"
end

No hacer un retorno dentro de un ensure

def foo
begin
fail
ensure
return 'very bad idea'
end
end

Usar el begin explicito cuando sea posible

# bad
def foo
begin
# main logic goes here
rescue
# failure handling goes here
end
end

# good
def foo
# main logic goes here
rescue
# failure handling goes here
end
Evitar la proliferacion de declaracione begin , usando metodos de contingencia.

# bad
begin
something_that_might_fail
rescue IOError
# handle IOError
end

begin
something_else_that_might_fail
rescue IOError
# handle IOError
end

# good
def with_io_error_handling
yield
rescue IOError
# handle IOError
end

with_io_error_handling { something_that_might_fail }

with_io_error_handling { something_else_that_might_fail }

Liberar recursos siempre dentro de un bloque ensure

f = File.open('testfile')
begin
# .. process
rescue
# .. handle error
ensure
f.close if f
end
Cadenas de caracteres

Formato

Utilizar sprintf y su alias format en vez String#% para darle formato a una cadena

# bad
'%d %d' % [20, 10]
# => '20 10'

# good
sprintf('%d %d', 20, 10)
# => '20 10'

# good
sprintf('%{first} %{second}', first: 20, second: 10)
# => '20 10'

format('%d %d', 20, 10)


# => '20 10'

# good
format('%{first} %{second}', first: 20, second: 10)
# => '20 10'

Nunca dejar los brackets {} a la hora de interpolar variable globales o de instancia

class Person
attr_reader :first_name, :last_name

def initialize(first_name, last_name)


@first_name = first_name
@last_name = last_name
end

# bad - valid, but awkward


def to_s
"#@first_name #@last_name"
end

# good
def to_s
"#{@first_name} #{@last_name}"
end
end

$global = 0
# bad
puts "$global = #$global"

# good
puts "$global = #{$global}"

A la hora de interpolar grandes cantidades de datos hay que utilizar String#<< en vez de String#+
la cual crea muchas instancias de la clase string haciendo la asignacion mas lenta, mientras que
String#<< muta la instancia de clase string que toma lugar haciendo la asignacion mas rapida

# good and also fast


html = ''
html << '<h1>Page title</h1>'

paragraphs.each do |paragraph|
html << "<p>#{paragraph}</p>"
end

Utilizar Here Docs para texto multilinea

first_quatrain = <<-EOT
My mistress' eyes are nothing like the sun;
Coral is far more red than her lips' red;
If snow be white, why then her breasts are dun;
If hairs be wires, black wires grow on her head.
EOT

def second_quatrain
x = <<-HTML
<blockquote>
I have seen roses damask'd, red and white,
But no such roses see I in her cheeks;
And in some perfumes is there more delight
Than in the breath that from my mistress reeks.
</blockquote>
HTML
x
end
Ruby on Rails
Ruby on Rails, tambin conocido como RoR o Rails, es un framework de aplicaciones web de cdigo
abierto escrito en el lenguaje de programacin Ruby, siguiendo el paradigma de la arquitectura
Modelo Vista Controlador (MVC).

Trata de combinar la simplicidad con la posibilidad de desarrollar aplicaciones del mundo real
escribiendo menos cdigo que con otros frameworks y con un mnimo de configuracin.

Rails se distribuye a travs de RubyGems, que es el formato oficial de paquete y canal de distribucin
de bibliotecas y aplicaciones Ruby.
Balloom

Sobreescribir modelos, controldores, decorators etc.

Para sobreescribir correctamente un modelo del balloom se debe de crear dicho modelo en la misma
ruta que posee el engine y agregarle _decorator al nombre del archivo. Ejemplo.

En app/models/balloom/order_decorator.rb

Balloom::Order.class_eval do
def my_awesome_method
puts "Gotcha!"
end
end

En caso de que necesitemos sobreescribir un modelo de un determinado engine podemos agregar al


inicio del archivo _decorator.rb un require_dependency indicando la ruta del archivo que se
encuentra en el Engine

require_dependency File.join(BalloomWishlist::Engine.root.to_s + "/app/models", "balloom/order_decorator")

Quedando asi:

require_dependency File.join(BalloomWishlist::Engine.root.to_s + "/app/models", "balloom/order_decorator")


Balloom::Order.class_eval do
def my_awesome_method
puts "Gotcha!"
end
end
Assets

Javascripts

Utilizar solo archivos coffeescript para escribir javascript y nombrarlo con extension .coffee.js
Si se necesita interactuar bastante con elementos HTML, crear clase en coffescript o crear plugins
de jquery utilizando el Widget Factory

Stylesheets

Utilizar solo archivos sass para escribir css y nombrarlo con extension .sass.css
Hacer uso de la gema de compass-rails y de los mixings que nos proporciona compass sass
Modelos
Nunca ocupar default scopes
No dejar consultas en ninguna parte que no sea un modelo, en vez de esto utilizar scopes
declarados en el modelo y anidar estos,

class HomeController < ApplicationController


def index
# bad
@recent_books = Book.where("books.published_at > ?", 1.week.ago).order("books.published_at DESC")

# good
@recent_books = Book.recent.published_desc # 'recent' and 'published_desc' are scopes defined in Book model
end
end
Controladores
No modificar el objeto params

#bad
def search
params.except!(:action, :controller)
@search = User.search(params)
render "search"
end

# good
def search
filter = params.except(:action, :controller)
@search = User.search(filter)
render "search"
end

# better
def search
@search = User.search(search_params)
render "search"
end

private

def search_params
# params.except(:action, :controller)
params.permit(:user_id, :name)
end

Utilizar helper_methods en vez de variables de instancia


# bad

def create
@user = User.new(params[:user])
@user.save
end

def edit
@user = User.find(params[:id]) rescue nil
end

def update
@user = User.find(params[:id]) rescue nil
@user.update_attributes(params[:user])
end

# good

helper_method :user

def create
user.save
end

def update
user.update_attributes(params[:user])
end

def user
@user ||=
case action_name
when "new", "create"
User.new(params[:user])
else
User.find(params[:id]) rescue nil
end
end
Vistas
TODO
Seguridad

Evitar el Cross Frame Scripting o Clickjacking

El Cross Frame Scripting o Clickjacking es una vulnerabilidad la cual permite el atacante capturar los
clicks y otros eventos mediante javascript a traves de un iframe

Colocar el siguiente meta tag dentro de la etiqueta head en tu pagina.

<meta content="deny" http-equiv="X-Frame-Options">


Helpers
NUNCA usar cadenas concatenadas para imprimir html o javascript

def draw_members users, filter


rsl = ""
rsl << %(<div class="clearfix">)
rsl << link_to(balloom.new_member_url, class: "pull-right", title: t("admin.labels.add_user")) do
raw("<i class='icon-plus-sign'></i>") + t("admin.labels.add")
end
rsl << %(</div>)
if users.size > 0
rsl << %(<table class="table table-striped table-condensed" style="margin-top: 3px;">)
rsl << %(<thead>)
rsl << %(<tr>)
rsl << %(<th>#{sort_link(filter, :email, t("admin.labels.email"), { controller: 'balloom/members', action: 'index
rsl << %(<th>#{sort_link(filter, :name, t("admin.labels.name"), { controller: 'balloom/members', action: 'index
rsl << %(<th>#{t("admin.labels.role")}</th>)
rsl << %(<th width="1%">&nbsp;</th>)
rsl << %(</tr>)
rsl << %(</thead>)
rsl << %(<tbody>)
rsl << users.map{|user| draw_member(user)}.join
rsl << %(</tbody>)
rsl << %(</table>)
else
rsl << %(<div class='well'>#{t("admin.labels.users_empty")}</div>)
end
raw(rsl)
end

Si se va imprimir html simple hacer uso de los helpers que nos otroga rails para tratar con html:
concat , raw , capture , content_tag , sanitize , etc.

def section_summary_for section


return "" if section.title.blank? && section.description.blank?
content_tag :section, class: 'ba-section-summary' do
unless section.title.blank?
concat content_tag :h4, sanitize(section.title), class: 'strong'
end
unless section.description.blank?
concat content_tag :article, nl2br(sanitize(section.description)), class: ''
end
end
end

Si vamos imprimir html complejo UTILIZAR PARTIALS en vez de helpers

render partial: "sections/summary", locals: {section: section}


Navegadores

Compatibiladad

Browser update
https://browser-update.org/

<script type="text/javascript">
var $buoop = {vs:{i:9,f:10,o:15,s:4.1}};
$buoop.ol = window.onload;
window.onload=function(){
try {if ($buoop.ol) $buoop.ol();}catch (e) {}
var e = document.createElement("script");
e.setAttribute("type", "text/javascript");
e.setAttribute("src", "//browser-update.org/update.js");
document.body.appendChild(e);
}
</script>

Script para evitar errores en navegadores que no tienen consola (IE)

// Avoid `console` errors in browsers that lack a console.


(function() {
var method;
var noop = function () {};
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});

while (length--) {
method = methods[length];

// Only stub undefined methods.


if (!console[method]) {
console[method] = noop;
}
}
}());

// Place any jQuery/helper plugins in here.


SEO

humans.txt

Un archivo TXT que contiene la informacin sobre las personas que han intervenido en la web.

Dnde se pone?

En la raz del site. Al lado de robots.txt. Y (siempre que sea posible) en el aade en el Tag author

<link type="text/plain" rel="author" href="http://domain/humans.txt" />

Ejemplo de humans.txt.
# humanstxt.org/
# The humans responsible & technology colophon

/* TEAM */
Chef:Juanjo Bernabeu
Contact: hello [at] humanstxt.org
Twitter: @juanjobernabeu
From:Barcelona, Catalonia, Spain

UI developer: Maria Macias


Twitter: @maria_ux
From:Barcelona, Catalonia, Spain

One eyed illustrator: Carlos Maas


Twitter: @oneeyedman
From:Madrid, Spain

Standard Man: Abel Cabans


Twitter: @abelcabans
From:Barcelona, Catalonia, Spain

Web designer: Abel Sutilo


Twitter: @abelsutilo
From:Sevilla, Andalucia, Spain

/* THANKS */

(First) EN Translator: Jos Flores


Twitter: @prosciuttos
From: Barcelona, Catalonia, Spain

CA Translator: Eva AC
Twitter: @evaac
From:Barcelona, Catalonia, Spain

EN Translator: Marta Armada


Twitter: @martuishere
From: Barcelona, Catalonia, Spain

Media Queries by: Marta Armada (@martuishere) and Javier Usobiaga (@htmlboy)

/* SITE */
Last update:2012/02/04
Language: Catal / Czech / Deutsch / English / Castellano / Japanese / Dutch / Russian / Chinese
Doctype:HTML5
IDE: Sublime Text, Notepad++, FileZilla, Photoshop

/* TECHNOLOGY COLOPHON */

HTML5, CSS3
jQuery, Modernizr
Bibliografia
https://github.com/bbatsov/ruby-style-guide
https://github.com/bbatsov/rails-style-guide
http://www.elabs.se/blog/36-working-with-time-zones-in-ruby-on-rails
http://javascript.info/tutorial/clickjacking
https://browser-update.org/
http://simpleror.wordpress.com/2009/03/15/q-q-w-w-x-r-s/
http://ruby-doc.org/core-2.0/doc/syntax/literals_rdoc.html
http://rubytutorial.wikidot.com/introduccion
http://phrogz.net/programmingruby/language.html#table_18.4
http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html

Вам также может понравиться