gemを使わない tag機能の実装
詳しく後日編集します
ポイント
中間テーブル
複数のテーブルを同時にcreateするモデルを使用
jsでajax通信
updateする
model
アソシエーションの記述
model/post.rb
class Post < ApplicationRecord belongs_to :user has_many :post_tag_relations, dependent: :destroy has_many :tags, through: :post_tag_relations has_one_attached :image extend ActiveHash::Associations::ActiveRecordExtensions belongs_to :status end
model/post.rb
class Tag < ApplicationRecord has_many :post_tag_relations, dependent: :destroy has_many :posts, through: :post_tag_relations //一意性のバリデーションはここに記述 validates :name, uniqueness: true end
model/post_tag_relation.rb
class PostTagRelation < ApplicationRecord belongs_to :post belongs_to :tag end
model/posts_tag.rb
ここに同時保存の内容を記述(マイグレーションファイルはいらないので、rails gで作成しないで手作業で生成する)
class PostsTag include ActiveModel::Model attr_accessor :title, :article_text, :status_id, :category_id, :image, :name, :user_id, :post_id with_options presence: true do validates :title , length: {maximum: 20} validates :article_text , length: {maximum: 300} validates :status_id , numericality: {other_than: 1, message: "は--以外から選んでください"} validates :category_id , numericality: {other_than: 1, message: "は--以外から選んでください"} validates :name validates :image end def save post = Post.create(title: title, article_text: article_text, status_id: status_id, category_id: category_id, image: image, user_id: user_id) tag = Tag.where(name: name).first_or_initialize tag.save PostTagRelation.create(post_id: post.id, tag_id: tag.id) end def update binding.pry @post = Post.where(id: post_id) post = @post.update(title: title, article_text: article_text, status_id: status_id, category_id: category_id, image: image, user_id: user_id) tag = Tag.where(name: name).first_or_initialize tag.save map = PostTagRelation.where(post_id: post_id) map.update(post_id: post_id, tag_id: tag.id) end end
コントローラー
class PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update] def index @posts = Post.all.order(created_at: :desc) end def new @post = PostsTag.new end def create @post = PostsTag.new(post_params) if @post.valid? @post.save return redirect_to root_path else render :new end end def edit @form = PostsTag.new(title: @post.title, article_text: @post.article_text, status_id: @post.status_id, category_id: @post.category_id, user_id: current_user.id, post_id: @post.id,image: @post.image) end def update @form = PostsTag.new(update_params) if @form.valid? @form.update redirect_to root_path else render :edit end end def tag_search return nil if params[:keyword] == "" tag = Tag.where(['name LIKE ?',"%#{params[:keyword]}%"] ) render json:{ keyword: tag } end private def post_params params.require(:posts_tag).permit(:title, :article_text, :status_id, :category_id, :image, :name).merge(user_id: current_user.id) end def update_params params.require(:posts_tag).permit(:title, :article_text, :status_id, :category_id, :image, :name).merge(user_id: current_user.id, post_id: params[:id]) end def set_post @post = Post.find(params[:id]) end end
PostsTagで同時保存
class PostsTag include ActiveModel::Model attr_accessor :title, :article_text, :status_id, :category_id, :image, :name, :user_id, :post_id with_options presence: true do validates :title , length: {maximum: 20} validates :article_text , length: {maximum: 300} validates :status_id , numericality: {other_than: 1, message: "は--以外から選んでください"} validates :category_id , numericality: {other_than: 1, message: "は--以外から選んでください"} validates :name validates :image end def save post = Post.create(title: title, article_text: article_text, status_id: status_id, category_id: category_id, image: image, user_id: user_id) tag = Tag.where(name: name).first_or_initialize tag.save PostTagRelation.create(post_id: post.id, tag_id: tag.id) end def update binding.pry @post = Post.where(id: post_id) post = @post.update(title: title, article_text: article_text, status_id: status_id, category_id: category_id, image: image, user_id: user_id) tag = Tag.where(name: name).first_or_initialize tag.save map = PostTagRelation.where(post_id: post_id) map.update(post_id: post_id, tag_id: tag.id) end end
view(posts/new.html)
※ edit.htmlには@formを渡してます
<%= form_with model: @post, url: posts_path, local: true do |f|%> <%= render 'shared/error_messages', model: f.object %> <div class="field"> <%= f.label :status_id, "公開/非公開 必須" %><br /> <%= f.collection_select(:status_id, Status.all, :id, :name, {class:"genre-select"}) %> </div> <div class="field"> <%= f.label :category_id, "カテゴリー 必須" %><br /> <%= f.collection_select(:category_id, Category.all, :id, :name, {class:"genre-select"}) %> </div> <div class="tag-field", id='tag-field'> <%= f.label :name, "タグ" %> <%= f.text_field :name, class:"input-tag" %> </div> <div id="search-result"> </div> <div class="field"> <%= f.label :title, "記事タイトル" %><br /> <%= f.text_field :title, id:"article_title" %> </div> <div class="field"> <%= f.label :image, "投稿画像" %><br /> <%= f.file_field :image, id:"post_image" %> </div> <div class="field"> <%= f.label :article_text, "記事テキスト" %><br /> <%= f.text_area :article_text, class: :form__text, id:"prototype_catch_copy" %> </div> <div class="actions"> <%= f.submit "保存する", class: :form__btn %> </div> <% end %>