Skip to content

Instantly share code, notes, and snippets.

@sergiomaia
Created October 4, 2016 23:24
Show Gist options
  • Save sergiomaia/2e653b8ee0eee666e9df670f68a777ab to your computer and use it in GitHub Desktop.
Save sergiomaia/2e653b8ee0eee666e9df670f68a777ab to your computer and use it in GitHub Desktop.
Add Hashtag
# para esse exemplo pressupõe-se que você tenha um recurso post com o campo >> content:string
#Primeiro criamos um model Tag
rails g model Tag name:string
# >> crie uma tabela CreatePostsTags com post_id e tag_id (para nosso relacionamento has_and_belongs_to_many)
rails g migration CreatePostsTags post:references tag:references
# >> modifique a migration CreatePostsTags add :id => false, já que não precisaremos de id nesta tabela
class CreatePostsTags < ActiveRecord::Migration[5.0]
def change
create_table :posts_tags, :id => false do |t| # :id => false
t.references :post, foreign_key: true
t.references :tag, foreign_key: true
end
end
end
# >> crie a tabela
rake db:migrate
# >> add o relacionamento em Post.rb
class Post < ActiveRecord::Base
has_and_belongs_to_many :tags
end
# >> add o relacionamento em Tag.rb
class Tag < ActiveRecord::Base
has_and_belongs_to_many :posts
end
# >> criamos, em post.rb um callback after_create que faz um scan no texto e encontra palavras iniciadas com # e salva como uma tag
after_create do
post = Post.find_by(id: self.id)
hashtags = self.content.scan(/#\w+/)
hashtags.uniq.map do |hashtag|
tag = Tag.find_or_create_by(name: hashtag.downcase.delete('#'))
post.tags << tag
end
end
# >> ainda em post.rb criamos um callback after_update, faz o mesmo que o código acima, na action update
before_update do
post = Post.find_by(id: self.id)
post.tags.clear #deleta tudo e cria novamente
hashtags = self.content.scan(/#\w+/)
hashtags.uniq.map do |hashtag|
tag = Tag.find_or_create_by(name: hashtag.downcase.delete('#'))
post.tags << tag
end
end
# >> agora criamos uma rota para renderizar a view que irá mostrar os posts com as mesmas tags
get '/posts/hashtag/:name', to:'posts#hashtags'
# >> agora criamos no controle de posts, a action hashtags que especificamos na rota acima.
class PostsController < ApplicationController
.
.
.
def hashtags
tag = Tag.find_by(name: params[:name])
@posts = tag.posts
end
end
# >> crie o template hashtags (app/views/posts/hashtags.html.erb) com o conteúdo idêntico a app/views/posts/index.html.erb
# >> dentro desses templates, modifique a seguinte linha
<%= post.content %>
<%= display_with_hashtags(post.content) %>
# >> e por último, crie o helper display_with_hashtags que usamos acima (posts_helper.rb) para mostrar as tags como link
module PostsHelper
def display_with_hashtags(content)
content.gsub(/#\w+/){|word| link_to word, "/posts/hashtag/#{word.delete('#')}"}.html_safe
end
end
# Valeu o/
@romarioclacino
Copy link

romarioclacino commented Oct 5, 2016

Muito bacana isso. Se me permite dar uma sugestão, você pode colocar o código do callbacks em um model privado e só chamar esse método no create e update, assim:

before_create: :method_name
before_update: :method_name

Assim você não precisa repetir o código

@sergiomaia
Copy link
Author

Ótima sugestão cara. Obrigado.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment