Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm using this code (taken from here) in ApplicationController to detect iPhone, iPod Touch and iPad requests:

before_filter :detect_mobile_request, :detect_tablet_request

protected

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

def mobile_request?
  #request.subdomains.first == 'm'
  request.user_agent =~ /iPhone/ || request.user_agent =~ /iPod/
end

def detect_tablet_request
  request.format = :tablet if tablet_request?
end

def tablet_request?
  #request.subdomains.first == 't'
  request.user_agent =~ /iPad/
end

This allows me to have templates like show.html.erb, show.mobile.erb, and show.tablet.erb, which is great, but there's a problem: It seems I must define every template for each mime type. For example, requesting the "show" action from an iPhone without defining show.mobile.erb will throw an error even if show.html.erb is defined. If a mobile or tablet template is missing, I'd like to simply fall back on the html one. It doesn't seem too far fetched since "mobile" is defined as an alias to "text/html" in mime_types.rb.

So, a few questions:

  1. Am I doing this wrong? Or, is there a better way to do this?
  2. If not, can I get the mobile and tablet mime types to fall back on html if a mobile or tablet file is not present?

If it matters, I'm using Rails 3.0.1. Thanks in advance for any pointers.

EDIT: Something I forgot to mention: I'll eventually be moving to separate sub-domains (as you can see commented out in my example) so the template loading really needs to happen automatically regardless of which before_filter has run.

like image 687
markquezada Avatar asked Oct 31 '10 09:10

markquezada


People also ask

What is MIME type in HTML?

MIME types are traditionally written in all lowercase, but MIME types are actually case in-sensitive. HTML elements such as the <a> , <embed> , <link> , <object> and <style> tags will use a MIME type in the type attribute.

What are MIME media types?

MIME (Multipurpose Internet Mail Extension) media types were originally devised so that e-mails could include information other than plain text. MIME media types indicate the following things − How different parts of a message, such as text and attachments, are combined into the message.

How are MIME types assigned and listed?

MIME types are officially supposed to be assigned and listed by the Internet Assigned Numbers Authority (IANA). Many of the popular MIME types in this list (all those begin with "x-") are not assigned by the IANA and do not have official status.

What is an IANA MIME type?

A MIME type (or media type) is an identifier for file formats or format contents on the Internet. MIME stands for Multipurpose Internet Mail Extensions and all MIME types are officially maintained by the Internet Assigned Numbers Authority (IANA).


3 Answers

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

However, I struggled with this exact same problem and came up with a fairly elegant solution that met my needs perfectly. Here is my answer from the other post.

I think I've found the best way to do this. I was attempting the same thing that you were, but then I remembered that in rails 3.1 introduced template inheritance, which is exactly what we need for something like this to work. I really can't take much credit for this implementation as its all laid out there in that railscasts link by Ryan Bates.

So this is basically how it goes.

Create a subdirectory in app/views. I labeled mine mobile.

Nest all view templates you want to override in the same structure format that they would be in the views directory. views/posts/index.html.erb -> views/mobile/posts/index.html.erb

Create a before_filter in your Application_Controller and do something to this effect.

 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

Once thats done, your files will default to the mobile views if they are on a mobile device and fallback to the regular templates if a mobile one is not present.

like image 178
Justin Herrick Avatar answered Nov 15 '22 09:11

Justin Herrick


You need to do several things to wire this up, but the good news is that Rails 3 actually makes this a lot simpler than it used to be, and you can let the router do most of the hard work for you.

First off, you need to make a special route that sets up the correct mime type for you:

# In routes.rb:
resources :things, :user_agent => /iPhone/, :format => :iphone
resources :things

Now you have things accessed by an iphone user agent being marked with the iphone mime type. Rails will explode at you for a missing mime type though, so head over to config/initializers/mime_types.rb and uncomment the iphone one:

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

Now you're mime type is ready for use, but your controller probably doesn't yet know about your new mime type, and as such you'll see 406 responses. To solve this, just add a mime-type allowance at the top of the controller, using repsond_to:

class ThingsController < ApplicationController
  respond_to :html, :xml, :iphone

Now you can just use respond_to blocks or respond_with as normal.

There currently is no API to easily perform the automatic fallback other than the monkeypatch or non-mime template approaches already discussed. You might be able to wire up an override more cleanly using a specialized responder class.

Other recommended reading includes:

https://github.com/plataformatec/responders

http://www.railsdispatch.com/posts/rails-3-makes-life-better

like image 40
raggi Avatar answered Nov 15 '22 10:11

raggi


Trying removing the .html from the .html.erb and both iPhone and browser will fallback to the common file.

like image 21
Joe Avatar answered Nov 15 '22 10:11

Joe