I will summarize how to implement the hashtag function.
https://glodia.jp/blog/3936/ https://qiita.com/Naoki1126/items/4ea584a4c149d3ad5472
I implemented it by combining the information from these two articles. Thank you very much.
This time, I will explain how to introduce hashtags in photo captions using the photo posting app as a theme.
A hashtag with a link is described in the caption of the photo details screen, and clicking it will display the hashtag page.
--Prepare various models and migration files --Added hashtag save / update action to model --Set routing --Create a helper method --Create a hashtag action on your controller --Edit view
The code is omitted except for the necessary parts.
%rails g model hashtag
%rails g model photo_hashtag_relation
Set the columns of the table.
create_hashtags.rb
class CreateHashtags < ActiveRecord::Migration[6.0]
def change
create_table :hashtags do |t|
t.string :hashname
t.timestamps
end
add_index :hashtags, :hashname, unique: true
end
end
create_photo_hashtag_relations.rb
class CreatePhotoHashtagRelations < ActiveRecord::Migration[6.0]
def change
create_table :photo_hashtag_relations do |t|
t.references :photo, index: true, foreign_key: true
t.references :hashtag, index: true, foreign_key: true
t.timestamps
end
end
end
Set the validation and association.
hashtag.rb
class Hashtag < ApplicationRecord
validates :hashname, presence: true, length: { maximum:99}
has_many :photo_hashtag_relations
has_many :photos, through: :photo_hashtag_relations
end
photo_hashtag_relation.rb
class PhotoHashtagRelation < ApplicationRecord
belongs_to :photo
belongs_to :hashtag
with_options presence: true do
validates :photo_id
validates :hashtag_id
end
end
%rails db:migrate
Add the following code to the photo model. This will save the hashtags in the hashtags table when you post (create) or edit (update) a photo.
photo.rb
#abridgement
has_many :photo_hashtag_relations
has_many :hashtags, through: :photo_hashtag_relations
.
.
#abridgement
.
.
#Perform just before committing to DB
after_create do
photo = Photo.find_by(id: self.id)
hashtags = self.caption.scan(/[##][\w\p{Han}Ah-Gae-゚]+/)
photo.hashtags = []
hashtags.uniq.map do |hashtag|
#Hashtag is at the beginning'#'Save after removing
tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#'))
photo.hashtags << tag
end
end
before_update do
photo = Photo.find_by(id: self.id)
photo.hashtags.clear
hashtags = self.caption.scan(/[##][\w\p{Han}Ah-Gae-゚]+/)
hashtags.uniq.map do |hashtag|
tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#'))
photo.hashtags << tag
end
end
end
Define a hashtag action in the photos controller and use get to display the page for each hashtag.
The URL has the hashtag name at the end.
The value in : name
will be set later by the helper method.
For example, if the hashtag is #turtle, the URL will be .../photo/hashtag/turtle It will be.
route.rb
get '/photo/hashtag/:name', to: "photos#hashtag"
Put the following code in photos_helper.rb. If the photos_helper.rb file does not exist, create it yourself.
For helper, see https://www.sejuku.net/blog/28563 etc.
Using this helper method creates a caption with a hashtag with a link. In the code, a URL with the hashtag name at the end is created and set as the link destination when the hashtag is clicked. For the URL before the hashtag name, write the URL you wrote in route.rb earlier.
photos_helper.rb
module PhotosHelper
def render_with_hashtags(caption)
caption.gsub(/[##][\w\p{Han}Ah-Gae-゚]+/){|word| link_to word, "/photo/hashtag/#{word.delete("#")}"}.html_safe
end
end
Assign the photo associated with the hashtag to @photos and use it in the hashtag view to display it.
photos_controller.rb
def hashtag
@user = current_user
@tag = Hashtag.find_by(hashname: params[:name])
@photos = @tag.photos
end
By describing the helper method render_with_hashtags
created earlier, the caption with the hashtag with the link will be displayed on the photo details screen.
erb:show.html.erb
#abridgement
<%= render_with_hashtags(@photo.caption) %>
On the hashtag screen, the @photos
set in the hashtag action is imported and the photos associated with the hashtag are displayed one by one.
erb:hashtag.html.erb
<h2>hashtag#<%= @tag.hashname %></h2>
<ul>
<% @photos.each do |photo| %>
<li>
<%= link_to photo_path(photo.id) do %>
<%= image_tag photo.image.variant(gravity: :center, resize:"640x640^", crop:"640x640+0+0"), if photo.image.attached? %>
<% end %>
</li>
<% end %>
</ul>
The above is the method of implementing the hashtag function this time. There are a lot of codes that I don't understand, but I hope I can understand them one by one.
** I am a beginner, so if you make a mistake, please point it out m (_ _) m **
Recommended Posts