Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Вложенные ресурсы Основы разработки на Ruby on Rails

Программа урока

  • Работа со вложенными ресурсами (limits, shallow nesting)
  • Организация контроллеров, пространство имен (namespace, scope)
  • Кастомные маршруты (member, collection)

Вложенные ресурсы

bin/rails g scaffold book title:string
bin/rails g scaffold page body:text book:references
bin/rails db:migrate

models/book.rb

class Book < ApplicationRecord
  has_many :pages
end

models/page.rb

class Page < ApplicationRecord
  belongs_to :book
end

config/routes.rb

Rails.application.routes.draw do
  root 'books#index'
  # родительский ID передаётся из пути
  # GET books/:book_id/pages
  # GET books/:book_id/pages/new
  # POST books/:book_id/pages
  resources :books, except: [:index] do
    resources :pages, only: [:index, :new, :create]
  end

  resources :books, except: [:index], shallow: true do
    resources :pages, only: [:show, :edit, :update, :destroy]
  end
end

controllers/page_controller.rb

class PagesController < ApplicationController
  before_action :set_book, only: %i[ index new create ]
  before_action :set_page, only: %i[ show edit update destroy ]

  # GET /book/1/pages
  def index
    @pages = @book.pages
  end

  # GET /pages/1
  def show
  end

  # GET book/1//pages/new
  def new
    @page = @book.pages.build
  end

  # GET /pages/1/edit
  def edit
  end

  # POST /book/1/pages
  def create
    @page = @book.pages.build(page_params)

    if @page.save
      redirect_to book_path(@book), notice: "Page was successfully created."
    else
      render :new, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /pages/1
  def update
    if @page.update(page_params)
      redirect_to book_path(@page.book), notice: "Page was successfully updated."
    else
      render :edit, status: :unprocessable_entity
    end
  end

  # DELETE /pages/1
  def destroy
    @page.destroy
    format.html { redirect_to pages_url, notice: "Page was successfully destroyed." }
  end

  private

  def set_book
    @book = Book.find(params[:book_id])
  end

  def set_page
    @page = Page.find(params[:id])
  end

  def page_params
    params.require(:page).permit(:body, :book_id)
  end
end

views/pages/show.html.erb

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

<p>
  <strong>Title:</strong>
  <%= @book.title %>
</p>

<%= link_to 'Add new page', new_book_page_path(@book) %> |
<%= link_to 'Edit', edit_book_path(@book) %> |
<%= link_to 'Back', root_path %>


<h1>Pages</h1>

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

  <tbody>
    <% @book.pages.each do |page| %>
      <tr>
        <td><%= page.body %></td>
        <td><%= link_to 'Edit', edit_page_path(page) %></td>
        <td><%= link_to 'Destroy', page, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

Организация контроллеров

controllers/web/application_controller.rb

# Контроллер модуля наследуется от базового контроллера
class Web::ApplicationController < ApplicationController
end

controllers/web/books_controller.rb

class Web::BooksController < Web::ApplicationController
  ...
end
# module Web
#   class BooksController < ApplicationController
#   ...
#   end
# end

controllers/web/pages_controller.rb

class Web::PagesController < Web::ApplicationController
  ...
end
# module Web
#   class PagesController < ApplicationController
#   ...
#   end
# end

config/routes.rb

Rails.application.routes.draw do
  # Контроллеры и вьюхи должны находиться в модуле Web
  # Задаётся только модуль, имена роутов и пути не изменяются
  scope module: :web do
    root 'books#index'
    resources :books, except: [:index] do
      resources :pages, only: [:index, :new, :create]
    end

    resources :books, except: [:index], shallow: true do
      resources :pages, only: [:show, :edit, :update, :destroy]
    end
  end
end

Создание нестандартных маршрутов

Rails.application.routes.draw do
  scope module: :web do
    root 'books#index'
    resources :books, except: [:index] do
      resources :pages, only: [:index, :new, :create]
      # добавляется метод для каждого экземпляра ресурса
      post :publish
    end
  end
end

# bin/rails routes -g publish
#       Prefix Verb   URI Pattern                       Controller#Action
# book_publish POST   /books/:book_id/publish(.:format) web/books#publish


Rails.application.routes.draw do
  scope module: :web do
    root 'books#index'
    resources :books, except: [:index] do
      # добавляется метод для каждого экземпляра ресурса
      collection do
        # Метод один для всех данных ресурсов
        post :publish
      end
    end
  end
end

# bin/rails routes -g publish
# =>        Prefix Verb   URI Pattern               Controller#Action
# => publish_books POST   /books/publish(.:format)  web/books#publish

Rails.application.routes.draw do
  scope module: :web do
    root 'books#index'
    resources :books, except: [:index] do
      # добавляется метод для каждого экземпляра ресурса
      member do
        post :publish
      end
    end
  end
end

# bin/rails routes -g publish
# =>       Prefix Verb URI Pattern                  Controller#Action
# => publish_book POST /books/:id/publish(.:format) web/books#publish

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Для полного доступа к курсу нужен базовый план

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

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Разработчик на Ruby on Rails
Профессия
c опытом
Создание веб-приложений со скоростью света
2 февраля 5 месяцев

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»
Изображение Тото

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