Есть ли способ добавить пользовательскую папку в «путь partials»? - PullRequest
8 голосов
/ 03 сентября 2011

У меня есть несколько моих частичных файлов в папке с именем partials, и я отображаю их в виде, используя render 'partials/name_of_my_partial', и это нормально.

В любом случае, возможно ли настроить вещи таким образом,чем я мог бы просто использовать render 'name_of_my_partial', и рельсы автоматически проверяют эту папку partials?

Прямо сейчас, у меня ошибка Missing partial.

Ответы [ 3 ]

10 голосов
/ 03 сентября 2011

В rails 3.0 это немного сложная задача, но, посмотрев на нее, я обнаружил, что в rails 3.1 они изменили работу поиска пути, сделав его намного проще. (Я не знаю, какую именно версию они изменили, хотя, возможно, это было намного раньше).

В 3.1 это относительно просто, потому что они представили способ отправки нескольких префиксов в поиск пути. Они извлекаются методом экземпляра _prefixes.

Легко добавить произвольный префикс к этому для всех контроллеров, просто переопределив его в базовом контроллере (или в модуле, который вы включаете в базовый контроллер, в зависимости от того).

Так в 3.1.x (где поиск использует несколько префиксов):

class ApplicationController
  ...
  protected
  def _prefixes
    @_prefixes_with_partials ||= super | %w(partials)
  end
end 

До этого изменения для поиска использовался один префикс, что значительно усложняло задачу. Возможно, это был не самый лучший способ, но я решил эту проблему в прошлом, спасая от пропущенных ошибок шаблона и пытаясь найти тот же путь с моим префиксом "fallback".

В 3.0.x (где поиск использует префикс с одним путем)

# in an initializer
module YourAppPaths
  extend ActiveSupport::Concern

  included do
    # override the actionview base class method to wrap its paths with your
    # custom pathset class
    def self.process_view_paths(value)
      value.is_a?(::YourAppPaths::PathSet) ?
        value.dup : ::YourAppPaths::PathSet.new(Array.wrap(value))
    end
  end

  class PathSet < ::ActionView::PathSet
    # our simple subclass of pathset simply rescues and attempts to
    # find the same path under "partials", throwing out the original prefix
    def find(path, prefix, *args)
      super
    rescue ::ActionView::MissingTemplate
      super(path, "partials", *args)
    end
  end
end

ActionView::Base.end(:include, YourAppPaths)
3 голосов
/ 17 февраля 2015

Мне не удалось найти другие ресурсы, кроме этого SO вопроса по этой теме, поэтому я пишу о своих усилиях здесь.

В Rails 3.2+ (также протестировано в 4.2), можно получить доступ и изменить lookup_context.prefixes из действия контроллера.Итак, чтобы изменить поиск шаблона и частичных префиксов для включения другого пути, вы можете сделать это:

class MyObjectsController < ApplicationController
  def show
    # WARNING: Keep reeding for issues with this approach!
    unless lookup_context.prefixes.first == "partials"
      lookup_context.prefixes.prepend "partials"
    end
  end
end

Таким образом, если в * есть шаблон show.html.erb 1013 * app / views / partials / папка, то она будет отображена.И то же самое относится к любым частям, указанным в show.html.erb .

Что здесь происходит?

Метод lookup_context возвращает объект типа ActionView::LookupContext, который является ответственным за хранение всей информации, необходимой для поиска шаблонов в ActionView.Следует отметить, что он также дает вам доступ к lookup_context.view_paths, то есть не , что запрашивается в этом вопросе, но звучит , как и должно быть.

ПРЕДУПРЕЖДЕНИЕ

Модификация массива lookup_context.prefixes кэшируется для всех будущих запросов.Поэтому, чтобы использовать его без проблем, лучше всего убедиться, что мы также удалили все префиксы, которые мы добавили.

Итак, есть ли простой способ сделать это?

Конечно.Для своих собственных проектов я создал модуль, который я могу включить в любой контроллер, которому нужна эта способность (или просто включить его в ApplicationController).Вот мой код:

# Helper methods for adding ActionView::LookupContext prefixes on including
# controllers. The lookup_context.prefixes collection is persisted on cached
# controllers, so these helpers take care to remove the passed-in prefixes
# after calling the block.
#
# @example Expected Usage:
#   around_action only: :show do |_, block|
#     prepend_lookup_context_prefixes("my_optional_name_space/my_objects", &block)
#   end
#
#   around_action only: %i[index edit update] do |_, block|
#     append_penultimate_lookup_context_prefixes("my_optional_name_space/my_objects", &block)
#   end
module PrefixesHelper
  # Prepends the passed in prefixes to the current `lookup_context.prefixes`
  # array, calls the block, then removes the prefixes.
  #
  # @param [Array<String>] prefixes
  def prepend_lookup_context_prefixes(*prefixes, &block)
    lookup_context.prefixes.prepend(*prefixes)
    block.call
    remove_lookup_context_prefixes(*prefixes, index: 0)
  end

  # Sets the penultimate (2nd-to-last) prefixes in the current
  # `lookup_context.prefixes` array, calls the block, then removes the prefixes.
  #
  # @param [Array<String>] prefixes
  def append_penultimate_lookup_context_prefixes(*prefixes, &block)
    lookup_context.prefixes.insert(-2, *prefixes)
    block.call
    remove_lookup_context_prefixes(*prefixes.reverse, index: -2)
  end

  # Removes the passed in prefixes from the current `lookup_context.prefixes`
  # array. If index is passed in, then will only remove prefixes found at the
  # specified index in the array.
  #
  # @param [Array<String>] prefixes
  # @param [Integer] index
  def remove_lookup_context_prefixes(*prefixes, index: nil)
    prefixes.each do |prefix|
      if index
        if lookup_context.prefixes[index] == prefix
          lookup_context.prefixes.delete_at(index)
        end
      else
        lookup_context.prefixes.delete(prefix)
      end
    end
  end
end

Как уже упоминалось в комментариях к этому модулю, ожидаемое использование этого модуля - вызов методов, содержащихся в нем, посредством вызова around_filter в вашем контроллере.Таким образом, модуль позаботится об удалении любых префиксов, которые он добавляет после выполнения действия контроллера.

Например:

around_filter only: :show do |_, block|
  prepend_lookup_context_prefixes("my_optional_name_space/my_objects", &block)
end

Или:

around_filter only: %i[index edit update] do |_, block|
  append_penultimate_lookup_context_prefixes("my_optional_name_space/my_objects", &block)
end

Я также включил модуль PrefixesHelper, размещенный здесь, в гем, который я использую, чтобы добавить несколько хороших расширений, подобных этим, в мои приложения на Rails.Если вы хотите использовать его, см. Здесь: https://github.com/pdobb/core_extensions

0 голосов
/ 19 января 2019

Примечание. Я отказался от этого подхода из-за странного поведения и несовместимости с гемом multi_fetch_fragments

Если вы хотите добавить префикс к своим частям для коллекции STI, я разработал следующий патч для обезьян (для Rails 3.2, Ruby 2.2 +).

конфиг / Инициализаторы / partial_renderer_prefix.rb

module ActionView
  class PartialRenderer
    def merge_prefix_into_object_path(prefix, object_path)
      # Begin monkey patch
      if @options.key?(:prefix)
        prefixes = [@options[:prefix]]
        return (prefixes << object_path).join("/")
      end

      # End monkey patch
      if prefix.include?(?/) && object_path.include?(?/)
        prefixes = []
        prefix_array = File.dirname(prefix).split('/')
        object_path_array = object_path.split('/')[0..-3] # skip model dir & partial

        prefix_array.each_with_index do |dir, index|
          break if dir == object_path_array[index]
          prefixes << dir
        end

        (prefixes << object_path).join("/")
      else
        object_path
      end
    end
  end
end

В представлении используйте его так:

<%= render @order_items, prefix: 'orders/timeline' %>

Где у вас есть app/views/orders/timeline/product_order_items/_product_order_item.html.erb и app/views/orders/timeline/subscription_order_items/_subscription_order_item.html.erb партиалы для каждой из ваших моделей STI.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...