Rails - ActiveRecord, где с несколькими условиями во вложенных маршрутах - PullRequest
0 голосов
/ 04 февраля 2019

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

У меня есть четыре модели (Пользователь, Проект, Бумага, Вопросы).

В questions_controller Я создал действие replies с цельювыбора всех ответов с конкретными project_id и paper_id.

В объекте @replies я хочу выбрать все документы и проект с project_id и paper_id, отображаемыми в URL.

http://0.0.0.0:3000/projects/3/papers/2/questions/1/replies

Я хочу выбрать все ответы с помощью project_id == 3 и paper_id == 2

. Для этого я написал следующий код:

questions_controller.rb

  def replies
    @project = Project.find(params[:project_id])
    @paper = Paper.find(params[:paper_id])
    @replies = Question.where("project_id = ? AND paper_id = ?", params[:project_id], params[:paper_id])
  end

И передано @replies в:

просмотров / вопросов / ответов.html.erb

<% @replies.each do |reply| %>
  <%= reply %>
<% end %>

Однако не работает.На самом деле мой запрос в @replies ничего не передает в моих views / questions / replies.html.erb .Я не уверен, что делаю не так.

rout.rb

Rails.application.routes.draw do
  resources :projects do
    resources :papers do
      resources :questions do
        collection do
          get 'replies'
        end
      end
    end
  end
devise_for :users
root to: 'pages#home'

project.rb

class Project < ApplicationRecord
  belongs_to :user
  has_many :papers, dependent: :destroy
  has_many :questions
end

paper.rb

class Paper < ApplicationRecord
  belongs_to :project
  has_many :questions
  has_one_attached :paper_pdf
end

question.rb

class Question < ApplicationRecord
  belongs_to :user
  belongs_to :paper
  belongs_to :project
end

user.rb

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 :projects
  has_many :questions
end

1 Ответ

0 голосов
/ 04 февраля 2019

Существуют различные проблемы в дизайне вашего приложения.

Первый - это взаимосвязь Вопросов:

class Question < ApplicationRecord
  belongs_to :user
  belongs_to :paper
  belongs_to :project
end

Я понимаю, что вы пытаетесь сделать здесь: вопрос может относиться к различным моделям: пользователь, бумагапроект.Хотя есть проблема: вопрос может относиться только к одной из этих моделей (было бы странно, если бы вопрос относился к разным объектам одновременно).Затем при создании нового вопроса, касающегося пользователя, внешние ключи для бумаги (paper_id) и проекта (project_id) будут пустыми.

Это не очень хороший дизайн.Способ сделать это - сделать модель «Вопрос» полиморфной моделью.

В случае, если Вопрос относится только к бумагам, как вы упомянули выше, тогда почему Вопрос является дочерним для других моделей, кроме Бумаги?

Вторая проблема : вы пытаетесь получитьВопросы с двумя внешними ключами:

@replies = Question.where("project_id = ? AND paper_id = ?", params[:project_id], params[:paper_id])

Как я уже описывал ранее в задаче 1, ваша модель Вопроса может иметь 3 внешних ключа (для 3 моделей, к которым она принадлежит), но вопросне может относиться к более чем одной модели одновременно.

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

Третья проблема : используйте поверхностное вложение, ваши маршруты слишком глубокие:

http://0.0.0.0:3000/projects/3/papers/2/questions/1/replies

Вам не нужно три уровня вложенности здесь,Вы, кажется, новичок, поэтому он может показаться вам не интуитивным, но проверьте мое предложение ниже

предложение :

Если я правильно прочитал ваш макет вопроса, вопросы относятся только к документам,Тогда, если вы хотите получить все вопросы, связанные с этой самой статьей, лучше создать новый метод get replies в этой самой модели, а не в модели вопроса.

Сделать его участником, а не коллекцией:

маршруты:

...
resources :papers do
  member do
     get 'replies'
  end
end
...

тогда, когда ваши маршруты заканчиваются на papers/5/replies

Вы можете вызватьприведенный ниже код в контроллере бумаги:

def replies
  @paper = Paper.find(params[:id])
  @replies = @paper.questions
end

Вы заметили, что мой код действия на самом деле не нуждается ни в одном из предыдущих идентификаторов маршрута.Я выбираю только params[:id], что относится к числу 5. Идентификатор бумажной модели.

Если у вас есть глубокие вложенные маршруты, вы понимаете, что в маршруте есть данные, которые не используются.Действительно важными данными из маршрута является последний параметр.И, возможно, предыдущий парам.

Если вам нужно убедиться, что бумага принадлежит текущему пользовательскому проекту, просто сравните текущего пользователя с идентификатором бумаги, например:

unless current_user.id == Paper.find(params[:id]).project.user.id
redirect_to root_path

И тогда все

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