Reputation: 11336
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).
Upvotes: 4
Views: 1621
Reputation: 198
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).
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
Now I can have (at my application level, or in an engine):
app/views/layouts/application.mobile.haml
.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
).
Upvotes: 0
Reputation: 8884
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)
Upvotes: 3
Reputation: 3822
Try this:
if File.exists?('app/views/object/mobile.file.erb')
render :mobile
else
render :html
end
Upvotes: 0