1

リファイナリーを使用してサイトを開発しています。製油所のバックエンドで作成される 1 つの特定のページについて、独自のコントローラーとビューを使用したいと考えています。ユーザーがこのページでできることは、メニュー位置、タイトル、メタ情報などを設定することだけです。このページの URL は、他のすべてのページと同じに見える必要があります。

たとえば、メニュー構造は次のようになります。

  • メニュークス
  • メニュー1
    • メニュー2
      • 特定のページ
  • メニュークス

また、「特定のページ」の URL は「locale/menu1/menu2/specific page」のようになります。

このサイトは複数の言語で利用できるため、すべての言語に対してこれらのルートを作成する必要があります。

現在、私は次のようなルートを作成しています:

specific_page_id = 1
Refinery::I18n.frontend_locales.each do |lang|
  slugs = []
  page = Refinery::Page.find_by_path_or_id(nil, specific_page_id)
  # get slug for page in current language
  slugs << page.translations.select { |p|  p.locale == lang  }.first.slug

  # get all slugs from parrent pages
  while !page.parent_id.blank?
    page = Refinery::Page.find_by_path_or_id(nil, page.parent_id)
    slugs << page.translations.select { |p|  p.locale == lang  }.first.slug
  end

  match "/:locale/#{slugs.reverse.join("/")}"  => "controller#action", :via => :get, :constraints => { :locale => /#{lang}/ }
end

これにより、上記のようにすべての言語で指定されたページへのルートを取得しています。

しかし、問題は、ユーザーがページの名前またはメニュー内の位置を変更したときに、ルートを再度生成する必要があることです。これはあまり頻繁には行われません。

今私の質問は、実行時にこれをより動的に行うにはどうすればよいですか? 制約について少し読んだことがありますが、これが必要かどうかはわかりません。

ご協力いただきありがとうございます!

4

1 に答える 1

5

Rails 4 アプリケーション (以下の例では「ComingSoon」と呼ばれます) でデータベース モデルからルートを構築する方法を自分で考え出す必要がありました。バックエンドで編集でき、ユーザー フレンドリな名前を付けられるページが必要でした。は Page#name フィールドに格納されるため、"About Us"通常、タイトル付きのページは"about_us"名前になり、"http://localhost:3000/about_us"次のようになります。

app/models/dynamic_router.rb に新しいモデルを作成します

class DynamicRouter
  def self.load
    ComingSoon::Application.routes.draw do
      Page.all.each do |pg|
        get "/#{pg.name}", :to => "pages#show", defaults: { id: pg.id }, as: "pages_#{pg.name}"
      end
    end
  end

  def self.reload
    ComingSoon::Application.routes_reloader.reload!
  end
end

上記の重要な点は、ページの id をパラメーターの 1 つとして渡すことです。そのため、検索はまだ Page#id フィールドにあります。これは、私見ですが、使いやすいプラグインを使用したり、スラグ化された値を検索したりするよりもはるかに優れています。

次の行を config/routes.rb に追加します

ComingSoon::Application.routes.draw do

  # ...

  DynamicRouter.load
end

最後に、ページが更新されたら、ルートをリロードする必要があるため、ページ モデルに after_safe コールバックを追加します。

class Page < ActiveRecord::Base
  after_save :reload_routes

  def reload_routes
    DynamicRouter.reload
  end
end

これをさらに改良して、name 属性が変更された場合にのみルートをリロードし、パフォーマンスが問題であることが判明した場合はすべてをリロードするのではなく、既存のルートを編集するだけにする予定です (現時点ではそうではありません)。

于 2014-01-06T13:10:18.930 に答える