4

This question is a follow up to my previous unanswered question: ActionView::MissingTemplate: Missing template (Trying to render nonexistent :mobile format )

Since doesn't seem to be a Rails approach consensus with this, Is there any way that when accessing from a mobile device to render default :html when :mobile format is not available? (If a :mobile view is present should have priority over those who are not mobile formatted).

Community
  • 1
  • 1
Martin
  • 11,216
  • 23
  • 83
  • 140

3 Answers3

3

assume you got a mobile_request? controller instance method to detect mobile requests, then you should be able to set format fallback chains:

# application_controller.rb
before_filter :set_request_format, :set_format_fallbacks

respond_to :html, :mobile # etc

def set_request_format
  request.format = :mobile if mobile_request?
end

def set_format_fallbacks
  if request.format == :mobile
    self.formats = [:mobile, :html]
  end
end

This should work but apparently it doesn't completely. https://github.com/rails/rails/issues/3855 If you have a mobile template, the format seems to get locked and it will not find a partial with only html.

Hopefully it will be fixed some way or other. In the meantime you can put this <% controller.set_format_fallbacks %> in each template (ouch) or write your own resolver. http://jkfill.com/2011/03/11/implementing-a-rails-3-view-resolver/

also look at:

Can a mobile mime type fall back to "html" in Rails?

Changing view formats in rails 3.1 (delivering mobile html formats, fallback on normal html)

Community
  • 1
  • 1
Viktor Trón
  • 8,774
  • 4
  • 45
  • 48
0

Try this:

if File.exists?('app/views/object/mobile.file.erb')
  render :mobile
else
  render :html
end
sgrif
  • 3,702
  • 24
  • 30
  • Would there be a way to figure out the template from the controller/action instead of knowing the file name exactly? – Travis May 22 '12 at 17:33
  • Yes. params[:action] gives you the action name. Controller should be constant for the file. Path would be "app/views/controller/#{params[:action]}.extension" controller and extension should obviously be changed to the name of the controller and the file extension you're using. – sgrif May 22 '12 at 17:37
  • Well, there's a search path in rails, I just wondered if there was a way to ask Rails for what view it "would" render. I guess you can always do that. – Travis May 22 '12 at 18:14
0

I need the same thing. I researched this including this stack overflow question (and the other similar one) as well as followed the rails thread (as mentioned in this question) at https://github.com/rails/rails/issues/3855 and followed its threads/gists/gems.

Heres what I ended up doing that works with Rails 3.1 and engines. This solution allows you to place the *.mobile.haml (or *.mobile.erb etc.) in the same location as your other view files with no need for 2 hierarchies (one for regular and one for mobile).

Engine and preparation Code

in my 'base' engine I added this in config/initializers/resolvers.rb:

    module Resolvers
      # this resolver graciously shared by jdelStrother at
      # https://github.com/rails/rails/issues/3855#issuecomment-5028260
      class MobileFallbackResolver < ::ActionView::FileSystemResolver
        def find_templates(name, prefix, partial, details)
          if details[:formats] == [:mobile]
            # Add a fallback for html, for the case where, eg, 'index.html.haml' exists, but not 'index.mobile.haml'
            details = details.dup
            details[:formats] = [:mobile, :html]
          end
          super
        end
      end
    end

    ActiveSupport.on_load(:action_controller) do
      tmp_view_paths = view_paths.dup # avoid endless loop as append_view_path modifies view_paths
      tmp_view_paths.each do |path|
        append_view_path(Resolvers::MobileFallbackResolver.new(path.to_s))
      end
    end

Then, in my 'base' engine's application controller I added a mobile? method:

    def mobile?
        request.user_agent && request.user_agent.downcase =~ /mobile|iphone|webos|android|blackberry|midp|cldc/ && request.user_agent.downcase !~ /ipad/
    end

And also this before_filter:

    before_filter :set_layout

    def set_layout
      request.format = :mobile if mobile?
    end

Finally, I added this to the config/initializers/mime_types.rb:

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

Usage

Now I can have (at my application level, or in an engine):

  • app/views/layouts/application.mobile.haml
  • and in any view a .mobile.haml instead of a .html.haml file.

I can even use a specific mobile layout if I set it in any controller: layout 'mobile'

which will use app/views/layouts/mobile.html.haml (or even mobile.mobile.haml).

Mike P.
  • 198
  • 1
  • 12