views:

45

answers:

2

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.

A: 

You can in this case for the format to html. By example you want always use the html in user show method

class UserController

  def show
    ..your_code..
    render :show, :format => :html
  end
end

In this case, if you request show on User controller you render all the time the html version.

If you want render JSON too by example you can made some test about your type like :

class UserController

  def show
    ..your_code..
    if [:mobile, :tablet, :html].include?(request.format)
      render :show, :format => :html
    else
      respond_with(@user)
    end
  end

end
shingara
That doesn't seem to achieve what he's looking for though. He wants to add :iphone formats by simply including an .iphone.erb template, which works, but then not have to explicitly render html every *other* request. Wouldn't this example force all responses to use the html templates?
Jeremy
I have no example of that and I don't know if it's really possible. My technique is a workaround
shingara
+1  A: 

Yes, I'm pretty sure this is the right way to do this in rails. I've defined iphone formats this way before. That's a good question about getting the format to default back to :html if a template for iphone doesn't exist. It sounds simple enough, but I think you'll have to add in a monkeypath to either rescue the missing template error, or to check if the template exists before rendering. Take a look a the type of patches shown in this question. Something like this would probably do the trick (writing this code in my browser, so more pseudo code) but throw this in an initializer

# config/initializers/default_html_view.rb
module ActionView
  class PathSet

    def find_template_with_exception_handling(original_template_path, format = nil, html_fallback = true)
      begin
        find_template_without_exception_handling(original_template_path, format, html_fallback)
      rescue ActionView::MissingTemplate => e
        # Template wasn't found
        template_path = original_template_path.sub(/^\//, '')
        # Check to see if the html version exists
        if template = load_path["#{template_path}.#{I18n.locale}.html"]
          # Return html version
          return template
        else
          # The html format doesn't exist either
          raise e
        end
      end
    end
    alias_method_chain :find_template, :exception_handling

  end
end
Jeremy
Although I'd rather not use a monkeypatch, this seems like a relatively clean solution. I read somewhere that this doesn't work for partials though. I'll try it out. Thanks.
Mark Quezada
the alias_method_chain system is always not a clean way to do. And it's can be works only with this version maybe not with futur version :(
shingara