お世話になります。
RubyonRailsを使用してアプリを作成しているのですが、タグ機能の実装に苦戦しているため、アドバイスをいただきたいです。
ちなみにgemは使わずに自力で実装しようと思っています。
投稿を(posts)、タグを(tags)としています。中間テーブルを(posts_tags)としています。
#サービス概要
簡易的なSNSアプリで、ユーザーが投稿し、そこに他のユーザーがコメントができるアプリです。
#実現したいこと
ユーザーがタイトル、本文を投稿する際にタグも投稿できるようにしたいです。また、投稿内容を保存し、一覧画面で投稿内容と併せて表示したいです。
ページの遷移としては、posts/new.html.erbで入力→confirm.html.erbで投稿前に内容を確認→index.html.erbで表示という流れです。
#posts/new.html.erb
posts
1 2<h3><strong>New Post</strong></h3> 3<div class="form-group"> 4 <%= form_with(model:@post, local: true, url:posts_confirm_path, class: 'container') do |f| %> 5 <div class="row"> 6 <div class="col-md-5"> 7 <h5><%= f.label :タイトル %></h5> 8 <%= f.text_area :title, autofocus: true, class: "form-control new-post-title" %> 9 </div> 10 </div> 11 <div class="row"> 12 <div class="col-md-8"> 13 <h5><%= f.label :相談内容 %></h5> 14 <%= f.text_area :text, class: "form-control" %> 15 </div> 16 </div> 17 <div class="row"> 18 <div class="col-md-3"> 19 <h5><%= f.label :タグ %></h5> 20 <%= f.text_area :name, class: "form-control" %> 21 </div> 22 </div> 23 <div class="row"> 24 <div class="col-md-1"> 25 <%= f.submit "投稿内容を確認する", class: "new-post-submit" %> 26 </div> 27 </div> 28 <% end %> 29</div>
#posts/confirm.html.erb
posts
1<h3><strong>投稿内容の確認</strong></h3> 2<div class="form-group"> 3 <div class="row"> 4 <div class="col-md-5"> 5 <h5>タイトル</h5> 6 <%= @post.title %> 7 </div> 8 </div> 9 <div class="row"> 10 <div class="col-md-8"> 11 <h5>相談内容</h5> 12 <%= @post.text %> 13 </div> 14 </div> 15 <div class="row"> 16 <div class="col-md-3"> 17 <h5>タグ</h5> 18 <%= @post.tags %> 19 </div> 20 </div> 21 <%= form_with(model: @post, local: true, url: posts_path) do |f| %> 22 <%= f.hidden_field :user_id, value: current_user.id %> 23 <%= f.hidden_field :title %> 24 <%= f.hidden_field :text %> 25 <%= f.hidden_field :name %> 26 <div class="row"> 27 <div class="col-md-1"> 28 <%= link_to "修正する", new_post_path(@post), class: 'btn btn-success' %> 29 </div> 30 </div> 31 <div class="row"> 32 <div class="col-md-1"> 33 <%= f.submit "投稿する", class: 'btn btn-danger' %> 34 </div> 35 </div> 36 <% end %> 37</div> 38 39 40 41 42
#posts_controller
class PostsController < ApplicationController def new @post = Post.new @user = current_user end def confirm @post = Post.new @post.text = params[:post][:text] @post.title = params[:post][:title] end def create @post = Post.tags.create(post_params) @post.save redirect_to posts_path end def index @posts = Post.all end def show @post = Post.find(params[:id]) @post_comment = PostComment.new @post_comments = @post.post_comments.order(created_at: :desc) end def destroy post = Post.find(params[:id]) post.destroy end private def post_params params.require(:post).permit(:user_id, :title, :text) end end
#tags_controller
class TagsController < ApplicationController def create @post = current_post @tag = @post.tags.build(tag_params) @tag.save end private def tag_params params.require(:tag).permit(:name) end end
#post.rb
class Post < ApplicationRecord belongs_to :user, optional: true has_many :post_comments, dependent: :destroy has_many :likes, dependent: :destroy has_many :post_tags, dependent: :destroy has_many :tags, through: :post_tags, dependent: :destroy validates :text, presence: true, length: { maximum: 30 } def liked_by?(user) likes.where(user_id: user.id).exists? end end
#post_tag.rb
class PostTag < ApplicationRecord belongs_to :post belongs_to :tag end
#tag.rb
class Tag < ApplicationRecord has_many :post_tags, dependent: :destroy has_many :posts, through: :post_tags, dependent: :destroy end
#routes.rb
Rails.application.routes.draw do root "homes#top" devise_for :admin_users, ActiveAdmin::Devise.config ActiveAdmin.routes(self) devise_for :users, controllers:{ sessions: "devise/sessions", registrations: "devise/registrations" } post 'posts/confirm' => 'posts#confirm' resources :posts, only:[:index, :new, :create, :edit, :update, :show, :destroy] do resource :likes, only:[:create, :destroy] resource :post_comments, only:[:create] end delete "posts/:post_id/post_comments/:post_comment_id", to: "post_comments#destroy", as: :post_comment resource :tags, only:[:create, :destroy] resources :users, only:[:show, :edit, :update] # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html post "/home/guest_sign_in" => "homes#new_guest" end
#schema.rb
# This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # # Note that this schema.rb definition is the authoritative source for your # database schema. If you need to create the application database on another # system, you should be using db:schema:load, not running all the migrations # from scratch. The latter is a flawed and unsustainable approach (the more migrations # you'll amass, the slower it'll run and the greater likelihood for issues). # # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 2020_10_22_021900) do create_table "active_admin_comments", force: :cascade do |t| t.string "namespace" t.text "body" t.string "resource_type" t.integer "resource_id" t.string "author_type" t.integer "author_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id" t.index ["namespace"], name: "index_active_admin_comments_on_namespace" t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id" end create_table "admin_users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_admin_users_on_email", unique: true t.index ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true end create_table "empathies", force: :cascade do |t| t.integer "post_id" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "likes", force: :cascade do |t| t.integer "user_id" t.integer "post_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "post_comments", force: :cascade do |t| t.integer "user_id" t.integer "post_id" t.string "text" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "posts", force: :cascade do |t| t.integer "user_id" t.string "text" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "title" end create_table "posts_tags", force: :cascade do |t| t.integer "post_id" t.integer "tag_id" end create_table "tags", force: :cascade do |t| t.integer "post_id" t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "thanks", force: :cascade do |t| t.integer "user_id" t.integer "comment_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.string "name" t.text "introduction" t.string "profile_image_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end end
#疑問点
◉投稿とタグは多対多の関係だと思うので、中間テーブルを作成(posts_tags)し、リレーションを組んだのですが、ルーティングに関してはネストさせる必要はあるのでしょうか。
◉tagのカラム(:name)をnew.html.erbに記述し、confirm.html.erbに移動すると、
:titleと:textは表示されるのですが、
<Tag::ActiveRecord_Associations_CollectionProxy:0x0000000005eda080>
と表示されてしまいます。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/10/22 14:58