2

Rails显示嵌套层次结构视图的方式是什么?似乎是一个简单的问题,但试着忍受我,也许有人会理解(并希望能消除)我的困惑。

我的应用程序是一个简单的层次结构(为了讨论的目的而更加简化):

  • 在顶部我有一个文档索引
  • 单击一个并获取有关文档的更多详细信息的视图,包括其章节的列表(索引)
  • 单击该列表中的一章并获得一个页面,其中包含上一个和下一个链接以及页边距中的类似章节列表,当前一个突出显示。

很简单,但我的问题是 Rails 的方式是什么:

  1. 嵌套资源,这样它们就不会太深?
  2. 构建视图?

我问一些看似如此基本的问题的原因是,从第一次单击开始,我正在查看“文档”()以及其中包含document#show的章节( )。那么,视图应该建立chapters#index两者中的哪一个?

与我正在查看章节开头的下一次单击相同。那可能是chapters#showorpages#index动作。不过,可以想象,我猜它也可以(并且也许应该)由pages#show.

想法?我是不是想太多了?(可能)

4

2 回答 2

4

Routes

You can set up your routes like this to take advantage of Rails' built in nested resources:

resources :documents, :only => [:index, :show] do
  resources :chapters, :only => :show do
    resources :pages, :only => :show
  end
end

This is roughly equivalent to setting up these custom routes:

get '/documents' => 'documents#index',
    :as => 'documents'
get '/documents/:id' => 'documents#show',
    :as => 'document'
get '/documents/:document_id/chapters/:id' => 'chapters#show',
    :as => 'document_chapter'
get '/documents/:document_id/chapters/:chapter_id/pages/:id' => 'pages#show',
    :as => 'document_chapter_page'

If the URLs are a little longer and more cumbersome than you had hoped for, or you want to use custom parameters (e.g. identifying pages by number and not by ID), you can always write custom routes instead:

resources :documents, :only => [:index, :show]
get '/documents/:document_id/:id' => 'chapters#show',
    :as => 'document_chapter'
get '/documents/:document_id/:chapter_id/:page' => 'pages#show',
    :as => 'document_chapter_page'

See the routing guide for more information.

Controllers

You don't want a user to be able to visit a chapter directly, instead they should see the first page of the chapter. However, it's arguably useful for chapter URLs to work without a page number (especially if page numbers refer to the position in a document and not the position in a chapter).

You could therefore redirect from the chapters controller's show action to the first page:

class ChaptersController < ApplicationController
  def show
    chapter = Chapter.find(params[:id])
    redirect_to [chapter.document, chapter, chapter.pages.first]
  end
end

Views

There are two approaches you could take to sharing the list of chapters between different views:

  1. Use Rails' built in support for rendering a collection of model objects. In your views/documents/show.html.erb and views/chapters/show.html.erb you can include something like the following (I'm assuming each action sets a @document variable):

    <ol>
      <%= render @document.chapters %>
    </ol>
    

    Rails will look for a partial view called views/chapters/_chapter.html.erb, and render it for each of the chapters. It could look like this:

    <li><%= link_to chapter, [chapter.document, chapter] %></li>
    
  2. Share the whole list in a single partial. For example, you could add the following to views/documents/show.html.erb and views/chapters/show.html.erb:

    <%= render 'chapters/list', :chapters => @document.chapters %>
    

    And create a partial view called views/chapters/_list.html.erb:

    <ol>
      <% chapters.each do |chapter| %>
        <li><%= link_to chapter, [chapter.document, chapter] %></li>
      <% end %>
    </ol>
    

See the section on Using Partials in the Layouts and Rendering guide for more information.

于 2012-09-20T22:49:20.300 回答
0

我不止一次地读过嵌套不应该被滥用,2 层显然很好,如果有意义的话,可以设置 3 层,但是任何超过 3 层的东西,你可能需要重新考虑。

您可以使用三层嵌套,即

/docs/:id/:chapter/:page

但这样做也可能有意义

/docs/:id/:page

即直接引用文档的一页,而不关心指定章节

如果章节是数字,页面是数字,您的路由将如何区分,即

/docs/1001/1

那是 doc 1001 的第 1 页吗?还是 doc 1001 的第 1 章?

只是扮演魔鬼的拥护者,当您尝试深入嵌套时,会显示出潜在的缺点。

我认为最自然的事情是:

'/docs' => 'docs#index'  # show all docs
'/docs/:id'  => 'docs#show' # show all chapters in a doc
'/docs/:id/chapter/:chpt' => 'docs#show_chapter' # show all pages in a chapter in a doc
'/docs/:id/:page'  => 'docs#show'  # show a page in a doc

the show actions would have:
if params[:page]
  # show page specified
else
  # show all chapters
end

the order of the routes is important

我推荐这个的原因是因为书籍/页面查询语义可能比书籍/章节/页面更常见。

这些关联将是:

class Doc < ActiveRecord::Base
  has_many :pages
  has_many :chapters
end

我不会在路由中公开 end_page,我只会在任何接受 :page 的路由上添加 '?endpage=X',例如在 show 操作中:

if params[:page]
  if params[:end_page]
    # show pages :page through :end_page
  else
    # show single :page
  end
else
  # show all chapters
end
于 2012-09-20T21:10:02.033 回答