rails 2.1.0

Posted by vigosan, Wed May 14 17:04:00 UTC 2008

En los próximos artículos voy a comentar las novedades de Rails que más me han impresionado de su última versión 2.1.0 y que próximamente será estable, por ejemplo:
vicent_route = User.find_by_name('vicent').routes.find(:first)
pepe_route = vicent_route.clone
Y eso también se podría abreviar como:
vicent_route = User.find_by_name('vicent').routes.first (ó last)
pepe = vicent_route.clone
¡Bonito de verdad!

0 comments | Filed Under: Rails | Tags:

Passenger, Rails + Apache made easy

Posted by vigosan, Mon Apr 14 10:13:00 UTC 2008

Needless to say, you only have to view the screencast of the new Passenger. I’m sure that you will cry ;)

138 comments | Filed Under: Rails | Tags:

eRun, new design

Posted by vigosan, Wed Apr 09 20:17:00 UTC 2008

I’m currently working hard to launch officially my new project eRun – mientrenamiento.com. For new people, eRun is an online community of Runners. Using this tool, you will be able to manage and share your diary trainings, and handle the kilometers made with each of your pair of running shoes. Here you are some of the new views:

135 comments | Filed Under: Proyectos Rails | Tags:

Setting up a Samba Server in few steps

Posted by vigosan, Fri Apr 04 10:08:00 UTC 2008

I will try to explain here the work we have done for implementing a linux-samba server with several users and folder privileges, of course, for server issues, we are going to use Debian distribution.

First at all, we need to install the samba packages as follow:

boxroom:# apt-get install samba samba-common

The next step is creating the users:

boxroom:# useradd -s /usr/sbin/nologin pini
boxroom:# smbpasswd -a pini
boxroom:# useradd -s /usr/sbin/nologin pon
boxroom:# smbpasswd -a pon

And the groups, for example:

boxroom:# groupadd cartoons

The group cartoons will include both users:

boxroom:# usermod -a -G cartoons pini
boxroom:# usermod -a -G cartoons pon

Now, we need to share one folder, in my case the /intranet one:

boxroom:# chmod 775 /intranet

And finally we edit the /etc/samba/smb.conf:

[global]
   workgroup = factory
   server string = Intranet

 # In my case I have a WINS Server in my network, so I use it, why not…
   wins support = no
   wins server = 192.168.100.2

####### Authentication #######
   security = user
   encrypt passwords = true
   invalid users = root

[Intranet]
   comment = Intranet
   path = /intranet
   guest ok = no
   browseable = yes
   writable = yes
   create mask = 6770
   directory mask = 6770

Now, we are going to create three folders for showing you how the permissions work:

boxroom:# cd /intranet
warehouse:/intranet# mkdir fpini
warehouse:/intranet# mkdir fpon
warehouse:/intranet# mkdir public

And we set the permissions:

warehouse:/intranet# chmod –R 6770 fpini fpon
warehouse:/intranet# chown pini:pini fpini
warehouse:/intranet# chown pon:pon fpon
warehouse:/intranet# chmod –R 6775 public
warehouse:/intranet# chown -R pini:cartoons public

In this case, Pini can access to fpini and public folders and Pon to fpon and public. Also, Pini can’t write in Pon folder and vice versa. In the case of plublic folder, all the users can see it, but only Pini or the users that belongs to cartoons group can write or delete files.

So that’s all, I hope you have enough information for setting your own intranet, bye.

138 comments | Filed Under: Debian | Tags:

Menú horizontal al estilo Flickr o Facebook

Posted by vigosan, Fri Mar 21 19:17:00 UTC 2008

I write my own similar Facebook horizontal menu using DOM (Document Object Model). The advantage of DOM is that the menu doesn’t depend of any external library such as jQuery or Scriptaculous. You can download the code pressing here. If you found any incompatibility, please let me know.

// fMenu v1.0.2
// By Vicent Gozalbes [vigosan@gmail.com]

var imgs = [];

function init() {
  if (!document.getElementsByTagName || !document.getElementById) { return; }
  var uls = document.getElementsByTagName('ul');

  for (var u=0; u < uls.length; u++) {
    if (uls[u].className.search(/\bmenu\b/) == -1) { continue; }
    var lis = uls[u].getElementsByTagName('li')
    for (var l=0; l < lis.length; l++) {
      var spans = lis[l].getElementsByTagName('span');
      for (var s=0; s < spans.length; s++) {
        var node = spans[s];
        if(node.className == 'head_menu' && lis[l].getElementsByTagName('ul').length > 0) {
          var image = node.childNodes[1];
          addEvent(image, 'mouseover', getMoverFor(image), false);
          addEvent(image, 'mouseout', getMoutFor(image), false);
          addEvent(image, 'click', getMclickFor(image), false);
          addEvent(document, 'click', getMclickFor(document), false);
          image.topul = lis[l].getElementsByTagName('ul')[0];
          image.topul.isOpen = false;
          imgs.push(image);
        }
      }
    }
  }
}

function addEvent(elm, evType, fn, useCapture) {
  if(elm.addEventListener) {
    elm.addEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.attachEvent) {
    var r = elm.attachEvent('on' + evType, fn);
    return r;
  } else {
    elm['on' + evType] = fn;
  }
}

function stopEvent(e) {
  if(!e) var e = window.event;

  //e.cancelBubble is supported by IE 
  e.cancelBubble = true;

  //e.stopPropagation works only in Firefox.
  if (e.stopPropagation) {
    e.stopPropagation();
    }
  return false;
}

function closeUls() {        
  for (var i = 0; i < imgs.length; i++) {
    imgs[i].topul.style.display = 'none';
    imgs[i].src = 'images/arrow.png';
    imgs[i].topul.isOpen = false;
  }
}

function setMover(e, targetElement) {
  var el = window.event ? targetElement : e ? e.currentTarget : null;
  if (!el) return;
  el.src = 'images/arrow_hover.png';
}

function setMout(e, targetElement) {
  var el = window.event ? targetElement : e ? e.currentTarget : null;
  if (!el) return;
  el.src = el.topul.isOpen ? 'images/arrow_select.png' : 'images/arrow.png';
}

function setMclick(e, targetElement) {
  stopEvent(e);
   var el = window.event ? targetElement : e ? e.currentTarget : null;
  if (!el) return;

  if(el.nodeName.toLowerCase() != 'img' && !el.topul) {
    closeUls();
    return;
  } else if (el.topul.isOpen) {
    el.src = 'images/arrow.png';
    el.topul.style.display = 'none';
    el.topul.isOpen = false;
  } else {
    closeUls();
    el.src = 'images/arrow_select.png';
    el.topul.style.display = 'block';
    el.topul.isOpen = true;
  }
}

function getMoverFor(node) {
  return function(e) { setMover(e, node); };
}

function getMoutFor(node) {
  return function(e) { setMout(e, node); };
}

function getMclickFor(node) {
  return function(e) { setMclick(e, node); };
}

addEvent(window, 'load', init, false);

0 comments | Filed Under: Proyectos | Tags:

eRun, mi nuevo proyecto Rails

Posted by vigosan, Mon Feb 25 12:28:00 UTC 2008

Últimamente ando un poco desaparecido, pero la realidad es que estoy liado con un proyecto bastante interesante, se llama eRun.

¿Qué es eRun?

eRun es una herramienta Web gratuita, que te permite registrar tus entrenamientos diarios de atletismo, así como llevar un control de los kilómetros realizados con cada par de tus zapatillas.

Funcionalidad

  • Registrar entrenamientos, indicando el tipo de entrenamiento, distancia recorrida, sensaciones, ppm, calorías, zapatillas utilizadas, etc.
  • Registrar zapatillas, modelos, precio, etc. La aplicación llevará la suma del kilometraje realizado y aconsejará su cambio.
  • Gráficas semanales, mensuales de km, ppm, distancias etc.
  • “Amigos” con los que compartir la información de nuestros entrenamientos y con los que poder compararnos y competir.

La funcionalidad de mañana

  • Crear y compartir planes de entrenamiento.
  • Gestión de carreras. Puedes anunciar una carrera que estás organizando y si participas en alguna darla de alta como un entrenamiento con puesto. ¡Y a ver quien ha llegado antes de tu grupo de amigos!
  • OpenId para hacer más sencilla la validación, así no es necesario tener que recordar tantos usuarios y contraseñas.
  • El log como un pequeño twitter para compartir tus comentarios sobre tus entrenamientos con tus amigos y contigo mismo.
  • Retos, será la parte más divertida, por ejemplo ver quien corre más km en una semana, o quien hace una marathon en menos de 3h45 etc.
  • Compra de zapatillas con recomendación por parte de la aplicación en base a a tu peso, tipo de pisada, distancias medias recorrida.
  • Entrenador personal (cualificado) y planes de entrenamiento a medida (previo pago al entrenador).

Características diferenciadoras

  • Creado por corredores para corredores
  • Proyecto dinámico. Realease early / release often. Una funcionalidad nueva por semana.
  • Total atención a las necesidades / peticiones de los usuarios

0 comments | Filed Under: Proyectos Rails | Tags:

Rails 2.0 y como enviar correos a través de Gmail

Posted by vigosan, Mon Feb 25 12:25:00 UTC 2008

Aquípongo un receta rápida de como enviar correos a través de Gmail.

Primero en el directorio /lib creamos un fichero llamado smtp_tls.rb que contenga:

require 'openssl'
require 'net/smtp'

Net::SMTP.class_eval do
  private
  def do_start(helodomain, user, secret, authtype)
    raise IOError, 'SMTP session already started' if @started
    check_auth_args user, secret, authtype if user or secret

    sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
    @socket = Net::InternetMessageIO.new(sock)
    @socket.read_timeout = 60 #@read_timeout

    check_response(critical { recv_response() })
    do_helo(helodomain)

    raise 'openssl library not installed' unless defined?(OpenSSL)
    starttls
    ssl = OpenSSL::SSL::SSLSocket.new(sock)
    ssl.sync_close = true
    ssl.connect
    @socket = Net::InternetMessageIO.new(ssl)
    @socket.read_timeout = 60 #@read_timeout
    do_helo(helodomain)

    authenticate user, secret, authtype if user
    @started = true
  ensure
    unless @started
      # authentication failed, cancel connection.
      @socket.close if not @started and @socket and not @socket.closed?
      @socket = nil
    end
  end

  def do_helo(helodomain)
    begin
      if @esmtp
        ehlo helodomain
      else
        helo helodomain
      end
    rescue Net::ProtocolError
      if @esmtp
        @esmtp = false
        @error_occured = false
        retry
      end
      raise
    end
  end

  def starttls
    getok('STARTTLS')
  end

  def quit
    begin
      getok('QUIT')
    rescue EOFError
    end
  end
end

Al final del fichero config/environment.rb añadimos:

require 'lib/smtp_tls'

yaml_contents = File.open("#{RAILS_ROOT}/config/mailer.yml") 
mailer_options = YAML.load(yaml_contents) 
ActionMailer::Base.smtp_settings = mailer_options 

Y por último la configuración de la cuenta en config/mailer.yml:

:address: "smtp.gmail.com" 
:port: 587 
:domain: "tudominio.com" 
:user_name: "usuario@gmail.com" 
:password: "contraseña" 
:authentication: :plain 

0 comments | Filed Under: Rails | Tags:

Menús dinámicos

Posted by vigosan, Mon Feb 25 12:24:00 UTC 2008

No se si el título refleja exactamente lo que pretendo hacer, pero de lo que se trata es de ayudarnos de algún helper para tener nuestro propio constructor de menús; voy a comentaros mi idea y si alguien tiene alguna mejor que la comente.

Primero en application.rb he defino la estructura que tendrá el menú, utilizando arrays, y en los que indico el nombre del enlace y la url. Además, mostrará un menú diferente dependiendo si el usuario está validado o no.

# application.rb
  helper_method navigation_links

  def navigation_links
    if logged_in?
      return [
        [ "Logout", "#{logout_path}" ]
      ]
    else
      return [
        [ "Home", "#{root_path}" ],
        [ "Log in", "#{login_path}" ],
        [ "Signup", "#{signup_path}" ]
      ]
    end
  end

Ahora application_helper.rb escribo las funciones que generarán el menú:

  def link_for(label, path = {})
    if controller.controller_name == path.split("/").last
      content_tag :li, link_to(label, path, { "class"=> "current" })
    else
      content_tag :li, link_to(label, path)
    end
  end

  def links_for_navigation(options = {})
    class_name = options[:class] || "navigation_links" 
    code = "<ul class=\"#{class_name}\">\n" 
    links = []
    navigation_links.each do |label, path|
      links.push link_for(label, path)
    end
    code << links.join(separator)
    code << "</ul>" 
  end

  def separator
    # quitar comentario si quieres añadir un separador
    # %{ <span class="separator"> | </span> }
  end

Y en la vista:

<div id="sidebar">
  <%= links_for_navigation %>
</div>

Lo dicho, si alguien tiene una idea mejor, que no dude en compartirla.

0 comments | Filed Under: Rails | Tags:

Paginación acts_as_taggable_on_steroids + will_paginate

Posted by vigosan, Mon Feb 25 12:23:00 UTC 2008

En un proyecto, estamos usando un par de plugins bastante conocidos, uno es will_paginate y el otro acts_as_taggable_on_steroids. Para ponernos en ejemplo, queremos obtener una lista de artículos paginados de 10 en 10, lo podemos hacer con:

@articles = Article.paginate(:all, :per_page => 10, :page => params[:page])

Por otra parte, podemos marcar nuestros artículos con una o varias etiquetas, tags:

  # modelo
  class Article < ActiveRecord::Base
    acts_as_taggable
    validates_presence_of :title, :body
  end

  # controlador
  def create
    @article = Article.new(params[:article])
    @article.tag_list = params[:tag_list]
    respond_to do |format|
      if @article.save
        flash[:notice] = 'Article was successfully created.'
        format.html { redirect_to article_url(@article) }
      else
        format.html { render :action => "new" }
      end
    end
  end

  # formulario
  <p>
    <b>Title</b><br />
    <%= f.text_field :title %>
  </p>

  <p>
    <b>Body</b><br />
    <%= f.text_area :body %>
  </p>

  <p>
    <b><%= _("Tags") %></b><br />
    <%= text_field_tag :tag_list, @article.tags.collect{|t| t.name}.join(" ")  %>
  </p>

Y en la vista mostrar una nube de etiquetas o tags:

<div id="sidebar">
  <h2>Tags</h2>
  <% tag_cloud @tags, %w(css1 css2 css3 css4) do |tag, css_class| %>
  <%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %>
   <% end %>
</div>

Y lo que pretendemos es que cuando se pulse en una de las etiquetas, se muestren sólo los artículos perteneciente a ellas. Aquí es donde combinamos los dos plugins:

# controlador
  def tag
    @articles = Article.paginate_by_id(Article.find_tagged_with(params[:id]), :page => params[:page])
    respond_to do |format|
      format.html { render :action => :index }
      format.xml  { render :xml => @articles.to_xml }
    end
  end

0 comments | Filed Under: Rails | Tags: