Раскладки рельсов за действие?

165

Я использую другой макет для некоторых действий (в основном для нового действия в большинстве контроллеров).

Мне интересно, каким будет лучший способ указать макет? (Я использую 3 или более разных макетов в одном контроллере)

Я не люблю использовать

render: layout => 'name'

Мне понравилось делать

макет 'name',: only => [: new]

Но я не могу использовать это, чтобы указать 2 или более разных макетов.

Например:

Когда я вызываю компоновку 2 раза в одном и том же контроллере с разными именами компоновки и разными параметрами, первый игнорируется - эти действия не отображаются в указанной компоновке.

Примечание: я использую Rails 2.

mrbrdo
источник
1
Документация по Rails Guides: guides.rubyonrails.org/…
Кевин
1
Хорошая точка зрения. Документация по Rails 2: guides.rubyonrails.org/v2.3.11/…
Кевин,
2
(Также я опубликовал руководство, чтобы помочь будущим читателям. Я не сомневаюсь, что ваша проблема была решена давным-давно ;-)
Кевин

Ответы:

297

Вы можете использовать метод для установки макета.

class MyController < ApplicationController
  layout :resolve_layout

  # ...

  private

  def resolve_layout
    case action_name
    when "new", "create"
      "some_layout"
    when "index"
      "other_layout"
    else
      "application"
    end
  end
end
Август Лиллеас
источник
22
Хорошо, спасибо. И в случае, если кто-то хочет сделать более простые вещи с помощью одной строки, возможно следующее. Его легко читать и поместить в верхней части контроллера. ---layout Proc.new{ ['index', 'new', 'create'].include?(action_name) ? 'some_layout' : 'other_layout' }
Холли
1
Повлияет ли это на производительность приложения, если различные макеты используют, скажем, несколько разных файлов CSS и JS соответственно?
Noz
15
-1: слишком сложный Комментарий ниже ( stackoverflow.com/a/21203783/285154 ) является лучшим вариантом.
dimitarvp
Спасибо! Это все еще проблема в Rails 4.2, возможно, только если вы используете унаследованные контроллеры на многих уровнях. Я использовал метод раньше, но не думал о тестировании, когда у меня возникла проблема, еще раз спасибо.
244an
@dimitko нет, это не так, я уже упоминал это решение в самом вопросе. Это не работает, если вы хотите использовать 3 или более разных макетов (как в моем случае).
mrbrdo
201

Если вы выбираете только между двумя макетами, вы можете использовать :only:

class ProductsController < ApplicationController
   layout "admin", only: [:new, :edit]
end

или

class ProductsController < ApplicationController
   layout "application", only: [:index]
end
axeltaglia
источник
2
Проблема в том, что вы не можете получить доступ к таким объектам, как current_user, для условного определения макета
Эндрю К
@AndrewK Динамический выбор макета не является частью задаваемого вопроса.
Ник
11
Если кто-то из вас прочитает вопрос, вы узнаете, что это неправильный ответ, поскольку я уже описал это решение в самом вопросе, а также почему оно не работает в моем случае (3 или более макетов).
mrbrdo
2
Как сказал мрбрдо, это не ответ. Его вопрос конкретно указывает (I am using 3 or more different layouts in the same controller). Этот ответ позволяет макет и не макет, не разные макеты.
Майкл,
49

Вы можете указать макет для отдельного действия, используя response_to :

  def foo
    @model = Bar.first
    respond_to do |format|
      format.html {render :layout => 'application'}
    end
  end
Гэвин Террилл
источник
Для меня это более гибкий ответ. СУШКИ с применением layout "[...]" to the controller class only allows one statement effectively. If you have more than two layouts to deal with (say, admin, generic_app, tailored_app), you will experience Render и / или Redirect были вызваны несколько раз в ошибках этого действия; и у вас нет выбора, кроме как использовать это предложение.
Джером
1
Этот ответ самый лучший, простой и аккуратный, в отличие от использования методов с инструкциями switch или if внутри.
Кев
также он может указывать файл erb и макет как: format.html { render 'custom_index', layout: 'application' } одинаково.
thatway_3
12

Вы также можете указать макет для действия с помощью рендера:

def foo
  render layout: "application"
end
yottanami
источник
7

Различные способы указания макета под контроллером:

  1. В следующем коде макет application_1 вызывается по индексу и показывается действие контроллера Users, а макет приложения (макет по умолчанию) вызывается для других действий.

    class UsersController < ApplicationController
      layout "application_1", only: [:index, :show]
    end
  2. В следующем коде макет application_1 вызывается для всех действий контроллера Users.

    class UsersController < ApplicationController
       layout "application_1"
    end
  3. В следующем коде макет application_1 вызывается только для тестового действия контроллеров пользователей, а для всех остальных действий вызывается макет приложения (по умолчанию).

        class UsersController < ApplicationController
          def test
            render layout: "application_1"
          end
        end
puneet18
источник
5

Точность:

Не совсем, но работающий способ СУХОГО - это то, что вы видите выше, но с точностью: макет должен быть после ваших переменных для работы ("@some"). Так как :

def your_action
   @some = foo
   render layout: "your_layout"
end

И нет :

def your_action
   render layout: "your_layout"
   @some = foo
   @foo = some
end

Если вы делаете before_action ... это тоже не сработает.

Надеюсь, поможет.

Gregdebrick
источник