Изменение форматов представления в rails 3.1 (доставка мобильных html-форматов, откат на обычный html) - PullRequest
3 голосов
/ 14 января 2012

Я создаю мобильный сайт рядом с нашим обычным HTML-сайтом.Использование рельсов 3.1.Мобильный сайт доступен в поддомене m.site.com.

Я определил мобильный формат (Mime :: Type.register_alias "text / html",: mobile).

В ApplicationController у меня есть«before_filter: mobile_site_before_filter», который распознает мобильный сайт и устанавливает формат в соответствии с ним.

def mobile_site_before_filter
  if request.subdomains.first == 'm'
    original_format = request.format
    request.format = :mobile
    @mobile_site = true
    request.formats.push(original_format)
  end
end

В макетах у меня есть 'main.html.erb' и 'main.mobile.erb'.Так что с мобильными сайтами используется мобильный макет.

Теперь он вроде работает нормально.

В UserController у меня есть действие index, которое автоматически выбирает index.html.erb или index.mobile.erb.Никакого дополнительного кодирования в верхней части мобильного просмотра не требуется.Успех.

Но у меня есть много других представлений, в которых тот же шаблон можно использовать для размещения внутри мобильных макетов, но с небольшими изменениями.

Например, в MessagesController такое же представление было бы почти нормально для мобильных

In index.html.erb
Normal user info, common for mobile and html
<%= render(:partial => 'messages') %>

Рендеринг messages.html.erb, нет необходимости в messages.mobile.erb.мобильное представление может быть сделано с помощью css

<%# By default self.formats = [:html] because this is .html.erb partial, even in mobile site %>
<%= self.formats = [:mobile, :html] if @mobile_site # How to get rid of this? %>
<%= render(:partial => 'vote_form') %>
<!-- rest of page ... -->

Теперь я хочу отрисовать voice_form. [mobile | html] .erb в зависимости от сайта ...

Теперь index.html.erbчастичное было бы хорошо использовать с мобильным телефоном, если бы я мог просто выбрать один из вариантов voice_form.html.erb или voice_form.mobile.erb.Я могу выбрать использование части телефона с использованием "self.formats = [: mobile,: html] if @mobile_site" в начале index.html.erb.Но глупо писать это в начале всех шаблонов.

Таким образом, вопрос:

  • Откуда появляются представления self.formats (что устанавливает его изначально) и как я могу установить этоэто всегда [: mobile,: html] внутри мобильного сайта?Почему это не то же самое, что я установил в контроллере before_filter?Можно ли как-то установить его в контроллере?

(незначительные вопросы о бонусе)

  • Что-то не так в этом подходе?Использование в основном тех же html-представлений, а в некоторых конкретных случаях вместо этого - использование представлений mobile.erb.Почему это не работает по умолчанию в рельсах?

  • Есть ли другие способы выбора рендеринга: мобильные представления, если они найдены с откатом к обычному представлению HTML?Даже через партиалы, так что html.erb-view пытается использовать _partial.mobile.erb partials.

Ответы [ 5 ]

4 голосов
/ 09 марта 2013

Как я могу установить, что он всегда [: mobile,: html] внутри мобильного сайта? Можно ли как-то установить его в контроллере уже?

Да.

Вот простое решение, но оно немного грубое.

class ApplicationController
    ...
    def formats=(values)
        values << :html if values == [:mobile]
        super(values)
    end
    ...
end

Оказывается, в Rails (3.2.11) уже добавлен запасной вариант: html для запросов в формате: js. Вот ActionView::LookupContext#formats=

# Override formats= to expand ["*/*"] values and automatically
# add :html as fallback to :js.
def formats=(values)
  if values
    values.concat(default_formats) if values.delete "*/*"
    values << :html if values == [:js]
  end
  super(values)
end

Таким образом, вы можете самостоятельно переопределять форматы, и это, вероятно, будет не более грубым и хакерским, чем существующая реализация Rails.

Откуда появляются самоформаты (что их устанавливает изначально)

ActionController::Rendering#process_action назначает массив форматов из запроса (см. action_controller/metal/rendering.rb)

# Before processing, set the request formats in current controller formats.
def process_action(*) #:nodoc:
  self.formats = request.formats.map { |x| x.ref }
  super
end

Почему это не то же самое, что я установил в контроллере before_filter?

Это не то же самое, что вы установили в своем before_filter, потому что перед запуском фильтров before #process_action (как и следовало ожидать). Поэтому все, что вы установили, будет засорено тем, что #process_action выполняет запрос.

4 голосов
/ 29 февраля 2012

Я думаю, что нашел лучший способ сделать это.Я пытался сделать то же самое, что и вы, но потом вспомнил, что в rails 3.1 введено шаблонное наследование , что именно то, что нам нужно для того, чтобы что-то подобное заработало.Я действительно не могу отдать должное этой реализации, поскольку все это изложено в этой ссылке на Railscasts Райаном Бейтсом.

Так что в основном так и происходит.

Создать подкаталог в app/views.Я пометил мой mobile.

Вложите все шаблоны представлений, которые вы хотите переопределить, в тот же формат структуры, что и в каталоге представлений.views/posts/index.html.erb -> views/mobile/posts/index.html.erb

Создайте before_filter в вашем Application_Controller и сделайте что-нибудь для этого.

 before_filter :prep_mobile
 def is_mobile?
   request.user_agent =~ /Mobile|webOS|iPhone/
 end 
 def prep_mobile
   prepend_view_path "app/views/mobile" if is_mobile?
 end

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

3 голосов
/ 09 апреля 2014

Rails 4.1 включает в себя довольно удобную функцию:

Варианты

Позволяет использовать различные шаблоны и ответы на действия длятот же тип пантомимы (скажем, HTML).Это волшебная палочка для любого приложения Rails, которое обслуживает мобильных клиентов.Теперь вы можете иметь отдельные шаблоны для рабочего стола, планшета и телефона, используя одну и ту же логику контроллера.

Теперь вы можете сделать что-то вроде этого:

class PostController < ApplicationController
  def show
    @post = Post.find(params[:id])

    respond_to do |format|
      format.json
      format.html               # /app/views/posts/show.html.erb
      format.html.phone         # /app/views/posts/show.html+phone.erb
      format.html.tablet do
        @show_edit_link = false
      end
    end
  end
end

Youпросто нужно установить вариант в зависимости от ваших потребностей, например в before_filter:

class ApplicationController < ActionController::Base
  before_action :detect_device_variant

  private

    def detect_device_variant
      case request.user_agent
      when /iPad/i
        request.variant = :tablet
      when /iPhone/i
        request.variant = :phone
      end
    end
end

Что нового в Rails 4.1

2 голосов
/ 14 января 2012

Вы можете зарегистрировать новый формат для всего приложения в инициализаторах MIME-типов:

 Mime::Type.register_alias "text/html", :mobile

Теперь вы можете сделать что-то подобное в своих шаблонах, чтобы указать приоритет формата (см. Как сделать рендерингпартиал другого формата в Rails? ):

<% self.formats = [:mobile, :html] %>

В этом случае, если есть мобильный шаблон, он будет использоваться для рендеринга с откатом к обычному HTML-шаблону.Теперь вам нужно только определить, просматривает ли пользователь мобильный браузер и выполнить этот код условно.Или вы можете просто присвоить форматам значение в фильтре ApplicationController , чтобы был выбран правильный шаблон автоматически .

ОБНОВЛЕНИЕ:

Похоже, к этому времени не существует "легального" способа решения этой проблемы с использованием Rails.Вот нераскрытая проблема в хранилище рельсов.Там вы можете найти патч, который может решить вашу проблему, но он использует частный Rails API, поэтому он может быть нестабильным.

Также вы можете попробовать реализовать свой собственный преобразователь представлений, который, возможно, может решить проблему: http://jkfill.com/2011/03/11/implementing-a-rails-3-view-resolver/

0 голосов
/ 14 января 2012

Почему бы вам не заглянуть в Адаптивный веб-дизайн Вместо этого используйте CSS и медиа-запросы для отображения страницы.Таким образом, вашему контроллеру не нужно знать, является ли представление мобильным или нет.

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