<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xml:base="http://dagi3d.net">
  <channel>
    <title>dagi3d - ruby on rails</title>
    <link>http://dagi3d.net</link>
    <description/>
    <language>es</language>
    <item>
      <category></category>
      <title>Validando las asociaciones de ActiveRecord con RSpec</title>
      <link>http://dagi3d.net/blog/archive/2008/9/6/validando-las-asociaciones-de-activerecord-con-rspec</link>
      <description>
        <![CDATA[<p>
Después de estar un tiempo sin tocar Rails para nada, me puse el otro día a cacharrerar un poco con RSpec y se me ocurrió escribir un <em>matcher </em>para validar las asociaciones de los modelos, ya que consideraba que un simple <em>@objeto.should respond_to(:metodo)</em> realmente tampoco garantiza nada. 

    <br />Lo único &#8216;interesante&#8217; que puede aportar este código es que a la hora de escribir nuestros specs, basta con poner directamente el nombre de la relación, ya que la clase asociada se obtiene de manera automática(bendita sea la convención sobre la configuración :)), al contrario que el resto de ejemplos que pude encontrar por ahí, donde se indica la clase y si se desea, se indica aparte el nombre de la relación(y creo que así se aporta algo de legibilidad a los specs)
    :</p>
  <pre>@record.should have_many(:songs) # utiliza la clase Song

@record.should belong_to(:artist) # utiliza la clase Artist­

@record.should have_one(:cover) # utiliza la clase Cover
</pre>
  <p>Si fuese necesario también se puede indicar de manera manual la clase del modelo relacionado: 

    <br /></p>
  <pre>@record.should have_many(:favorite_songs).from_class(Song)</pre>
  <pre>module ARAssociationsMatchers

  # ARAssociationMatcher
  #
  class ARAssociationMatcher

    def initialize(expected, macro)
      @expected_association = expected
      @expected_macro = macro
    end

    def matches?(target)
      @target = target

      unless @expected_class.nil?
        expected_class = @expected_class
      else
        expected_class_name = @expected_association.to_s.singularize.camelize
        expected_class = Kernel.const_get(expected_class_name)
      end

      reflection = target.class.reflect_on_association(@expected_association)

      !reflection.nil? &amp;amp;&amp;amp; (reflection.macro == @expected_macro) &amp;amp;&amp;amp; (reflection.klass == expected_class)
    end

    def from_class(expected_class)
      @expected_class = expected_class
      self
    end

    def failure_message
      "expected #{@target.inspect} to #{@expected_macro} #{@expected_association.inspect}, but it didn't" 
    end

    def negative_failure_message
      "expected #{@target.inspect} not to #{@expected_macro} #{@expected_association.inspect}, but it didn't" 
    end

  end

  # matchers functions
  #
  def have_many(expected)
    ARAssociationMatcher.new(expected, :has_many)
  end

  def have_one(expected)
    ARAssociationMatcher.new(expected, :has_one)
  end

  def belong_to(expected)
    ARAssociationMatcher.new(expected, :belongs_to)
  end

end
</pre>

	<p>La idea inicial está tomada de ­<a href="http://smartic.us/2007/11/26/rspec-matcher-for-active-record-associations">este enlace</a></p>]]>
      </description>
      <pubDate>Sat, 06 Sep 2008 01:35:58 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2008/9/6/validando-las-asociaciones-de-activerecord-con-rspec#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>Back to the world</title>
      <link>http://dagi3d.net/blog/archive/2008/8/21/back-to-the-world</link>
      <description>
        <![CDATA[<p>Bueno, después de bastante tiempo sin actualizar voy a ver si vuelvo a retomar el tema del blog. Últimamente han cambiado muchas cosas, tanto en el aspecto laboral/escolar como en el personal(eso sí, todas para bien), así que espero volver a darle caña al tema de Rails que lo tenía bastante abandonado. Me acaban de llegar de Amazon los libros <a href="http://www.mypearsonstore.com/title/0672328844">The Ruby Way</a>, <a href="http://www.mypearsonstore.com/title/0321445619">The Rails Way</a>(que ya había catado en su versión en pdf y me pareció muy bueno) y <a href="http://www.mypearsonstore.com/bookstore/product.asp?isbn=0130676349">Agile Software Development with Scrum</a>, así que ahora toca <a href="http://es.wikipedia.org/wiki/Procrastinaci%C3%B3n">procrastinar</a> a tope :)

    <br /></p>]]>
      </description>
      <pubDate>Thu, 21 Aug 2008 22:44:02 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2008/8/21/back-to-the-world#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>A&#241;adiendo nuevos tipos en las migraciones de Rails</title>
      <link>http://dagi3d.net/blog/archive/2008/1/4/anadiendo-nuevos-tipos-en-las-migraciones-de-rails</link>
      <description>
        <![CDATA[<p>
En el proyecto con el que ando liado en mis r­atos libres, necesitaba añadir a varios modelos atributos que almaceneran decimales. En principio era tan simple como crear en cada migración las columnas con su tipo de dato correspondiente:</p>
  <pre>t.column :price, :precision =&amp;gt; 6, :scale =&amp;gt; 2, :default =&amp;gt; nil
</pre>
  <p>El caso es ­que se&nbsp; me hacía un tanto repetitivo estar añadiendo la misma línea en todas las migraciones donde me hacía falta(sé que no es para tanto, pero a veces la vagancia me puede) y además no estaba usando el estilo de los <a href="http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#M001222">nuevos atajos que trae Rails 2.0</a>, así que la solución era tan sencilla como reabrir la clase <em>ActiveRecord::ConnectionAdapters::TableDefinition</em>(bendito Ruby) y crear el método necesario:
  </p>
  <pre>class ActiveRecord::ConnectionAdapters::TableDefinition

  def currency(*columns)
    columns.each do |column|
      self.column column, :decimal, :precision =&amp;gt; 6, :scale =&amp;gt; 2, :default =&amp;gt; nil
    end
  end

end­
</pre>
­

  <p>Y ya podía usar en todas mis migraciones el método t.price teniendo que indicar únicamente el nombre de la columna(o columnas) que quería crear:

    <br /></p>
  <pre>class CreateLineItems &amp;lt; ActiveRecord::Migration
  def self.up
    create_table :line_items do |t|
      t.references :order
      t.references :item, :polymorphic =&amp;gt; true
      &lt;strong&gt;t.currency :price&lt;/strong&gt;
      t.timestamps
    end
  end

  def self.down
    drop_table :line_items
  end
end
</pre>]]>
      </description>
      <pubDate>Fri, 04 Jan 2008 00:50:12 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2008/1/4/anadiendo-nuevos-tipos-en-las-migraciones-de-rails#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>Charla/Taller de introducci&#243;n a Ruby On Rails</title>
      <link>http://dagi3d.net/blog/archive/2007/11/6/charla-taller-de-introduccion-a-ruby-on-rails</link>
      <description>
        <![CDATA[<p><img align="right" src="http://www.dagi3d.net/temp/rails.png" />Bajo el marco de las <span class="caps">III</span> Jornadas de Informática organizadas en la Universidad Europea de Madrid que se celebran los días 15 y 16 de noviembre, <a href="http://raul.murciano.net/">Raúl Murciano</a> y yo impartiremos una charla-taller de introducción a Ruby On Rails. El taller tendrá lugar el jueves 15 y comenzará a las 12:00 y finalizará sobre las 14:00.

    <br />El acceso es totalmente libre y gratuito(al igual que el resto de charlas y eventos de las jornadas) y animo a que se acerque a todo aquel que quiera iniciarse en este estupendo framework de desarrollo web.</p>
  <p><a href="http://www.gluem.net/jornadas/programa.html">Programa de las jornadas</a>
    <br /><a href="http://corporativo.uem.es/es/como-llegar">Cómo llegar a la <span class="caps">UEM</span></a>
    <br /></p>]]>
      </description>
      <pubDate>Tue, 06 Nov 2007 21:42:07 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2007/11/6/charla-taller-de-introduccion-a-ruby-on-rails#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>Programa de facturaci&#243;n en Ruby On Rails</title>
      <link>http://dagi3d.net/blog/archive/2007/8/15/programa-de-facturacion-en-ruby-on-rails</link>
      <description>
        <![CDATA[<p>Hace poco para optar a un trabajo tuve que realizar como prueba una
aplicación en Rails que gestionase un listado de facturas junto a sus
clientes. El caso es que decidí añadirle alguna cosilla más y hacerle
una interfaz más aceptable y liberar el código por si a alguien le podía
interesar.
esto) y el diseño del pdf es totalmente personalizable a partir de un
documento xhtml y css.
ampliando conforme lo vaya necesitando ahora que empiezo con el tema
del freelanceo.
Se puede ver en funcionamiento en <a target="_blank" href="http://facturails.dagi3d.net/">http://facturails.dagi3d.net/</a> y se puede descargar directamente desde el repositorio subversion en <a target="_blank" href="http://svn.dagi3d.net/rails/facturails/trunk">http://svn.dagi3d.net/rails/facturails/trunk</a> (bajo licencia <span class="caps">MIT</span>)</p>


	<pre><code><br />
<br /></code></pre>]]>
      </description>
      <pubDate>Wed, 15 Aug 2007 21:47:33 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2007/8/15/programa-de-facturacion-en-ruby-on-rails#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>Sumando varios elementos de un array</title>
      <link>http://dagi3d.net/blog/archive/2007/8/12/sumando-varios-elementos-de-un-array</link>
      <description>
        <![CDATA[<p>
Realizando una aplicación en Rails necesitaba
  sumar varios atributos de los objetos almacenados en un array. El problema es que cuando se trata de sumar un único atributo, se suele utilizar el método <em>inject</em>:</p>
  <pre>total = mi_array.inject { |sum, obj| sum + obj.value }</pre>
  <p>
pero en este caso no me terminaba de convecer estar llamando al método <em>inject </em>tantas veces como atributos quisiera sumar, así que en teoría la solución pasaría por iterar sobre el array e ir sumando:</p>
  <pre>var1 = 0
var2 = 0
var3 = 0
...
mi_array.each do |obj|
  var1 += obj.value1
  var2 += obj.value2
  var3 += obj.value3
  ...
end
</pre>
  <p>Funcionar, funcionaba, pero digamos que el código quedaba algo feo, así que para seguir trasteando, intenté encontrar una solución más &#8216;ruby&#8217; y esto fue lo que hice:</p>
  <pre>class Array

  def accumulate(fields)

    results = fields.dup

    self.each do |obj|
      fields.each_key do |key|
        results[key] += obj.send(key) if obj.respond_to?(key)
      end
    end

    results
  end
end
</pre>
  <p>Ahora bastaba con llamar al método <em>accumulate </em>sobre el array de objetos e indicar qué atributos quería sumar para obtener un hash con los resultados:</p>
  <pre># la lista de objetos
foos = [
  OpenStruct.new(:foo =&amp;gt; 1, :bar =&amp;gt; 2, :foobar =&amp;gt; 3),
  OpenStruct.new(:foo =&amp;gt; 3, :bar =&amp;gt; 4, :foobar =&amp;gt; 5),
  OpenStruct.new(:foo =&amp;gt; 5, :bar =&amp;gt; 6, :foobar =&amp;gt; 7)
]

foos.accumulate(:foo =&amp;gt;­; 0, :bar =&amp;gt; 0, :foobar =&amp;gt; 0) 
# {:foo=&amp;gt;9, :bar=&amp;gt;12, :foobar=&amp;gt;15}­
</pre>]]>
      </description>
      <pubDate>Sun, 12 Aug 2007 16:54:49 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2007/8/12/sumando-varios-elementos-de-un-array#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>Comparar gemas instaladas en desarrollo y producci&#243;n</title>
      <link>http://dagi3d.net/blog/archive/2007/7/21/comparar-gemas-instaladas-en-desarrollo-y-produccion</link>
      <description>
        <![CDATA[<p>
A raíz de un <a href="http://www.norellana.com/2007/07/17/cuidado-con-lo-que-instalas-en-desarrollo/">post</a> en el blog de <a href="http://www.norellana.com/">Nicolás Orellana</a>, donde mencionaba el problema de no tener sincronizadas las gemas instaladas en la máquina de desarrollo con las que deberían estar también en la máquina de producción, me animé a escribir una pequeña tarea para Capistrano que intentase resolver este problema. La idea en principio era sencilla, tan sólo habría que obtener la lista de gemas instaladas en local utilizando el comando &#8216;gem list&#8217; tal como mencionaba Nicolás, hacer lo mismo en remoto, compararlas para ver las diferencias y luego ofrecer la posibilidad de instalar aquellas que no estuviesen en la máquina de producción.</p>
  <p>Y esta fue la solución a la que llegué (de momento no hace ningún control sobre las versiones, pero si tengo un rato intentaré completarla):</p>
  <p></p>
  <pre>task :compare_gems do

  def parse_gem_line(line, gems)
    if line =~ /^([[:alnum:]]+)\s\((.*)\)/
      gem = $1
      gems[gem] = []
      versions = $2.gsub(/\s/, '').split(",")
      gems[gem] &amp;lt;&amp;lt; versions
    end
  end

  local_gems = {}
  remote_gems = {}

  local_gem_list = %x{gem list}
  local_gem_list.each_line { |line| parse_gem_line(line, local_gems)}

  run "gem list" do |channel, stream, data|
    parse_gem_line(data, remote_gems)
  end

  not_installed_gems = local_gems.dup

  not_installed_gems.delete_if {|key, value| remote_gems.has_key? key }

  puts "== Not installed gems ==" 

  not_installed_gems.each_key do |gem|

    puts "* #{gem}" 
    puts "Install? [yN]" 
    answer = STDIN.gets.chomp

    if answer.downcase == "y" 
      run "gem install #{gem} -y" do |channel, stream, data|
        puts data
        if data =~ /^&amp;gt;/
          install_option = STDIN.gets.chomp
          channel.send_data "#{install_option}\n" 
        end
      end
    end
  end

  puts "========================" 
end
</pre>
  <p></p>]]>
      </description>
      <pubDate>Sat, 21 Jul 2007 05:42:10 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2007/7/21/comparar-gemas-instaladas-en-desarrollo-y-produccion#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>Generar documentos pdf con Rails y Flying Saucer</title>
      <link>http://dagi3d.net/blog/archive/2007/6/28/generar-documentos-pdf-con-rails-y-flying-saucer</link>
      <description>
        <![CDATA[<p>En la aplicación que estaba haciendo en RoR necesitaba generar documentos en formato pdf a partir de los formularios rellenados por el usuario. Había comenzado a hacerlos usando la librería para ruby <a href="http://ruby-pdf.rubyforge.org/pdf-writer/"><span class="caps">PDF</span>::Writer</a> y aparentemente funcionaba bastante bien pero resultaba un infierno el tener que maquetar toda la presentación desde código, aparte de que no me gustaba mucho la idea de hacerlo así de cara a posibles cambios de la plantilla.

    <br />
    De casualidad, a través de un enlace en Devzone di con un <a href="http://today.java.net/pub/a/today/2007/06/26/generating-pdfs-with-flying-saucer-and-itext.html">árticulo</a> sobre la generación de pdf&#8217;s en java usando las librerías <a href="https://xhtmlrenderer.dev.java.net/">Flying Saucer</a> e <a href="http://www.lowagie.com/iText/">iText.</a>
    <br />
    Flying Saucer es una librería para renderizar documentos xhtml y css 2.1 y que ahora trabaja de manera conjunta a iText, que sirve para generar documentos pdf.

    <br />
    Así que la opción de tratar de integrar esta librería en la aplicación para así convertir la vista generada desde Rails en el pdf, era más que tentadora.</p>
  <p>
    Para hacerlo, lo primero era descargar la librería <a href="https://xhtmlrenderer.dev.java.net/">Flyin Saucer</a>(que ya viene con iText incluida) y generar la aplicación en Java que se encargase de convertir el documento xhtml en pdf(está copiada casi tal cual de un ejemplo del artículo):</p>
  <pre>import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.DocumentException;

public class Xhtml2Pdf {

    /**
     * @param args
     */
    public static void main(String[] args) throws IOException, DocumentException {

        if (args.length != 2) return;

        String inputFile = args[0];
        String url = new File(inputFile).toURI().toURL().toString();

        String outputFile = args[1];

        OutputStream os = new FileOutputStream(outputFile);

        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocument(url);
        renderer.layout();
        renderer.createPDF(os);

        os.close();
    }
}
</pre>
  <p>Luego escribí una sencilla función en ruby que se encargase de ejecutar la clase hecha en java pasándole como parámetros el archivo de origen con el documento xhtml y el archivo de destino donde se generaría el pdf(lo único que tiene así de &#8216;chicha&#8217; es que genera el classpath de manera dinámica):</p>
  <pre>def xhtml2pdf(input_file, output_file)

  java_dir = File.join(File.expand_path(File.dirname(__FILE__)), "java")
  jar_dir = File.join(java_dir, "jar")

  class_path = ".:#{java_dir}" 

  Dir.foreach(jar_dir) do |jar|
    class_path &amp;lt;&amp;lt; ":#{jar_dir}/#{jar}" if jar.match(/\.jar/)  
  end

  command = "java -cp #{class_path} Xhtml2Pdf #{input_file} #{output_file}" 
  system(command)
end
</pre>
  <p>Para poder utilizar la librería desde el controlador, tan sólo quedaba copiar el fichero en ruby dentro la carpeta lib/ del proyecto Rails, la clase en java en lib/java y los jar&#8217;s necesarios para ésta, en lib/java/jar:</p>
  <p><img src="/temp/xhtml2pdf.png" /></p>
  <p>Y en el controlador tan sólo tenía que generar la vista y guardarla en un fichero, convertirlo en pdf y mandarlo al cliente:</p>
  <pre>require 'xhtml2pdf'

class FooController &amp;lt; ApplicationController

  def generate_pdf

    @document = Document.find(params[:id])

    xhtml = "/tmp/foo.xhtml" 
    pdf = "/tmp/foo.pdf" 

    File.open(xhtml, "w") do |file|
      file &amp;lt;&amp;lt; render_to_string(:template =&amp;gt; "pdf/document", :layout =&amp;gt; "../pdf/pdf")
    end

    xhtml2pdf(xhtml, pdf)

    send_file pdf,
      :filename =&amp;gt; "document.pdf",
      :type =&amp;gt; "application/pdf" 
  end
end
</pre>
  <p>Y si quisieramos ir viendo en el navegador cómo va a quedar sin necesidad de generar el pdf, bastaría con comentar el contenido de esta función(o hacer una nueva) y generar la vista como hariamos normalmente:</p>
  <pre>render :template =&amp;gt; "pdf/document", :layout =&amp;gt; "../pdf/pdf" 
</pre>
  <p>Por último, comentar que para que Flying Saucer pueda acceder a las imágenes y hojas de estilo del documento xhtml, las rutas de estos elementos deben estar de manera absoluta apuntando a un recurso local(file://&lt;rutadelfichero&gt;) o bien de manera relativa a dónde se encuentre físicamente el xhtml, por lo que igual habría que hacer un helper que modificase la ruta de los recursos dependiendo de si se está previsualizando desde el navegador o se está volcando en disco.</p>
  <p>Aunque <span class="caps">PDF</span>::Writer parecía funcionar bastante bien e iba más rápido ya que escribe directamente el pdf sin necesidad de parsear un documento xhtml y sus hojas de estilo, creo que en este caso compensa tener un pequeño híbrido en rails y java por el tiempo ahorrado en maquetar el pdf directamente desde ruby.</p>]]>
      </description>
      <pubDate>Thu, 28 Jun 2007 12:37:25 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2007/6/28/generar-documentos-pdf-con-rails-y-flying-saucer#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>Ocultando objetos en Ruby On Rails: acts_as_invisible</title>
      <link>http://dagi3d.net/blog/archive/2007/6/16/ocultando-objetos-en-ruby-on-rails-acts_as_invisible</link>
      <description>
        <![CDATA[<p>Durante el desarrollo de la aplicaci&oacute;n que mencion&eacute; en el &uacute;ltimo post, se me plante&oacute; un nuevo &#8216;problema&#8217;  y es que necesitaba que desde el propio programa se pudieran borrar registros pero que realmente no se eliminaran de la base de datos, si no que simplemente desaparecieran de cara a la aplicaci&oacute;n. En principio esto era tan sencillo de solucionar como a&ntilde;adir un nuevo atributo a la clase a modo de flag y a&ntilde;adir una nueva condici&oacute;n a la hora de buscar los objetos dentro del controlador:</p>
<pre>Document.find(:all, :conditions =&amp;gt; [&amp;quot;visible = ?&amp;quot;, true])&lt;br /&gt;Document.find(id, :conditions =&amp;gt; [&amp;quot;visible = ?&amp;quot;, true])&lt;br /&gt;&lt;br /&gt;# &amp;quot;borrando&amp;quot; el objeto&lt;br /&gt;document.visible = false&lt;br /&gt;document.save</pre>
<p>Esto funcionaba, pero me parec&iacute;a un tanto engorroso tener que a&ntilde;adir una condici&oacute;n extra a la hora de hacer las b&uacute;squedas y borrar en todas las clases que quer&iacute;a que fuesen &#8216;ocultables&#8217;. As&iacute; que por aquello de seguir con la filosof&iacute;a del <span class="caps">DRY</span> e indagar un poco en el core de Rails, hice un sencillo plugin que a&ntilde;ad&iacute;a esta funcionalidad de manera transparente y sin necesidad de tocar el c&oacute;digo ya existente del controlador. As&iacute;, tan s&oacute;lo habr&iacute;a que marcar la clase del modelo con el m&eacute;todo &#8216;acts_as_invisible&#8217; (Se da por hecho que existe una columna de tipo booleano llamada &#8216;visible&#8217; en la tabla asociada a la clase):</p>
<pre>class Document &amp;lt; ActiveRecord::Base&lt;br /&gt;  &lt;br /&gt;  acts_as_invisible&lt;br /&gt;&lt;br /&gt;end</pre>
<p>Y a la hora de trabajar con el modelo, se har&iacute;a de la siguiente manera:</p>
<pre># recuperar s&amp;oacute;lo los documentos visibles&lt;br /&gt;Document.find(:all)&lt;br /&gt;&lt;br /&gt;# recuperar s&amp;oacute;lo los documentos visibles cuyo t&amp;iacute;tulo empiece por 'presupuesto'&lt;br /&gt;Document.find(:all, :conditions =&amp;gt; &amp;quot;title like 'presupuesto%'&amp;quot;)&lt;br /&gt;&lt;br /&gt;# recuperar todos los documentos&lt;br /&gt;Document.find(:all, :show_hidden =&amp;gt; true)&lt;br /&gt;&lt;br /&gt;# ocultar un documento&lt;br /&gt;Document.destroy(id)&lt;br /&gt;&lt;br /&gt;# si se tratase de recuperar el documento ocultado &lt;br /&gt;# previamente, saltar&amp;iacute;a una excepci&amp;oacute;n&lt;br /&gt;Document.find(id)&lt;br /&gt;&lt;br /&gt;# volver a hacer visible un documento&lt;br /&gt;Document.show(id)&lt;br /&gt;&lt;br /&gt;# borrar el documento de la base de datos&lt;br /&gt;Document.confirm_destroy(id)</pre>
<p>Por si a alguien le interesa, puede bajarse el plugin de <a href="http://svn.dagi3d.net/rails/acts_as_invisible/tags/acts_as_invisible/ ">http://svn.dagi3d.net/rails/acts_as_invisible/tags/acts_as_invisible/ </a>y si tengo algo de tiempo ya le a&ntilde;adir&eacute; alguna funcionalidad m&aacute;s como que el nombre del campo utilizado sea configurable.</p>]]>
      </description>
      <pubDate>Sat, 16 Jun 2007 01:25:26 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2007/6/16/ocultando-objetos-en-ruby-on-rails-acts_as_invisible#post_comments</comments>
    </item>
    <item>
      <category></category>
      <title>Parche para acl_system</title>
      <link>http://dagi3d.net/blog/archive/2007/6/6/parche-para-acl_system</link>
      <description>
        <![CDATA[<p>Ahora estoy desarrollando un programa de gestión con Ruby On Rails donde necesitaba usar algún sistema de control de privilegios dentro de la aplicación. Tras investigar un poco opté por usar <a href="http://brainspl.at/articles/2006/02/20/new-plugin-acl_system">acl_system</a>, que parecía bastante sencillo de usar y era más que suficiente para lo que necesitaba, ya que permite restringir el acceso a los métodos del controlador y delimitar partes de la vista para usuarios que tengan un determinado &#8216;rol&#8217; .
<br />
El único inconveniente era que si dentro del controlador quería preguntar por un rol en concreto para hacer cosas más específicas, tenía que hacer algo así:<br /></p>


<code>
<pre>
if current_user.roles.map { |role| role.title }.include?("admin")
...
end
</pre>
</code>

Aunque funcionaba perfectamente, pensaba que quedaría mejor si le añadía un pequeño parche al plugin acl_system que permitiese hacer algo del tipo
<code>
<pre>
if current_user.has_admin_role?
...
end
</pre>
</code>

Así que aprovechando el potencial de ruby, en unas pocas líneas de código conseguí dar con la solución:
<code>
<pre>
module Dagi3d

  module RoleModel
    def self.included(mod)
      mod.extend(ClassMethods)
    end

    module ClassMethods

      def has_roles
        include InstanceMethods
      end

    end # ClassMethods 

    module InstanceMethods

      def method_missing(method, *args)

        if method.to_s =~ /has_(\w+)_role\?/
          self.roles.map {|role| role.title}.include? $1
        else
          super
        end
      end #method_missing

    end #InstanceMethods
  end
end
</pre>
</code>

Para hacerlo andar, bastaría con añadir el módulo en la carpeta del plugin e incluirlo en el fichero init.rb:
<code>
<pre>
require 'caboose/logic_parser'
require 'caboose/role_handler'
require 'caboose/access_control'
require 'caboose/role_model'

ActionController::Base.send :include, Caboose
ActionController::Base.send :include, Caboose::AccessControl
ActiveRecord::Base.send :include, Dagi3d::RoleModel
</code>
</pre>

Y ya por último, llamar en nuestro modelo al método de clase &#8216;has_roles&#8217;:
<code>
<pre>
class User &lt; ActiveRecord::Base

  has_roles
  ...
end
</code>
</pre>]]>
      </description>
      <pubDate>Wed, 06 Jun 2007 20:54:05 +0100</pubDate>
      <comments>http://dagi3d.net/blog/archive/2007/6/6/parche-para-acl_system#post_comments</comments>
    </item>
  </channel>
</rss>
