Как создать вложенные ресурсы для приложения Ruby on Rails

Вступление

Ruby on Rails - это инфраструктура веб-приложений, написанная на Ruby, которая предлагает разработчикам самоуверенный подход к разработке приложений. Работа с Rails дает разработчикам:

  • Соглашения для обработки таких вещей, как маршрутизация, данные о состоянии и управление активами.

  • Твердое основание в model-view-controller (MCV) архитектурном паттерне, который разделяет логику приложения, расположено в моделях, от представления и маршрутизации информации о приложении.

По мере того, как вы будете усложнять свои приложения на Rails, вы, вероятно, будете работать с несколькими моделями, которые представляют бизнес-логику вашего приложения и интерфейс с вашей базой данных. Добавление связанных моделей означает установление содержательных отношений между ними, которые затем влияют на то, как информация передается через контроллеры вашего приложения, а также как она собирается и представляется пользователям через представления.

В этом руководстве вы будете использовать существующее приложение Rails, которое предлагает пользователям факты об акулах. В этом приложении уже есть модель для обработки данных об акулах, но вы добавите вложенный ресурс для сообщений об отдельных акулах. Это позволит пользователям выстраивать более широкий круг мыслей и мнений об отдельных акулах.

Предпосылки

Чтобы следовать этому уроку, вам понадобится:

  • Локальный компьютер или сервер разработки под управлением Ubuntu 18.04. Ваша машина разработки должна иметь пользователя без полномочий root с правами администратора и брандмауэром, настроенным с помощью + ufw +. Инструкции о том, как это настроить, см. В нашем учебном руководстве Initial Настройка сервера с Ubuntu 18.04.

  • https://nodejs.org [Node.js] и npm, установленные на локальном компьютере или на сервере разработки. В этом руководстве используются версия Node.js и версия npm. Для получения инструкций по установке Node.js и npm в Ubuntu 18.04 следуйте инструкциям в разделе «Установка с использованием PPA» на странице https://www.digitalocean.com/community/tutorials/how-to-install-node-js-. on-ubuntu-18-04 # Установка-использование-a-ppa [Как установить Node.js в Ubuntu 18.04].

  • Ruby, rbenv и Rails, установленные на локальном компьютере или на сервере разработки, следуя шагам 1-4 в https://www.digitalocean.com/community/tutorials/how- to-install-ruby-on-rails-with-rbenv-on-ubuntu-18-04 [Как установить Ruby on Rails с помощью rbenv в Ubuntu 18.04]. В этом руководстве используются Ruby, rbenv и Rails.

  • Установлен SQLite и создано базовое информационное приложение по акулам, следуя указаниям в https://www.digitalocean.com/community/tutorials/how-to-build-a-ruby-on-rails-application[Как построить Ruby на Rails Application.

Шаг 1 - Леса вложенной модели

Наше приложение будет использовать активную запись associations для построения отношений между моделями + Shark + и + Post +: посты будут принадлежать конкретным акулам, и каждому Акула может иметь несколько постов. Наши модели + Shark + и + Post + будут, следовательно, связаны через https://guides.rubyonrails.org/association_basics.html#the-belongs-to-association [+ own_to +] и https: // направляющие. rubyonrails.org/association_basics.html#the-has-many-association [+ has_many +] ассоциации.

Первым шагом к созданию приложения таким способом будет создание модели + Post + и связанных ресурсов. Для этого мы можем использовать команду + rails generate scaffold +, которая даст нам модель, database миграция, чтобы изменить схему базы данных, контроллер, полный набор представлений для управления стандартными операциями Create, Read, Update и Delete (CRUD), а также шаблоны для частичных операций, помощников и тестов. Нам нужно будет изменить эти ресурсы, но использование команды + scaffold + сэкономит нам время и энергию, поскольку она генерирует структуру, которую мы можем использовать в качестве отправной точки.

Во-первых, убедитесь, что вы находитесь в каталоге + sharkapp + для проекта Rails, который вы создали в предварительных условиях:

cd sharkapp

Создайте ресурсы + Post + с помощью следующей команды:

rails generate scaffold Post body:text shark:references

Используя + body: text +, мы говорим Rails включить поле + body + в таблицу базы данных + posts + - таблицу, которая отображается в модель + Post +. Мы также включаем ключевое слово +: reference +, которое устанавливает связь между моделями + Shark + и + Post +. В частности, это будет гарантировать, что foreign key, представляющий каждую запись акулы в базе данных + sharks +, будет добавлен в базу данных + posts +.

После запуска команды вы увидите выходные данные, подтверждающие ресурсы, которые Rails сгенерировал для приложения. Прежде чем двигаться дальше, вы можете проверить файл миграции базы данных, чтобы посмотреть, какие отношения существуют между вашими моделями и таблицами базы данных. Используйте следующую команду, чтобы просмотреть содержимое файла, заменив отметку времени в своем собственном файле миграции на показанную здесь:

cat db/migrate/_create_posts.rb

Вы увидите следующий вывод:

Outputclass CreatePosts < ActiveRecord::Migration[5.2]
 def change
   create_table :posts do |t|
     t.text :body


     t.timestamps
   end
 end
end

Как видите, в таблице есть столбец для внешнего ключа акулы. Этот ключ будет иметь вид + _id + - в нашем случае + _id +.

Rails установил отношения между моделями и в других местах. Посмотрите на недавно сгенерированную модель + Post + с помощью следующей команды:

cat app/models/post.rb
Outputclass Post < ApplicationRecord
 belongs_to :shark
end

Ассоциация «+ own_to +» устанавливает связь между моделями, в которой один экземпляр декларирующей модели принадлежит одному экземпляру именованной модели. В случае нашего приложения это означает, что один пост принадлежит одной акуле.

В дополнение к установке этого отношения команда + rails generate scaffold + также создала маршруты и представления для сообщений, как это было сделано для наших ресурсов по акулам в https://www.digitalocean.com/community/tutorials/how-to-build. -a-ruby-on-rails-application # step-3-% E2% 80% 94-строительные леса-приложение [Шаг 3] из https://www.digitalocean.com/community/tutorials/how-to- build-a-ruby-on-rails-application [Как создать приложение Ruby on Rails].

Это полезное начало, но нам нужно будет настроить некоторую дополнительную маршрутизацию и укрепить ассоциацию Active Record для модели + Shark +, чтобы отношения между нашими моделями и маршрутами работали по желанию.

Шаг 2 - Указание вложенных маршрутов и ассоциаций для родительской модели

Rails уже установил ассоциацию + own_to + в нашей модели + Post +, благодаря ключевому слову +: reference + в команде + rails generate scaffold +, но для того, чтобы эти отношения функционировали должным образом, нам потребуется также укажите ассоциацию + has_many + в нашей модели + Shark +. Нам также нужно будет внести изменения в стандартную маршрутизацию, которую нам дал Rails, чтобы сделать почтовые ресурсы дочерними для ресурсов акул.

Чтобы добавить ассоциацию + has_many + к модели + Shark +, откройте + app / models / shark.rb + с помощью + nano + или вашего любимого редактора:

nano app/models/shark.rb

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

~ / Sharkapp / приложение / модели / shark.rb

class Shark < ApplicationRecord

 validates :name, presence: true, uniqueness: true
 validates :facts, presence: true
end

Здесь стоит подумать о том, что происходит с постами после удаления конкретной акулы. Скорее всего, мы не хотим, чтобы сообщения, связанные с удаленной акулой, сохранялись в базе данных. Чтобы гарантировать, что любые сообщения, связанные с данной акулой, будут удалены при удалении этой акулы, мы можем включить в ассоциацию опцию + зависимый +.

Добавьте следующий код в файл, чтобы гарантировать, что действие + destroy + для данной акулы удалит все связанные сообщения:

~ / Sharkapp / приложение / модели / post.rb

class Shark < ApplicationRecord
 has_many :posts
 validates :name, presence: true, uniqueness: true
 validates :facts, presence: true
end

Когда вы закончите вносить эти изменения, сохраните и закройте файл. Если вы используете + nano +, вы можете сделать это, нажав + CTRL + X +, + Y +, затем + ENTER +.

Затем откройте ваш файл + config / rout.rb +, чтобы изменить отношения между вашими находчивыми маршрутами:

nano config/routes.rb

В настоящее время файл выглядит так:

~ / Sharkapp / конфигурации / routes.rb

Rails.application.routes.draw do
 resources :posts
 resources :sharks

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

Текущий код устанавливает независимые отношения между нашими маршрутами, когда мы хотим выразить dependent Relations между акулами и связанными с ними сообщениями.

Давайте обновим наше объявление маршрута, чтобы сделать +: sharks + родителем для +: posts +. Обновите код в файле, чтобы он выглядел следующим образом:

~ / Sharkapp / конфигурации / routes.rb

Rails.application.routes.draw do
 resources
   resources

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

Сохраните и закройте файл, когда вы закончите редактирование.

После внесения этих изменений вы можете перейти к обновлению контроллера + posts +.

Шаг 3 - Обновление контроллера сообщений

Связь между нашими моделями дает нам методы, которые мы можем использовать для создания новых почтовых экземпляров, связанных с конкретными акулами. Чтобы использовать эти методы, нам нужно будет добавить их в наш пост контроллера.

Откройте файл контроллера сообщений:

nano app/controllers/posts_controller.rb

В настоящее время файл выглядит так:

~ / Sharkapp / Контроллеры / posts_controller.rb

class PostsController < ApplicationController
 before_action :set_post, only: [:show, :edit, :update, :destroy]

 # GET /posts
 # GET /posts.json
 def index
   @posts = Post.all
 end

 # GET /posts/1
 # GET /posts/1.json
 def show
 end

 # GET /posts/new
 def new
   @post = Post.new
 end

 # GET /posts/1/edit
 def edit
 end

 # POST /posts
 # POST /posts.json
 def create
   @post = Post.new(post_params)

   respond_to do |format|
     if @post.save
       format.html { redirect_to @post, notice: 'Post was successfully created.' }
       format.json { render :show, status: :created, location: @post }
     else
       format.html { render :new }
       format.json { render json: @post.errors, status: :unprocessable_entity }
     end
   end
 end

 # PATCH/PUT /posts/1
 # PATCH/PUT /posts/1.json
 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

 # DELETE /posts/1
 # DELETE /posts/1.json
 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(:body, :shark_id)
   end
end

Как и наш контроллер sharks, методы этого контроллера работают с экземплярами связанного класса + Post +. Например, метод + new + создает новый экземпляр класса + Post +, метод + index + захватывает все экземпляры класса, а метод + set_post + использует + find + и + params + `выбрать конкретный пост с помощью + id + . Однако, если мы хотим, чтобы наши почтовые экземпляры были связаны с конкретными экземплярами акул, нам нужно будет изменить этот код, поскольку класс `+ Post + в настоящее время работает как независимый объект.

Наши модификации будут использовать две вещи:

  • Методы, которые стали доступны нам, когда мы добавили в наши модели ассоциации + own_to + и + has_many +. В частности, теперь у нас есть доступ к https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many [+ build + метод] благодаря определенной нами ассоциации + has_many + в нашей модели "+ Акула ". Этот метод позволит нам создать коллекцию объектов записей, связанных с конкретным объектом акулы, используя внешний ключ ` shark_id `, который существует в нашей базе данных ` posts +`.

  • Маршруты и помощники маршрутизации, которые стали доступны, когда мы создали вложенный маршрут + posts +. Полный список примеров маршрутов, которые становятся доступными при создании вложенных отношений между ресурсами, см. В документации Rails. На данный момент нам будет достаточно знать, что для каждой конкретной акулы - скажем, + sharks / + - будет связанный маршрут для сообщений, связанных с этой акулой: + sharks // posts +. Также будут помощники маршрутизации, такие как + shark_posts_path (@shark) + и + edit_sharks_posts_path (@shark) +, которые ссылаются на эти вложенные маршруты.

В этом файле мы начнем с написания метода + get_shark +, который будет запускаться перед каждым действием в контроллере. Этот метод создаст локальную переменную экземпляра + @ shark +, найдя экземпляр акулы с помощью + shark_id +. Имея эту переменную, доступную нам в файле, можно будет связать сообщения с определенной акулой в других методах.

Над другими методами + private + внизу файла добавьте следующий метод:

~ / Sharkapp / Контроллеры / posts_controller.rb

. . .
private



 # Use callbacks to share common setup or constraints between actions.
. . .

Затем добавьте соответствующий фильтр в * top * файла перед существующим фильтром:

~ / Sharkapp / Контроллеры / posts_controller.rb

class PostsController < ApplicationController

Это обеспечит выполнение + get_shark + перед каждым действием, определенным в файле.

Затем вы можете использовать этот экземпляр + @ shark + для перезаписи метода + index +. Вместо того, чтобы захватывать все экземпляры класса + Post +, мы хотим, чтобы этот метод возвращал все экземпляры записей, связанные с конкретным экземпляром акулы.

Измените метод + index + так, чтобы он выглядел следующим образом:

~ / Sharkapp / Контроллеры / posts_controller.rb

. . .
 def index
   @posts =
 end
. . .

Метод + new + потребует аналогичной ревизии, поскольку мы хотим, чтобы новый экземпляр поста был связан с конкретной акулой. Чтобы достичь этого, мы можем использовать метод + build + вместе с нашей локальной переменной экземпляра + @ shark +.

Измените метод + new +, чтобы он выглядел так:

~ / Sharkapp / Контроллеры / posts_controller.rb

. . .
 def new
   @post =
 end
. . .

Этот метод создает объект post, связанный с конкретным экземпляром акулы из метода + get_shark +.

Далее мы рассмотрим метод, который наиболее тесно связан с + new:` + create`. Метод + create + выполняет две вещи: он создает новый экземпляр post, используя параметры, введенные пользователями в форму + new +, и, если ошибок нет, он сохраняет этот экземпляр и использует перенаправитель маршрута для перенаправления. пользователи, где они могут увидеть новый пост. В случае ошибок он снова отображает шаблон + new +.

Обновите метод + create +, чтобы он выглядел так:

~ / Sharkapp / Контроллеры / posts_controller.rb

 def create
   @post = (post_params)

       respond_to do |format|
        if @post.save
           format.html { redirect_to , notice: 'Post was successfully created.' }
           format.json { render :show, status: :created, location: @post }
        else
           format.html { render :new }
           format.json { render json: @post.errors, status: :unprocessable_entity }
     end
   end
 end

Далее рассмотрим метод + update +. Этот метод использует переменную экземпляра + @ post +, которая явно не установлена ​​в самом методе. Откуда эта переменная?

Посмотрите на фильтры в верхней части файла. Второй автоматически сгенерированный фильтр + before_action + дает ответ:

~ / Sharkapp / Контроллеры / posts_controller.rb

class PostsController < ApplicationController
 before_action :get_shark
 before_action :set_post, only: [:show, :edit, :update, :destroy]
 . . .

Метод + update + (например, + show +, + edit + и + destroy) принимает переменную` + @ post + из метода + set_post + . Этот метод, указанный в методе `+ get_shark + вместе с другими нашими методами + private +, в настоящее время выглядит следующим образом:

~ / Sharkapp / Контроллеры / posts_controller.rb

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

В соответствии с методами, которые мы использовали в другом месте файла, нам нужно изменить этот метод так, чтобы + @ post + ссылался на конкретный экземпляр в * коллекции * сообщений, связанных с конкретной акулой. Помните здесь метод + build + - благодаря ассоциациям между нашими моделями и методам (таким как + build +), которые доступны нам благодаря этим ассоциациям, каждый из наших экземпляров post является частью коллекции объектов, которые связаны с конкретной акулой. Поэтому имеет смысл, что при запросе определенного поста мы будем запрашивать коллекцию постов, связанных с определенной акулой.

Обновите + set_post +, чтобы он выглядел так:

~ / Sharkapp / Контроллеры / posts_controller.rb

. . .
private
. . .
 def set_post
   @post = (params[:id])
 end
. . .

Вместо того чтобы находить конкретный экземпляр всего класса + Post + с помощью + id +, мы вместо этого ищем соответствующий + id + в коллекции постов, связанных с конкретной акулой.

Обновив этот метод, мы можем взглянуть на методы + update и` + destroy`.

Метод + update + использует переменную экземпляра + @ post + из + set_post + и использует ее с + post_params +, который пользователь ввел в форме + edit +. В случае успеха мы хотим, чтобы Rails отправлял пользователя обратно в представление + index + сообщений, связанных с определенной акулой. В случае ошибок Rails снова отобразит шаблон + edit +.

В этом случае единственное изменение, которое нам нужно будет сделать, - это оператор + redirect_to + для обработки успешных обновлений. Обновите его, чтобы перенаправить на + shark_post_path (@shark) +, который будет перенаправлять на представление + index + выбранных сообщений акулы:

~ / Sharkapp / Контроллеры / posts_controller.rb

. . .
 def update
   respond_to do |format|
     if @post.update(post_params)
       format.html { redirect_to , 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
. . .

Далее мы внесем аналогичное изменение в метод + destroy +. Обновите метод + redirect_to + для перенаправления запросов в + shark_posts_path (@shark) + в случае успеха:

~ / Sharkapp / Контроллеры / posts_controller.rb

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

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

~ / Sharkapp / Контроллеры / posts_controller.rb

class PostsController < ApplicationController
 before_action :get_shark
 before_action :set_post, only: [:show, :edit, :update, :destroy]

 # GET /posts
 # GET /posts.json
 def index
   @posts = @shark.posts
 end

 # GET /posts/1
 # GET /posts/1.json
 def show
 end

 # GET /posts/new
 def new
   @post = @shark.posts.build
 end

 # GET /posts/1/edit
 def edit
 end

 # POST /posts
 # POST /posts.json
 def create
   @post = @shark.posts.build(post_params)

       respond_to do |format|
        if @post.save
           format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
           format.json { render :show, status: :created, location: @post }
        else
           format.html { render :new }
           format.json { render json: @post.errors, status: :unprocessable_entity }
     end
   end
 end

 # PATCH/PUT /posts/1
 # PATCH/PUT /posts/1.json
 def update
   respond_to do |format|
     if @post.update(post_params)
       format.html { redirect_to shark_post_path(@shark), 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

 # DELETE /posts/1
 # DELETE /posts/1.json
 def destroy
   @post.destroy
   respond_to do |format|
     format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
     format.json { head :no_content }
   end
 end

 private

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

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

Контроллер управляет передачей информации из шаблонов представления в базу данных и наоборот. Наш контроллер теперь отражает отношения между нашими моделями + Shark + и + Post +, в которых сообщения связаны с определенными акулами. Мы можем перейти к изменению самих шаблонов представления, в которые пользователи будут заходить и изменять информацию о постах об определенных акулах.

Шаг 4 - Изменение видов

Наши изменения шаблона представления будут включать изменение шаблонов, относящихся к публикациям, а также изменение нашего представления акул + show +, поскольку мы хотим, чтобы пользователи видели сообщения, связанные с определенными акулами.

Давайте начнем с основополагающего шаблона для наших сообщений: частичного + form +, который повторно используется в нескольких шаблонах сообщений. Откройте эту форму сейчас:

nano app/views/posts/_form.html.erb

Вместо того, чтобы передавать только модель + post + в помощник форм + form_with +, мы передадим модели + shark + и + post +, с + post +, установленным в качестве дочернего ресурса.

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

~ / Sharkapp / просмотров / сообщений / _form.html.erb

<%= form_with(model: , local: true) do |form| %>
. . .

Затем * удалите * раздел, который перечисляет + shark_id + связанной акулы, так как это не является важной информацией в представлении.

Готовая форма, с нашими правками в первой строке и без удаленного раздела + shark_id +, будет выглядеть следующим образом:

~ / Sharkapp / просмотров / сообщений / _form.html.erb

<%= form_with(model: [@shark, post], local: true) do |form| %>
 <% if post.errors.any? %>
   <div id="error_explanation">
     <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

     <ul>
     <% post.errors.full_messages.each do |message| %>
       <li><%= message %></li>
     <% end %>
     </ul>
   </div>
 <% end %>

 <div class="field">
   <%= form.label :body %>
   <%= form.text_area :body %>
 </div>

 <div class="actions">
   <%= form.submit %>
 </div>
<% end %>

Сохраните и закройте файл, когда вы закончите редактирование.

Затем откройте представление + index +, в котором будут показаны сообщения, связанные с определенной акулой:

nano app/views/posts/index.html.erb

Благодаря команде + rails generate scaffold + Rails сгенерировал лучшую часть шаблона, вместе с таблицей, которая показывает поле + body + каждого поста и связанный с ним + shark +.

Как и другой код, который мы уже модифицировали, этот шаблон обрабатывает сообщения как независимые объекты, когда мы хотим использовать связи между нашими моделями и коллекциями и вспомогательными методами, которые нам дают эти ассоциации.

В теле таблицы внесите следующие обновления:

Во-первых, обновите + post.shark + до + post.shark.name +, чтобы таблица включала поле имени ассоциированной акулы, а не определяющую информацию о самом объекте акулы:

~ / Sharkapp / приложение / просмотров / сообщений / index.html.erb

. . .
 <tbody>
   <% @posts.each do |post| %>
     <tr>
       <td><%= post.body %></td>
       <td><%= post.shark %></td>
. . .

Затем измените перенаправление + Show, чтобы направить пользователей к представлению` + show s` для связанной акулы, поскольку они, скорее всего, захотят вернуться к исходной акуле. Мы можем использовать переменную экземпляра + @ shark +, которую мы установили здесь в контроллере, поскольку Rails делает переменные экземпляра, созданные в контроллере, доступными для всех представлений. Мы также изменим текст ссылки с + Show на` + Show Shark`, чтобы пользователи лучше понимали его функцию.

Обновите эту строку следующим образом:

~ / Sharkapp / приложение / просмотров / сообщений / index.html.erb

. . .
 <tbody>
   <% @posts.each do |post| %>
     <tr>
       <td><%= post.body %></td>
       <td><%= post.shark.name %></td>
       <td><%= link_to 'Show ',  %></td>

В следующей строке мы хотим убедиться, что пользователи перенаправляют правильный вложенный путь при редактировании сообщения. Это означает, что вместо направления + posts // edit +, пользователи будут перенаправлены на + sharks // posts // edit +. Для этого мы будем использовать помощник по маршрутизации + shark_post_path + и наши модели, которые Rails будет обрабатывать как URL-адреса. Мы также обновим текст ссылки, чтобы сделать его функцию более понятной.

Обновите строку + Edit +, чтобы она выглядела следующим образом:

~ / Sharkapp / приложение / просмотров / сообщений / index.html.erb

. . .
 <tbody>
   <% @posts.each do |post| %>
     <tr>
       <td><%= post.body %></td>
       <td><%= post.shark.name %></td>
       <td><%= link_to 'Show Shark', [@shark] %></td>
       <td><%= link_to 'Edit ',  %></td>

Далее, давайте добавим аналогичное изменение в ссылку + Destroy +, обновим его функцию в строке и добавим наши ресурсы + shark + и + post +:

~ / Sharkapp / приложение / просмотров / сообщений / index.html.erb

. . .
 <tbody>
   <% @posts.each do |post| %>
     <tr>
       <td><%= post.body %></td>
       <td><%= post.shark.name %></td>
       <td><%= link_to 'Show Shark', [@shark] %></td>
       <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
       <td><%= link_to 'Destroy ', , method: :delete, data: { confirm: 'Are you sure?' } %></td>

Наконец, в нижней части формы мы захотим обновить путь + New Post +, чтобы пользователи могли переходить по соответствующему вложенному пути, когда они хотят создать новое сообщение. Обновите последнюю строку файла, чтобы использовать + new_shark_post_path (@shark) + помощник по маршрутизации:

~ / Sharkapp / приложение / просмотров / сообщений / index.html.erb

. . .
<%= link_to 'New Post',  %>

Готовый файл будет выглядеть так:

~ / Sharkapp / приложение / просмотров / сообщений / index.html.erb

<p id="notice"><%= notice %></p>

<h1>Posts</h1>

<table>
 <thead>
   <tr>
     <th>Body</th>
     <th>Shark</th>
     <th colspan="3"></th>
   </tr>
 </thead>

 <tbody>
   <% @posts.each do |post| %>
     <tr>
       <td><%= post.body %></td>
       <td><%= post.shark.name %></td>
       <td><%= link_to 'Show Shark', [@shark] %></td>
       <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
       <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>
     </tr>
   <% end %>
 </tbody>
</table>

<br>

<%= link_to 'New Post', new_shark_post_path(@shark) %>

Сохраните и закройте файл, когда вы закончите редактирование.

Другие правки, которые мы сделаем для публикации просмотров, не будут такими многочисленными, так как другие наши представления используют частичку + form +, которую мы уже редактировали. Однако мы захотим обновить ссылки + link_to + в других шаблонах записей, чтобы отразить изменения, которые мы внесли в нашу частичку + form +.

Откройте + app / views / posts / new.html.erb +:

nano app/views/posts/new.html.erb

Обновите ссылку + link_to + внизу файла, чтобы использовать помощник + shark_posts_path (@shark) +:

~ / Sharkapp / приложение / просмотров / сообщений / new.html.erb

. . .
<%= link_to 'Back',  %>

Сохраните и закройте файл, когда вы закончите вносить эти изменения.

Затем откройте шаблон + edit +:

nano app/views/posts/edit.html.erb

В дополнение к путю + Back, мы обновим` + Shows`, чтобы отразить наши вложенные ресурсы. Измените последние две строки файла, чтобы они выглядели так:

~ / Sharkapp / приложение / просмотров / сообщений / edit.html.erb

. . .
<%= link_to 'Show',  %> |
<%= link_to 'Back',  %>

Сохраните и закройте файл.

Затем откройте шаблон + show +:

nano app/views/posts/show.html.erb

Внесите следующие изменения в пути + Edit + и + Back + внизу файла:

~ / Sharkapp / приложение / просмотров / сообщений / edit.html.erb

. . .
<%= link_to 'Edit',  %> |
<%= link_to 'Back',  %>

Сохраните и закройте файл, когда вы закончите.

В качестве последнего шага мы хотим обновить представление + show + для наших акул, чтобы посты были видны для отдельных акул. Откройте этот файл сейчас:

nano app/views/sharks/show.html.erb

Наши правки будут включать добавление к форме раздела + Posts + и ссылку + Add Post + внизу файла.

Ниже + Facts + для данной акулы мы добавим новый раздел, который перебирает каждый экземпляр в коллекции сообщений, связанных с этой акулой, выводя + body + каждого сообщения.

Добавьте следующий код в раздел формы + Facts + и над перенаправлениями внизу файла:

~ / Sharkapp / приложение / просмотров / акулы / show.html.erb

. . .
<p>
 <strong>Facts:</strong>
 <%= @shark.facts %>
</p>








<%= link_to 'Edit', edit_shark_path(@shark) %> |
. . .

Затем добавьте новый редирект, чтобы позволить пользователям добавить новый пост для этой конкретной акулы:

~ / Sharkapp / приложение / просмотров / акулы / show.html.erb

. . .
<%= link_to 'Edit', edit_shark_path(@shark) %> |

<%= link_to 'Back', sharks_path %>

Сохраните и закройте файл, когда вы закончите редактирование.

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

Шаг 5 - Добавление проверок и тестирование приложения

В Step 5 [ Как создать приложение Ruby on Rails, вы добавили проверки в свою модель + Shark + обеспечить единообразие и согласованность данных, сохраняемых в базе данных + sharks +. Теперь мы предпримем аналогичный шаг, чтобы гарантировать гарантии и для базы данных + posts +.

Откройте файл, в котором определена ваша модель + Post +:

nano app/models/post.rb

Здесь мы хотим убедиться, что сообщения не являются пустыми, и что они не дублируют контент, который могли опубликовать другие пользователи. Для этого добавьте в файл следующую строку:

~ / Sharkapp / приложение / модели / post.rb

class Post < ApplicationRecord
 belongs_to :shark

end

Сохраните и закройте файл, когда вы закончите редактирование.

С этим последним изменением вы готовы запустить миграцию и протестировать приложение.

Сначала запустите ваши миграции:

rails db:migrate

Далее запустите свой сервер. Если вы работаете локально, вы можете сделать это, запустив:

rails s

Если вы работаете на сервере разработки, запустите следующую команду:

rails s --binding=

Перейдите в корневой каталог приложения по адресу + http: // localhost: 3000 + или + http: //: 3000 +.

В обязательном руководстве по проекту Rails рассказывается о добавлении и редактировании записи * Great White * shark. Если вы не добавили больше акул, целевая страница приложения будет выглядеть следующим образом:

изображение: https: //assets.digitalocean.com/articles/rails_nested_resource/shark_post_landing_2.png [целевая страница приложения Shark]

Нажмите * Показать * рядом с именем * Great White *. Это приведет вас к представлению "+ show +" для этой акулы. Вы увидите имя акулы и ее факты, а также заголовок * Posts * без содержания. Давайте добавим пост, чтобы заполнить эту часть формы.

Нажмите * Добавить сообщение * под заголовком * Сообщения *. Это приведет вас к посту + index +, где у вас будет возможность выбрать * New Post *:

изображение: https: //assets.digitalocean.com/articles/rails_nested_resource/new_post_landing.png [Представление индекса сообщения]

Благодаря механизмам аутентификации, которые вы установили в https://www.digitalocean.com/community/tutorials/how-to-build-a-ruby-on-rails-application#step-6--%E2%80% 94-добавление-аутентификация [Шаг 6] из How для создания приложения Ruby on Rails, Вас могут попросить пройти аутентификацию с использованием имени пользователя и пароля, созданных на этом шаге, в зависимости от того, создали ли вы новый сеанс или нет.

Нажмите * New Post *, чтобы перейти к шаблону + new +:

изображение: https: //assets.digitalocean.com/articles/rails_nested_resource/new_post_form.png [Новая запись]

В поле * Body * введите «Эти акулы страшны!»

изображение: https: //assets.digitalocean.com/articles/rails_nested_resource/new_shark_post_2.png [Новый пост акулы]

Нажмите на * Создать сообщение *. Вы будете перенаправлены в представление + index + для всех сообщений, принадлежащих этой акуле:

изображение: https: //assets.digitalocean.com/articles/rails_nested_resource/post_success.png [Успешная публикация]

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

В представлении + index + нажмите * New Post *. В поле * Body * новой формы попробуйте снова ввести «Эти акулы страшны!»:

изображение: https: //assets.digitalocean.com/articles/rails_nested_resource/new_shark_post_2.png [Повторить сообщение акулы]

Нажмите на * Создать сообщение *. Вы увидите следующую ошибку:

изображение: https: //assets.digitalocean.com/articles/rails_nested_resource/post_unique_error.png [Уникальная ошибка публикации]

Нажмите * Назад *, чтобы вернуться на главную страницу сообщений.

Чтобы проверить нашу другую проверку, нажмите * New Post * еще раз. Оставьте сообщение пустым и нажмите * Создать сообщение *. Вы увидите следующую ошибку:

изображение: https: //assets.digitalocean.com/articles/rails_nested_resource/post_blank_error.png [Пустая ошибка сообщения]

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

Заключение

С вашим Rails-приложением вы можете работать над такими стилями, как стилизация и разработка других интерфейсных компонентов. Если вы хотите узнать больше о маршрутизации и вложенных ресурсах, то отличное место для начала - документация Rails.

Чтобы узнать больше об интеграции интерфейсных сред с вашим приложением, взгляните на https://www.digitalocean.com/community/tutorials/how-to-set-up-a-ruby-on-rails-project-with Как настроить проект Ruby on Rails с помощью React Frontend.

Related