Rails STI and Views

54 views Asked by At

My code:

class Document < ApplicationRecord   
    belongs_to :series

    has_one_attached :file

    validates :name, presence: true
end
class MagazineIssue < Document
    
end
class DocumentsController < ApplicationController
  before_action :set_document, only: %i[ show edit update destroy ]

  # GET /documents or /documents.json
  def index
    @documents = Document.all
  end

  # GET /documents/1 or /documents/1.json
  def show
  end

  # GET /documents/new
  def new
    @document = Document.new
  end

  # GET /documents/1/edit
  def edit
  end

  # POST /documents or /documents.json
  def create
    @document = Document.new(document_params)

    respond_to do |format|
      if @document.save
        format.html { redirect_to document_url(@document), notice: "Document was successfully created." }
        format.json { render :show, status: :created, location: @document }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @document.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /documents/1 or /documents/1.json
  def update
    respond_to do |format|
      if @document.update(document_params)
        format.html { redirect_to document_url(@document), notice: "Document was successfully updated." }
        format.json { render :show, status: :ok, location: @document }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @document.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /documents/1 or /documents/1.json
  def destroy
    @document.destroy!

    respond_to do |format|
      format.html { redirect_to documents_url, notice: "Document was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_document
      @document = Document.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def document_params
      params.require(:document).permit(:name, :month, :year)
    end
end
class MagazineIssuesController < DocumentsController
    def show
        @magazine_issue = MagazineIssue.find(params[:id])
    end
end

I also have a show.html.erb file in both views/documents and views/magazine_issues.

Basically What I want to happen is that if a type of Document, eg "MagazineIssue" has a set of views, then I want it to render those. If not, then I want any to render using the fallback set of views for "Document".

Right, now, I have a standard Document (with no type set in the DB) and a MagazineIssue type Document and both just render using the Document show view.

How can I get the MagazineIssue Document use the MagazineIssue show view?

1

There are 1 answers

0
Mike Szyndel On

There's a couple ways to answer this question!

First of all, let's get one thing out of the way. If you visit GET /documents/1/ it will call DocumentsController#show. Since your show method is defined as

# GET /documents/1 or /documents/1.json
def show
end

Rails will default to /app/views/documents/show.erb.html since this is convention-ver-configuration default.

If in turn you visited GET /magazine_issues/1 it will render magazine_issues/show template.

How can you get the result you want?

  1. Tell Rails which template to render in DocumentsController#show
def show
  render "#{@document.type.underscore.pluralize}/show" # Underscore method will convert MagazineIssue to magazine_issue
end
  1. Redirect to the correct action when loading a document. You can do it with a filter
before_action :redirect_magazine_issues, only: :show

def redirect_magazine_issues
  redirect_to magazine_issues_path(@document.id)
end
  1. Make sure that when you link from another page (like index) you link to the correct controller.