Как реализовать комментарий, связанный с постом и пользователем в рельсах 5 - PullRequest
0 голосов
/ 01 октября 2019

Я реализую комментарии для постов, и они должны быть показаны в индексе постов, но комментарий не будет создан.

Я пробовал много способов получить решение, но безрезультатно, этопоследний.

Модель пользователя

  class User < ApplicationRecord
    # Include default devise modules. Others available are:
    # :confirmable, :lockable, :timeoutable, :trackable and 
    :omniauthable
    devise :database_authenticatable, :registerable,
            :recoverable, :rememberable, :validatable

    has_many :posts, dependent: :destroy
    has_many :likes, dependent: :destroy
    has_many :comments, dependent: :destroy

    before_save :downcase_email

    validates :name, presence: true, length: { maximum: 50 }, 
     allow_blank: false
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\. 
    [a-z]+\z/i.freeze
    validates :email, presence: true, length: { maximum: 255 },
                        format: { with: VALID_EMAIL_REGEX },
                        uniqueness: { case_sensitive: false }
    validates :password, presence: true, length: { minimum: 6 }, 
    allow_nil: false, allow_blank: false

    private

    # Converts email to all lower-case.
    def downcase_email
        self.email = email.downcase
    end
  end

Почтовая модель

  class Post < ApplicationRecord
    belongs_to :user
    has_many :likes, dependent: :destroy
    has_many :comments, dependent: :destroy

    default_scope -> { order(created_at: :desc) }
    mount_uploader :picture, PictureUploader
    validates :user_id, presence: true
    validates :content, presence: true, length: { maximum: 300 }
    validate :picture_size

    private

    # Validates the size of an uploaded picture.
    def picture_size
        errors.add(:picture, 'image size could not be more than 
    5MB') if picture.size > 5.megabytes
    end
  end

Комментарий модели

  class Comment < ApplicationRecord
    belongs_to :user
    belongs_to :post
    validates :user_id, presence: true
    validates :body, presence: true, length: { maximum: 300 }
    validates :post_id, presence: true

    default_scope -> { order(created_at: :desc) }
  end

Контроллер приложений

  class ApplicationController < ActionController::Base
    protect_from_forgery with: :exception

    # to avoid error message "undefined method `errors' for 
    nil:NilClass"
    before_action :instantiate_post
    before_action :instantiate_comment
    def instantiate_post
        @post = Post.new
    end

    def instantiate_comment
        @comment = Comment.new
    end
  end

Контроллер пользователей

  class UsersController < ApplicationController
    #before_action :set_user, only: %i[show edit update destroy]
    before_action :authenticate_user!, only: %i[create destroy]
    before_action :current_user, only: %i[create destroy]


    def index
        @users = User.all
    end


    def show
        @user = User.find_by(id: params[:id])
        @posts = @user.posts
        @comments = @post.comments
        @comment = current_user.comments.build(:post => @post)
    end


    def profile
        @user = User.find_by(id: params[:id])
    end

    def destroy
        @user = User.find_by(id: params[:id])
        @user.destroy
        respond_to do |format|
        format.html { redirect_to users_path, notice: 'User was 
    successfully destroyed.' }
        format.json { head :no_content }
        end
    end

    private


        # def set_user
        #   #    @user = User.find(params[:id])
        # end

        # Never trust parameters from the scary internet, only 
    allow the white list through.
        def user_params
        params.require(:user).permit(:name, :email, :password)
        end
    end

Контроллер сообщений

  class PostsController < ApplicationController
    before_action :set_post, only: %i[show edit update destroy]
    before_action :authenticate_user!, only: %i[create destroy]
    before_action :current_user, only: %i[create destroy]

    def index
        @posts = Post.all
    end

    def show; end

    def new
        @post = Post.new
    end

    def edit; end

    def create
        @post = current_user.posts.build(post_params)
        respond_to do |format|
        if @post.save
            format.html { redirect_to authenticated_root_path, 
        notice: 'Post was successfully created.' }
            format.json { render :show, status: :created, 
        location: @post }
        else
            format.html { redirect_to current_user, alert: 'post 
        not created' }
            format.json { render json: @post.errors, status: 
    :unprocessable_entity }
        end
        end
    end

    def update
        respond_to do |format|
        if @post.update(post_params)
            format.html { redirect_to @post, notice: 'Post was 
       successfully updated.' }
            format.json { render :show, status: :ok, location: 
       @post }
        else
            format.html { render :edit }
            format.json { render json: @post.errors, status: 
    :unprocessable_entity }
        end
        end
    end

    def destroy
        @post.destroy
        respond_to do |format|
        format.html { redirect_to posts_url, notice: 'Post was 
    successfully destroyed.' }
        format.json { head :no_content }
        end
    end

    private

        # Use callbacks to share common setup or constraints 
       between actions.
        def set_post
        @post = Post.find(params[:id])
        end

        # Never trust parameters from the scary internet, only 
    allow the white list through.
        def post_params
        params.require(:post).permit(:content, :picture)
        end
    end

Контроллер комментариев

  class CommentsController < ApplicationController
    before_action :set_post, only: %i[update destroy]
    before_action :set_comment, only: %i[update destroy]
    before_action :authenticate_user!, only: %i[create destroy]
    before_action :current_user, only: %i[create destroy]

    def index
        @comments = Comment.all
    end

    def new
        @comment = Comment.new
    end
    def update
        respond_to do |format|
        if @comment.update(comment_params)
            format.html { redirect_to @post, notice: 'Post was 
            successfully updated.' }
            format.json { render :show, status: :ok, location: 
        @post }
        else
            format.html { render :edit }
            format.json { render json: @post.errors, status: 
    :unprocessable_entity }
        end
        end
    end

    def destroy
        @comment.destroy
        respond_to do |format|
        format.html { redirect_to posts_url, notice: 'Post was 
    successfully destroyed.' }
        format.json { head :no_content }
        end
    end

    def create
        @comment = @post.comments.build(comment_params)
        @comment.user = current_user
        respond_to do |format|
        if @comment.save
            format.html { redirect_to @post, notice: 'Post was 
      successfully commented.' }
            format.json { render :show, status: :created, 
        location: @post }
        else
            format.html { redirect_to @post, alert: 'post not 
       commented' }
            format.json { render json: @post.errors, status: 
    :unprocessable_entity }
        end
        end
    end

    private

        def comment_params
        params.require(:comment).permit(:body, :post_id)
        end

        def set_post
        @post = Post.find(params[:post_id])
        end

        def set_comment
          @comment = @post.comments.find(params[:id])
        end
    end

просмотров / сообщений / индекса

  <div class="row">
    <p id="notice"><%= notice %></p>  
    <div class="col-md-6 form-new-user col-md-offset-3">    
        <h1>Posts</h1> 
        <%=render "form",post: @post =%> <br>
        <% @posts.each do |post| %>
        <ol class='posts'>
            <%= render post =%>

            <p>Comment on This Post</p>
            <%= render "comments/form" ,post: post=%>
            <%= render @post.comments %>
        </ol>
        <% end %>
    </div>
  </div>

просмотров / комментариев/_comment.html.erb

  <li id="comment-<%= comment.id %>">
    <%= link_to gravatar_for(comment.user, size: 30), comment.user 
    %>
    <span class="user"><%= link_to comment.user.name, comment.user 
    %></span>
    <span class="content">
        <%= comment.body %>
        <%= image_tag post.picture.url if post.picture? %>
    </span>
    <span class="timestamp">
        At: <%= (comment.created_at) %> 
        <% if current_user == post.user || current_user == 
        comment.user %>
        <%= link_to 'Edit', edit_post_path(post) %> |
        <%= link_to "delete", post, method: :delete,
                                        data: { confirm: "You 
    sure?" } %>
        <% end %>
    </span>
  </li>

views / comments / _form.html.erb

  <%= form_for [post, Comment.new] do |f| %>
    <%= f.hidden_field :post_id, value: post.id %>
    <%= f.label :body %><br>
    <%= f.text_area :body ,class:"form-control"%><br>
    <%= f.submit "Replay", class: "btn btn-primary" %>
  <% end %>

Routes.rb

  Rails.application.routes.draw do
    resources :posts do
        resources :comments
    end

    # For details on the DSL available within this file, see 
    http://guides.rubyonrails.org/routing.html

    devise_for :users, controllers: { registrations: 
   'users/registrations' }

    as :user do
        authenticated :user do
        root 'posts#index', as: :authenticated_root
        end

        unauthenticated do
        root 'devise/registrations#new', as: :unauthenticated_root
        end
    end
    resources :users, only: %i[index show destroy]
    get '/users/:id/profile', to: 'users#profile', as: 'profile'

  end

Получение отката

  Started POST "/posts/250/comments" for ::1 at 2019-10-01 
   12:46:45 +0100
   Processing by CommentsController#create as HTML
   Parameters: {"utf8"=>"✓", 
   "authenticity_token"=>"KNntIHqHzAQ9RWylAUoXa+NmEvMTL
   ZaewL2Z3wrO0ZB921j1YGjYJA6OAXVjDCQ1GNuN0Okv4tuSp4BacDXwqA=="
   ,"comment"=>{"post_id"=>"250", "body"=>"fixed?"}, 
   "commit"=>"Replay", "post_id"=>"250"}
   User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE 
   "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  
   [["id", 1], ["LIMIT", 1]]
   ↳/home/othmane/.rbenv/versions/2.6.1/lib/ruby/gems/
    2.6.0/gems/activerecord- 
    5.2.3/lib/active_record/log_subscriber.rb:98
    (0.2ms)  BEGIN
    ↳ app/controllers/comments_controller.rb:40
    (2.7ms)  ROLLBACK
    ↳ app/controllers/comments_controller.rb:40
     Redirected to http://localhost:3000/posts
    Completed 302 Found in 22ms (ActiveRecord: 3.6ms)

1 Ответ

0 голосов
/ 01 октября 2019

Сервер сообщает, что post_id - это недопустимый параметр. Мы также видим, что вы проверяете наличие post_id в любых сохраненных комментариях. Я полагаю, что комментарий не проходит эту проверку, что приводит к откату.

Чтобы разрешить post_id и тело, измените приватную часть вашего контроллера комментариев на:

private

  def comment_params
    params.require(:comment).permit(:body, :post_id)
  end

  def set_post
    @post = Post.find(params[:post_id])
  end

  def set_comment
    @comment = @post.comments.find(params[:id])
  end
end

Это должно позволить комментарию быть связанным с сообщением и пройти проверку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...