Ruby on Railsでセクション固有のナビゲーションを実装するにはどうすればよいですか?
-
02-07-2019 - |
質問
メインの「セクション」が2つまたは3つあるRuby / Railsアプリがあります。ユーザーがそのセクションにアクセスしたときに、サブナビゲーションを表示したいと思います。 3つのセクションはすべて同じレイアウトを使用しているため、「ハードコード」することはできません。レイアウトへのナビゲーション。
これを行うには、いくつかの異なる方法が考えられます。人々が投票するのを助けるために、それらを答えとして入れます。
他のアイデアはありますか?または何に投票しますか?
解決
各セクションに独自のコントローラーがあると仮定すると、パーシャルを使用して簡単にこれを行うことができます。
投稿、ユーザー、および管理者という3つのセクションがあり、それぞれに独自のコントローラーがあるとしましょう: PostsController
、 UsersController
および AdminController
。
対応する各 views
ディレクトリで、 _subnav.html.erb
パーシャルを宣言します:
/app/views/users/_subnav.html.erb /app/views/posts/_subnav.html.erb /app/views/admin/_subnav.html.erb
これらのsubnavパーシャルのそれぞれで、そのセクションに固有のオプションを宣言します。したがって、 /users/_subnav.html.erb
には以下が含まれます。
<ul id="subnav">
<li><%= link_to 'All Users', users_path %></li>
<li><%= link_to 'New User', new_user_path %></li>
</ul>
/posts/_subnav.html.erb
には以下が含まれる場合があります:
<ul id="subnav">
<li><%= link_to 'All Posts', posts_path %></li>
<li><%= link_to 'New Post', new_post_path %></li>
</ul>
最後に、これを実行したら、レイアウトにsubnavパーシャルを含める必要があります。
<div id="header">...</div>
<%= render :partial => "subnav" %>
<div id="content"><%= yield %></div>
<div id="footer">...</div>
他のヒント
- 部分レンダリング。これはヘルパーメソッドに非常に似ていますが、レイアウトにifステートメントが含まれているか、ヘルパーに渡される可能性があります...
サブメニューの内容については、各コントローラーで宣言的な方法でアクセスできます。
class PostsController < ApplicationController
#...
protected
helper_method :menu_items
def menu_items
[
['Submenu 1', url_for(me)],
['Submenu 2', url_for(you)]
]
end
end
ビューからmenu_itemsを呼び出すたびに、特定のコントローラーを反復処理する適切なリストが作成されます。
このロジックをビューテンプレートに配置するよりも、よりクリーンなソリューションであると思います。
ApplicationController内でデフォルト(空?)menu_itemsを宣言することもできます。
警告:高度なテクニックを先に!
それらすべてをレンダリング。 CSS / Javascriptを使用して不要なものを非表示にします。CSS/ Javascriptは、さまざまな方法で簡単に初期化できます。 (Javascriptは、使用されているURL、クエリパラメータ、Cookie内の何かなどを読み取ることができます)これには、キャッシュではるかにうまくプレイできるという利点があります(3つのビューをキャッシュし、1つをキャッシュできるときにそれらすべてを同時に期限切れにしなければならない理由) ?)、およびユーザーエクスペリエンスの向上に使用できます。
たとえば、サブナビゲーションを備えた共通のタブバーインターフェースを持っているふりをしましょう。 3つのタブすべてのコンテンツ(つまり、HTMLで記述されたもの)をレンダリングし、2つのタブを非表示にすると、2つのタブ間の切り替えは簡単なJavascriptであり、サーバーにヒットしません。大勝利!ユーザーの待ち時間はありません。サーバーの負荷はありません。
別の大きな勝利が必要ですか?この手法のバリエーションを使用して、ユーザー間で99%共通する可能性があるが、ユーザーの状態を保持しているページをチートできます。たとえば、すべてのユーザーに比較的よく見られる「Hiya Bob」と言うサイトのフロントページがあるとします。共通の部分(「Hiya、Bob」)をCookieに入れます。 Cookieを読み取るJavaScriptを介して、ページのその部分を読み取らせます。 ページキャッシュで、ログインステータスに関係なくすべてのユーザーのページ全体をキャッシュします。これにより、一部のサイトのRailsスタック全体からアクセスの70%をスライスできます。
サイトが実際にNginxが静的アセットを提供している場合にRailsがスケーリングできるかどうかを気にする人は、1,000回ごとのアクセスで実行されるRubyによって時々配信される新しいHTMLページを伴う;)
http:// rpheathのナビゲーションプラグインなどを使用できます。 com / posts / 309-rails-plugin-navigation-helper
そのままではサブセクションナビゲーションを行いませんが、少し調整すれば、おそらく同様のことを行うように設定できます。
パーシャルを使用することをお勧めします。いくつかの方法があります。特定の変数を必要とするという点で少しうるさいパーシャルを作成するとき、ヘルパーメソッドも作成します。
module RenderHelper
#options: a nested array of menu names and their corresponding url
def render_submenu(menu_items=[[]])
render :partial => 'shared/submenu', :locals => {:menu_items => menu_items}
end
end
パーシャルにはmenu_itemsという名前のローカル変数があり、これを繰り返してサブメニューを作成できます。ハッシュの順序は予測できないため、ハッシュではなくネストされた配列をお勧めします。
メニューに表示する項目を決定するロジックは、それがあなたにとってより理にかなっている場合、render_submenu内にある可能性があることに注意してください。
私はほとんど同じ質問を自分でしました:アドバイスが必要:構造サブメニューのRailsビューの数おそらく最良の解決策は、パーシャルを使用することです。
これを行う別の方法があります:ネストされたレイアウト
このコードを見つけた場所を覚えていないので、元の作者に謝罪します。
libフォルダーにnested_layouts.rbというファイルを作成し、次のコードを含めます。
module NestedLayouts
def render(options = nil, &block)
if options
if options[:layout].is_a?(Array)
layouts = options.delete(:layout)
options[:layout] = layouts.pop
inner_layout = layouts.shift
options[:text] = layouts.inject(render_to_string(options.merge({:layout=>inner_layout}))) do |output,layout|
render_to_string(options.merge({:text => output, :layout => layout}))
end
end
end
super
end
end
次に、レイアウトフォルダーにさまざまなレイアウトを作成します(たとえば、「admin.rhtml」および「application.rhtml」)。
コントローラで、クラス内にこれを追加します:
include NestedLayouts
そして最後にアクションの最後にこれを行います:
def show
...
render :layout => ['admin','application']
end
配列内のレイアウトの順序は重要です。 adminレイアウトは、「yeild」が存在するアプリケーションレイアウト内にレンダリングされます。
この方法は、サイトのデザインとさまざまな要素の編成方法によっては非常にうまく機能します。たとえば、含まれるレイアウトの1つには、特定のアクションで表示する必要があるコンテンツを含む一連のdivを含めることができ、上位のレイアウトのCSSはそれらの配置を制御できます。
この問題に対するアプローチはほとんどありません。
セクションごとに異なるレイアウトを使用できます。
特定のディレクトリ内のすべてのビューに含まれるパーシャルを使用できます。
ビューまたはパーシャルのいずれかで満たされ、グローバルレイアウトで呼び出される content_for
を使用する場合があります。
個人的には、この場合は抽象化を避けるべきだと思います。