Añadiendo Likes a nuestra aplicación

Seguramente ya te diste cuenta de que Ruby nos hace la vida mucho más sencilla gracias a las gemas, hoy usaremos acts as votable para añadir likes a nuestra aplicación.

Añadiendo la gema

Como es costumbre, comenzaremos con añadir la gema a nuestro archivo Gemfile, añadela debajo de Cancan, tal que así:

gem 'cancancan'
gem 'acts_as_votable', '~> 0.10.0'

Instalala con $ bundle, luego genera la migración requerida por la gema con $ rails g acts_as_votable:migration y luego migra $ rails db:migrate.

Configurando los Likes

Ahora, debemos hacerle saber a nuestra gema cuales modelos pueden recibir likes, para esto, abrimos el modelo fact.rb y añadimos acts_as_votable, de tal manera que queda así:

class Fact < ApplicationRecord
  resourcify
  acts_as_votable # NUEVA LÍNEA
  has_attached_file :image, :styles => { :large => "1024x768", :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/default_image.png"
  validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
  validates :image, presence: true
  belongs_to :user
  has_many :comments, dependent: :destroy
end

Ya le hicimos saber a nuestra gema que los Facts pueden tener likes, ahora tenemos que hacerle saber quien puede votar, para ello, abre el modelo user.rb y añade acts_as_voter, quedaría así:

class User < ApplicationRecord
  acts_as_voter # NUEVA LÍNEA
  rolify
  # Relationships
  has_many :facts
  
  # Devise custom fields
  validates :name, presence: true, uniqueness: true
  
  # Paperclip validations
  has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/default_avatar.png"
  validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
  validates_with AttachmentSizeValidator, attributes: :avatar, less_than: 1.megabytes
  
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end

Genial, nuestros modelos están listos, falta editar los permisos, de tal manera que un usuario este autorizado a dar likes, abre el archivo ability.rb:

def initialize(user)
    if user.has_role? :admin
      can :manage, :all
    else
      can :read, :all
      can :create, :all
      can :upvote, Fact # NUEVA LÍNEA
    end
    
    can :update, Fact do |fact|
      fact.user == user
    end
    
    can :destroy, Fact do |fact|
      fact.user == user
    end
  end

Editemos nuestro controlador de tal manera que podamos dar likes, abre el archivo facts_controller.rb, primero edita before_action :find_fact, only: [:show, :edit, :update, :destroy] y añade :upvote, quedaría así: before_action :find_fact, only: [:show, :edit, :update, :destroy, :upvote]. Puedes haber notado que aún no hemos creado este método, debajo de:

def destroy
  @fact.destroy
  redirect_to facts_path, :notice => "Fact deleted successfully!"
end

Añade:

def upvote
  @fact.upvote_by current_user
  redirect_to :back
end

Ahora, tenemos que editar nuestras rutas, para poder hacer uso de este método desde nuestras vistas:

Rails.application.routes.draw do
  devise_for :users
  root "facts#index"
  # DESDE AQUÍ CAMBIAMOS:
  resources :facts do
    member do
      put "like", to: "facts#upvote"
    end
  end
end

Hemos terminado, solo falta añadir un botón que sirva para dar likes y mostrar la cuenta, en tu vista facts/show.html.erb justo debajo de <% if current_user %> añade:

<%= link_to like_fact_path(@fact), method: :put do %>
  <div class="ui labeled button" tabindex="0">
    <div class="ui blue button">
      <i class="heart icon"></i> Like
    </div>
    <div class="ui basic blue left pointing label">
      <%= @fact.get_upvotes.size %>
    </div>
  </div>
<% end %>

La mayoría son solo estilos, debes prestar atención a link_to like_fact_path(@fact), method: :put do, donde le decimos que deseamos añadir un nuevo like al Fact actual usando el método put (“actualizar”), además de <%= @fact.get_upvotes.size %> donde contamos cuantos likes tiene nuestro Fact. Puedes ver los cambios realizados en el repositorío si te has confundido.

Eso es todo por esta serie, espero que hayan tenido la oportunidad de aprender algo nuevo y nos volveremos a ver en la red.