Llaves foraneas en Rails

Si se puede, estoy trabajando en ello.

Posted in Codigo | Tagged , | Leave a comment

Usa el metodo ‘h’ para tus vistas. Es seguro y sencillo.

html_escape

Cuando progamamos nuestras vistas hay veces que vamos muy rapido  y olvidamos un pequenio detalle. Usar el metodo ‘h’ o ‘html_escape’.

Esto regularmente se realiza en vistas como el show de un controller, o bien, cuando llamamos informacion de la base de datos.

Este metodo nos puede ayudar a librar problemas de seguridad muy facilmente. Pero que hace?

Lo que hace el metodo ‘h’ es tomar el string o informacion que va a desplegar y cualquier caracter que tenga que ver con HTML lo ‘comenta’  para que en la vista no salga como codigo, sino como texto. Mejor ponemos un ejemplo:

1
2
3
4
5
6
7
8
   # app/views/example/show.html.erb

  # Suponemos que @string es un atributo de cualquier objeto que queremos desplegar.
  @string = "<script type=\"text/javascript\">alert();</script>"

  <%= @string %>  # ERROR! Cuando se carga la pagina, aparece un popup con la leyenda 'te hackee'!

  <%=h @string %> # HACK FRUSTRADO. En este caso, se despliega el script, no se ejecuta.

Tomemos en cuenta que se hacemos el deploy de nuestra aplicacion en un servidor apache. El lenguaje PHP es soportado por default por estos webservers. Esto quiere decir que no solo un atacante puede usar javascript, si no tambien, PHP.

Esto es una metodo facil de usar, y que nos puede ayudar mucho a que nuestra aplicacion sea segura.

Posted in Codigo, Rails | Tagged , | Leave a comment

ActiveRecord y el uso de :include

Cuando se tienen modelos que estan relacionados, es facil cometer el error de solo pedir a ActiveRecord por un objeto, y en la vista, llamar a los otros objetos relacionados. Para ilustrar la situacion, se presenta el siguiente codigo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#Modelos relacionados
class Post < ActiveRecord
  hay_many :comments
end

class Comment < ActiveRecord
   belongs_to :post
   belongs_to :user
end

class PostsController < ApplicationController
   def show
       @post = Post.first # Con fines de explicacion, seleccionamos el primer post.
   end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#  /app/views/posts/show.html.erb

<h1><%= @post.title %></h1>


<%= post.body %>
<hr />

<h2>Comments</h2>


<% for comment in @post.comments %>
   <%= comment.user.name %>

   <%= comment.body %>
<% end %>

Como dije anteriormente, este es un error ya que segun la filosofia de Rails, todo codigo debe estar en su lugar. Y en este ejemplo, podemos ver que en la vista, se llaman a los comentarios de la publicacion, asi como el usuario que subio el comentario.

Si se tuviera el log de esto, se podria observar que una ves que esta haciendo el render de la vista, sigue haciendo peticiones a la base de datos, y eso es un NO NO!

Aqui es en donde entra nuestro parametro de ActiveRecord :include.

Include

El parametro :include sirve para que desde el controlador se puedan llamar a todos los objetos que seran desplegados en la vista. Nuestro codigo queria asi.

1
2
3
4
5
class PostsController
   def show
       @post = Post.find(:first, :include=>[:comments=>[:user]])
   end
end

De esta manera, cuando la vista sea ‘rendereada’, Rails ya habra guardado en memoria los resultados de todos los queries a la base de datos.

El parametro Include recibe un arreglo de las asociaciones que se quieren llamar. A continuacion ejemplos de posibles peticiones a ActiveRecord con :inlude.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Modelo de Publicacion o Post
class Post < ActiveRecord
   has_many :comments, :images, :urls
end

# Modelo de Comentario
class Comment < ActiveRecord
    belongs_to :post
    belongs_to :user
end

#modelo de Imagenes o Images
class Image < ActiveRecord
    belongs_to :post
end


## Dada esta situacion, el query queda asi.
# Controlador
   def show
       @post = Post.find(:first, :include => [:comments => [:user], :images, :urls]
   end

Bueno, ahora que ya lo saben, no cometan este error.

En posts futuros veremos como podemos poner nuestro codigo mas bonito poniendo la opcion :include en los modelos, no el controlador.

Posted in Codigo, Rails | Tagged | Leave a comment

Atributos de asociaciones que debes proteger

Asociaciones

Una asociacion se hace cuando un modelo esta relacionado con otro. Por ejemplo: Marca tiene varios Productos. Y un Producto tiene 1 marca.  Esta es una de las asociaciones mas sencillas. Veamos en codigo.

1
2
3
4
5
6
7
8
9
class Brand &lt; ActiveRecord
   has_many :products
end

##

class Product &lt; ActiveRecord
    belongs_to :brand
end

De acuerdo a la naturaleza de esta asociacion. Nuestro modelo Product debe tener la llave foranea brand_id. (Puede ser otra, pero Rails propone esta tecnica.)

El problema viene al momento de asginar una marca a un producto.

Cuando se asigna informacion por medio de una forma, se le conoce como mass assignment. Y hay maneras de ‘hackear’ el mass assignment. Usando la herramienta CURL, algun usuario malicioso podria asignar una marca a un producto que no deberia.

Por eso debemos proteger atributos de modelos que pueden llegar a ser delicados. Para realizar esta tarea se usa el metodo ‘attr_protected’

1
2
3
4
5
class Product
   belongs_to :brand

   attr_protected :brand_id # =D Con esta linea quedamos protegidos de formas truqueadas intencionalmente.
end

Lo que hace este metodo es ignorar lo que venga desde una forma, o bien, el ‘Mass Assignment’. De esta manera podemos tapar una brecha de seguridad que podria llegar a ser peligrosa. Bien se sabe que en cuestiones de seguridad mas vale exagerar que sufrir las consecuencias.

Posted in Codigo, Rails | Tagged , | Leave a comment

Que es RJS ?

Si si, sabemos rails y todo, pero cuando viene la hora de contestar que es RJS nos quedamos…. mmmmmmmm…..

RJS es una herramienta, un traductor que nos da Rails para poder escribir javascript con la hermosa sintaxis de  RUBY. Es como usar JRUBY pero para javascript.

Este post se puede extender por mucho pero solo dejo la idea principal, asi que un ejemplito de RJs va asi.

1
2
3
4
5
6
7
8
9
10
11
12
13
# lo mismo que hacer $('div')
page['div']

# para hacer un $('div').show();
page['div'].show

# para agregar javascript puro.
page << "if (true){alert('yes! is true!')};"

# Para hacer un Timeout o Tiempo de espera antes de ejecutar algo.
page.delay(10) do
  page['div'].hide
end

Muy bien, pero ahora como lo agregamos a nuestras vistas y acciones, para que nos ayude a no pelear con casos simples de javascript ?

update_page y update_page_tag son los metodos que nos ayudaran a hace el trabajo. Vamos a ver.

1
2
3
4
5
# Cualquier vista .html.erb
<%= update_page_tag do |page|
                page['div'].show
           end
%>

En este caso no nos ayuda mucho lo que acabamos de escribir ya que solo hara aparecer el div con id=’div’.
Ademas, tomar en cuenta que para que el script funcione debemos usar update_page_tag. Lo que hace a diferencia de update_page, es que el codigo producido se encierra en script tags. Es decir <script></script>

Veamos otro ejemplo donde RJS juega un papel mas interesante.

1
2
3
4
5
6
<%=
 link_to_remote "test", :url=>{:action=>:test, :id=>@test.id},
     :success => update_page do |page|
                            page[@test].highlight
                        end
%>

En este caso, cuando nuestra llamada se completa exitosamente, RJS genero codigo para que el div con id del objeto @test (normalmente seria algo asi: test_id)

Esto ya es un poco mas util.

RJS tambien se puede usar en los controladores de la siguiente manera.

1
2
3
4
5
6
7
##Cualquier controlador.
def giveme_rjs
  ## Realiza una accion si quieres, si no puedes dejarlo como quieras. En la siguente linea esta el chiste.
  render :update do |page|
     page.replace_html 'mydivid', :partial => @myexample
  end
end

Con este codigo podemos hacer que la accion ‘giveme_rjs’ reemplace el contenido de un DIV por lo que genere un ‘partial’.

Posted in Codigo, Rails | Tagged , , , | Leave a comment

Link to remote, sus callbacks y donde escribir el codigo ligado a Ajax

link_to_remote es un metodo que no da ActionView para poder hacer una llamada asincrona o bien, AJAX.

Si bien esta funcion es muy util, hay veces que nos podemos confundir en donde escribir el codigo que activa las animaciones segun el estado de la peticion que realizamos.

Podemos tomar tres caminos posibles:

  1. Escribirlo en el la accion de controlador.
  2. Escribirlo en una vista (accion.js.rjs)
  3. Usar los CallBacks de link_to_remote.

Como en la mayoria de las situaciones en rails, TODO DEPENDE. Pero si es importante el DE QUE Depende.

Supongamos que tenemos la siguiente vista.

1
2
3
4
<% div_for @example do %>
<%= @example.title %>
<%= link_to_remote "Remove", :url=>{:action=>:destroy, :id=>@example.id} %>
<% end %>

Escribir codigo en la accion del controlador.

Cuando uses esta tecnica, es solo porque necesitas referenciar el objeto que se esta manipulando. Ejemplo: Borras un objeto y quieres que use un efecto de SlideUp. El codigo quedaria asi.

1
2
3
4
5
6
7
8
def destroy
   @example = Example.find(params[:id])
   if @example.destroy
      render :update do |page|
         page[@example].visual_effect 'SlideUp'
      end
   end
end

Hay que tomar en cuenta, que para poder hacer esto, se necesita que en la vista, se haga uso del metodo “div_for” para que RJS pueda identificar el DIV.

Escribirlo en una vista

Esto viene siendo exactamente lo mismo que lo anterior, solo que se tiene mas orden.

En el directorio /app/views/controller_name/accion.js.rjs

Rails es inteligente y puede detectar que el request es de tipo XMLHttpRequest y usar la vista .js.rjs, pero seria una muy buena practica definir las acciones dependiendo del tipo de request.

Esto queda de la siguiente manera.

1
2
3
4
5
6
7
8
9
10
11
## Controlador

def accion
   @example = Example.find(params[:id])
      if @example.destroy
         respond_to do |format|
            format.js ## Con esto especificamos que cuando el request sea XMLHttpReq. Use la vista .js.rjs
            format.html{redirect_to home_path }
         end
       end #if
end
1
2
3
4
5
6
7
## Vista accion.js.rjs
 page[@example].visual_effect 'SlideUp'

## Una ventaja de usar una vista, es cuando necesitamos hacer muchas lineas que se verian mal en el  controlador. Por ejemplo:
 page << "alert('Remooved succesfully');"
 page['notice-div'].inner_html "Borrado exitosamente!"
 page['notice-div'].show

Usar los Callbacks del metodo link_to_remote

Cuando se inicia en rails y se usa link_to_remote, a veces no se sabe las opciones que te da el metodo.

Cuando se realiza un XMLHttpRequest, Ajax puede saber el estado de la transaccion. Ver el libro “Ajax on Rails” de Scott Raymond para MUCHO mas informacion.

Es de intuicion adivinar los estados que un XMLHttpReq. puede tener. A continuacion se da un boceto con el codigo que se podria usar en el metodo link_to_remote.

1
2
3
4
5
   :before => # ccion a tomar ANTES de que se realice la llamada.
   :after   => # Accion DESPUES (no importa el resultado) de la llamada.
   :success => #Accion tomada cuando la llamada Termino con estado SATISFACTORIO
   :failure => # Activado cuando la llamada termina con estado ERROR.
   :complete => # Cuando la llamada termina.

Una vez teniendo en mente esto, podemos hacer que el link_to_remote se encargue de manipular el DOM dependiendo del estado de la llamada. Esto nos ayuda a que en el controlador solo nos preocupemos por destruir el objeto y no mas! Esta a todo DAR!

Quedaria Asi:

1
2
3
4
5
6
7
<%= link_to_remote "Borrar",
       :url =>{:action=>:destroy,:id=>@example.id},
       :before => "$('loading').show()",
       :complete => "$('loading').hide()",
       :success => "$('example_#{@example.id}').hide();",
       :fail => "alert('Error! Algo paso mal');"
%>

Como conclusion podemos ver que usar los callbacks de ajax pueden ayudar mucho a que nuestro codigo quede limpio y mas facil de manejar. Tambien ayuda a la interfaz del usuario. Hay que tomar en cuenta que la aplicacion que estemos desarrollando en nuestra computadora no tendra mucho delay, pero pensando ya en un ambiente donde la aplicacion esta en vivo, las cosas cambian. Si el usuario hace click en “borrar” y no sabe que la llamada esta siendo procesada, lo puede sacar de onda y dejar la aplicacion porque piensa que ya no sirve.

Espero les haya servido. =D

Posted in Codigo, Rails | Tagged , | Leave a comment