2010-10-31 23 views
22

Tôi đang sử dụng mã này (lấy từ here) trong ApplicationController để phát hiện iPhone, iPod Touch và iPad yêu cầu:Loại mime di động có thể quay lại "html" trong Rails không?

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 

này cho phép tôi để có mẫu như show.html.erb, show.mobile.erb và show.tablet.erb, điều này thật tuyệt, nhưng có vấn đề: Có vẻ như tôi phải định nghĩa mọi mẫu cho mỗi loại mime. Ví dụ: yêu cầu hành động "hiển thị" từ iPhone mà không xác định show.mobile.erb sẽ ném một lỗi ngay cả khi show.html.erb được xác định. Nếu thiếu mẫu thiết bị di động hoặc máy tính bảng, tôi chỉ muốn quay lại mẫu html. Nó không có vẻ quá xa vời vì "điện thoại di động" được định nghĩa là một bí danh để "văn bản/html" trong mime_types.rb.

Vì vậy, một số câu hỏi:

  1. Tôi có làm sai điều này? Hoặc là có một cách tốt hơn để làm điều này?
  2. Nếu không, tôi có thể nhận loại điện thoại di động và máy tính bảng để quay lại trên html nếu tệp trên điện thoại di động hoặc máy tính bảng không có mặt không?

Nếu có vấn đề, tôi đang sử dụng Rails 3.0.1. Cảm ơn trước cho bất kỳ con trỏ.

EDIT: Điều tôi quên đề cập: Cuối cùng tôi sẽ chuyển sang các tên miền phụ riêng biệt (như bạn có thể thấy nhận xét trong ví dụ của tôi) để tải mẫu thực sự cần tự động bất kể before_filter có chạy.

+0

Đây là một cuộc thảo luận tại đường ray để tham khảo: https://github.com/rails/rails/issues/3855 –

Trả lời

17

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

Tuy nhiên, tôi phải vật lộn với cùng một vấn đề này chính xác và đã đưa ra một giải pháp khá thanh lịch mà đáp ứng nhu cầu của tôi một cách hoàn hảo. Đây là câu trả lời của tôi từ bài viết khác.

Tôi nghĩ tôi đã tìm ra cách tốt nhất để thực hiện việc này. Tôi đã cố gắng cùng một điều mà bạn đã, nhưng sau đó tôi nhớ rằng trong đường ray 3.1 giới thiệu template inheritance, đó là chính xác những gì chúng ta cần cho một cái gì đó như thế này để làm việc. Tôi thực sự không thể mất nhiều tín dụng cho việc thực hiện này vì tất cả được đặt ra ở đó trong liên kết railscasts bởi Ryan Bates.

Vì vậy, đây là cơ bản như thế nào nó đi.

Tạo thư mục con trong app/views. Tôi đã gắn nhãn của tôi là mobile.

Canh tất cả các mẫu xem mà bạn muốn ghi đè ở cùng định dạng cấu trúc mà chúng sẽ nằm trong thư mục lượt xem. views/posts/index.html.erb -> views/mobile/posts/index.html.erb

Tạo before_filter trong số Application_Controller và làm điều gì đó cho hiệu ứng này.

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 

Sau khi thực hiện xong, tệp của bạn sẽ mặc định ở chế độ xem trên thiết bị di động nếu chúng không có mặt.

+3

Câu hỏi của tôi, được hỏi cách đây hơn một năm, là một có thể trùng lặp của một câu hỏi đã được hỏi 1 tháng trước? Ngoài ra, lưu ý trong câu hỏi ban đầu Rails 3.0.1 là phiên bản hiện tại. Mặc dù vậy, điều này giống như một giải pháp khả thi cho Rails 3.1. – markquezada

+1

Ah, tôi đã không kiểm tra ngày đủ gần, nhưng nhiều hơn hoặc ít hơn tôi có nghĩa là bình luận của tôi là một bản sao của những gì tôi đã nói về một câu hỏi khác. Xin lỗi về sự nhầm lẫn. –

0

Bạn có thể trong trường hợp này để định dạng thành html. Ví dụ: bạn muốn luôn sử dụng html trong phương thức hiển thị của người dùng

class UserController 

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

Trong trường hợp này, nếu bạn yêu cầu hiển thị trên bộ điều khiển người dùng, bạn sẽ hiển thị tất cả các phiên bản html.

Nếu bạn muốn làm cho JSON quá bằng ví dụ bạn có thể thực hiện một số thử nghiệm về loại hình như:

class UserController 

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

end 
+0

Điều đó dường như không đạt được những gì anh ấy đang tìm kiếm. Anh ta muốn thêm: các định dạng iphone bằng cách đơn giản bao gồm một mẫu .iphone.erb, hoạt động, nhưng sau đó không phải hiển thị html một cách rõ ràng mọi yêu cầu * khác *. Chẳng phải ví dụ này sẽ buộc tất cả các phản hồi để sử dụng các mẫu html? – Jeremy

+0

Tôi không có ví dụ về điều đó và tôi không biết nếu nó thực sự có thể. Kỹ thuật của tôi là một cách giải quyết – shingara

1

Vâng, tôi khá chắc chắn đây là đúng cách để làm điều này trong đường ray. Tôi đã định nghĩa các định dạng iphone theo cách này trước đây. Đó là một câu hỏi hay về việc định dạng mặc định quay lại: html nếu một mẫu cho iphone không tồn tại. Nghe có vẻ đơn giản, nhưng tôi nghĩ bạn sẽ phải thêm vào một đường dẫn để giải cứu lỗi mẫu bị thiếu hoặc để kiểm tra xem mẫu có tồn tại trước khi hiển thị hay không. Hãy xem một loại bản vá được hiển thị trong this question. Một cái gì đó như thế này có lẽ sẽ làm các trick (viết mã này trong trình duyệt của mình, mã nên giả hơn) nhưng ném này trong một 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 
+0

Mặc dù tôi không muốn sử dụng một monkeypatch, điều này có vẻ giống như một giải pháp tương đối sạch. Tôi đọc một nơi nào đó rằng điều này không làm việc cho partials mặc dù. Tôi se thử no. Cảm ơn. – markquezada

+0

hệ thống alias_method_chain luôn không phải là cách làm sạch.Và nó có thể chỉ hoạt động với phiên bản này có thể không có phiên bản tương lai: ( – shingara

+0

Vâng, điều này không được đảm bảo để làm việc cho các phiên bản sau này, mặc dù tôi lấy nó từ một ví dụ 2.x, và nó vẫn có vẻ áp dụng trong 3.0. Đây là tài liệu có liên quan [ActionView :: PathSet # find_template] (http://apidock.com/rails/ActionView/PathSet/find_template) có vẻ như các đường ray hiện chỉ mặc định là: html nếu nó đang cố gắng sử dụng định dạng js, thay vì bất kỳ định dạng nào khác, do đó cần có một miếng vá khỉ. – Jeremy

3

Đang cố gắng loại bỏ các .html từ .html.erb và cả iPhone và trình duyệt sẽ dự phòng cho tệp chung.

+1

Xin chào Joe, cảm ơn câu trả lời. Điều này hoạt động, nhưng có vẻ hơi lạ vì tệp .erb mới sẽ là mặc định cho * mọi loại * mime không chỉ là mẫu di động (html aliased). Ngoài ra, tôi nghĩ rằng tôi đọc ở đâu đó rằng điều này đã không được chấp nhận trong Rails 3? – markquezada

2

Cách tôi xử lý việc này chỉ đơn giản là skip_before_filter trên những yêu cầu mà tôi biết tôi muốn hiển thị chế độ xem HTML cho. Rõ ràng, điều đó sẽ làm việc với partials.

Nếu trang web của bạn có rất nhiều quan điểm di động và/hoặc máy tính bảng, bạn có thể muốn thiết lập bộ lọc của bạn trong ApplicationController và bỏ qua chúng trong các lớp con, nhưng nếu chỉ có một vài hành động có tầm nhìn di động cụ thể, bạn nên chỉ cuộc gọi bộ lọc trước trên các hành động/bộ điều khiển bạn muốn.

+0

Đó thực sự là một cách tiếp cận thực sự thú vị (và hữu ích!). Nó chắc chắn sẽ hoạt động trong nhiều trường hợp, nhưng đối với trường hợp cụ thể của tôi (như bạn có thể thấy trong phần nhận xét của ví dụ của tôi), cuối cùng tôi sẽ chuyển sang các miền phụ cho từng loại thiết bị để tôi có thể sử dụng bộ nhớ đệm chiến lược. Điều này có nghĩa là tôi thực sự cần mã tải mẫu không phụ thuộc vào bộ lọc trước. Cảm ơn vì đầu vào của bạn. – markquezada

2

Nếu hệ điều hành của bạn có các liên kết tượng trưng, ​​bạn có thể sử dụng chúng.

$ ln -s show.html.erb show.mobile.erb 
4

Bạn cần phải làm một vài điều để dây này lên, nhưng những tin tức tốt lành là Rails 3 thực sự làm này rất nhiều đơn giản hơn trước kia nữa, và bạn có thể cho các bộ định tuyến làm hầu hết các công việc khó khăn cho bạn.

tắt Trước tiên, bạn cần phải thực hiện một lộ trình đặc biệt mà thiết lập các loại mime chính xác cho bạn:

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

Bây giờ bạn có những thứ truy cập bởi một user agent iphone được đánh dấu bằng loại iphone kịch câm. Rails sẽ nổ vào bạn cho một loại mime thiếu mặc dù, vì vậy đi qua để config/initializers/mime_types.rb và bỏ iphone một:

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

Bây giờ bạn đã loại mime đã sẵn sàng để sử dụng, nhưng điều khiển của bạn có thể chưa biết về loại mime mới của bạn, và như vậy bạn sẽ thấy 406 câu trả lời. Để giải quyết việc này, chỉ cần thêm một trợ cấp mime-type ở trên cùng của bộ điều khiển, sử dụng repsond_to:

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

Bây giờ bạn chỉ có thể sử dụng các khối respond_to hoặc respond_with như bình thường.

Hiện tại không có API để dễ dàng thực hiện dự phòng tự động khác với các phương pháp tiếp cận mẫu monkeypatch hoặc non-mime đã được thảo luận. Bạn có thể có dây để ghi đè lên một cách rõ ràng hơn bằng cách sử dụng lớp trả lời chuyên dụng.

đề nghị đọc khác bao gồm:

https://github.com/plataformatec/responders

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

+0

Câu trả lời của bạn phù hợp hơn cho câu hỏi: "Làm cách nào để thêm loại mime di động vào đường ray?" (Bạn sẽ nhận thấy rằng câu hỏi cho thấy rằng tôi đã làm điều này.) Bạn không giải quyết các câu hỏi thực sự là làm thế nào để rơi trở lại loại mime html nếu một mẫu điện thoại di động không tồn tại. Cách tiếp cận tốt hơn là sử dụng mẫu thừa kế thay vì loại mime tùy chỉnh như được mô tả trong câu trả lời của Justin Herrick. – markquezada

3

Tôi đã thêm một câu trả lời mới cho phiên bản 3.2.X. Câu trả lời này hợp lệ cho < ~ 3.0.1.

Tôi đã đến câu hỏi này trong khi tìm cách có thể có nhiều dự phòng trên chế độ xem. Ví dụ, nếu sản phẩm của tôi có thể có màu trắng-nhãn và lần lượt nếu đối tác trắng-nhãn của tôi là có thể bán tài trợ, sau đó tôi cần một thác quan điểm trên mỗi trang như thế này:

  • Nhà tài trợ Xem: .sponsor_html
  • Partner Xem: .partner_html
  • mặc định Xem: .html

Câu trả lời của Joe, chỉ loại bỏ .html công trình (rất tốt) nếu bạn chỉ có một mức độ cao hơn mặc định, nhưng trong ứng dụng thực tế Tôi cần 5 cấp độ trong một số trường hợp.

Dường như không có cách nào để thực hiện đoạn ngắn này của một số con khỉ vá trong cùng một mạch như Jeremy.

Lõi cốt lõi tạo ra một số giả định khá rộng mà bạn chỉ muốn một định dạng và nó ánh xạ tới một phần mở rộng (với phần mở rộng mặc định là KHÔNG).

Tôi cần một giải pháp duy nhất có thể hoạt động cho tất cả các yếu tố chế độ xem - bố cục, mẫu và partials.

Cố gắng thực hiện điều này nhiều hơn theo các quy ước của tôi, tôi đã đưa ra những điều sau đây.

# app/config/initializers/resolver.rb 
module ActionView 
    class Base 
    cattr_accessor :extension_fallbacks 
    @@extension_fallbacks = nil 
    end 

    class PathResolver < Resolver 
    private 
     def find_templates_with_fallbacks(name, prefix, partial, details) 
     fallbacks = Rails.application.config.action_view.extension_fallbacks 
     format = details[:formats].first 

     unless fallbacks && fallbacks[format] 
      return find_templates_without_fallbacks(name, prefix, partial, details) 
     end 

     deets = details.dup 
     deets[:formats] = fallbacks[format] 

     path = build_path(name, prefix, partial, deets) 
     query(path, EXTENSION_ORDER.map {|ext| deets[ext] }, details[:formats]) 
     end 
     alias_method_chain :find_templates, :fallbacks 
    end 
end 

# config/application.rb 
config.after_initialize do 
config.action_view.extension_fallbacks = { 
    html: [:sponsor_html, :partner_html, :html], 
    mobile: [:sponsor_mobile, :partner_mobile, :sponsor_html, :partner_html, :html] 
} 

# config/initializers/mime_types.rb 
register_alias 'text/html', :mobile 

# app/controllers/examples_controller.rb 
class ExamplesController 
    respond_to :html, :mobile 

    def index 
    @examples = Examples.all 

    respond_with(@examples) 
    end 
end 

Lưu ý: Tôi đã thấy các nhận xét quanh alias_method_chain và ban đầu đã thực hiện cuộc gọi đến siêu ở vị trí thích hợp. Điều này thực sự được gọi là ActionView :: Resolver # find_templates (điều này làm tăng ngoại lệ NotImplemented) thay vì ActionView :: PathResolver # find_templates trong một số trường hợp. Tôi không đủ kiên nhẫn để theo dõi lý do tại sao. Tôi nghi ngờ nó vì là một phương pháp riêng.

Ngoài ra, Rails, tại thời điểm này, không báo cáo alias_method_chain là không được chấp nhận. Chỉ là bài đó.

Tôi không như câu trả lời này vì nó liên quan đến một số triển khai rất dễ vỡ xung quanh cuộc gọi find_templates đó. Đặc biệt giả định rằng bạn chỉ có MỘT định dạng, nhưng đây là một giả định được thực hiện trên tất cả các vị trí trong yêu cầu mẫu.

Sau 4 ngày cố gắng giải quyết vấn đề này và chải kỹ toàn bộ yêu cầu mẫu, ngăn xếp tốt nhất của nó có thể xuất hiện.

+0

Điều này làm việc trong một ứng dụng đường ray sạch, nhưng trong ứng dụng đầy đủ của tôi nó không cho một vài lý do. Vì vậy, câu trả lời này chưa hoàn thành ... Sớm hơn. – Simon

+0

Chỉnh sửa mã được đặt. Nó sẽ hoạt động như mong đợi ngay bây giờ. Lưu ý rằng bạn không cần thêm tất cả các phần mở rộng vào dưới dạng mime_types, chỉ là định dạng. – Simon

+0

Rất đẹp, sử dụng nó, cảm ơn! – dolzenko

1

Dưới đây là một ví dụ về cách để làm điều đó, lấy cảm hứng bởi mã Simon, nhưng ngắn hơn một chút và một chút ít hacky:

# application_controller.rb 
class ApplicationController < ActionController::Base 
    # ... 

    # When the format is iphone have it also fallback on :html 
    append_view_path ExtensionFallbackResolver.new("app/views", :iphone => :html) 

    # ... 
end 

và đâu đó trong một autoload_path hoặc yêu cầu một cách rõ ràng:

# extension_fallback_resolver.rb 
class ExtensionFallbackResolver < ActionView::FileSystemResolver 

    attr_reader :format_fallbacks 

    # In controller do append_view_path ExtensionFallbackResolver.new("app/views", :iphone => :html) 
    def initialize(path, format_fallbacks = {}) 
    super(path) 
    @format_fallbacks = format_fallbacks 
    end 

    private 

    def find_templates(name, prefix, partial, details) 
     fallback_details = details.dup 
     fallback_details[:formats] = Array(format_fallbacks[details[:formats].first]) 

     path = build_path(name, prefix, partial, details) 
     query(path, EXTENSION_ORDER.map { |ext| fallback_details[ext] }, details[:formats]) 
    end 

end 

Ở trên vẫn là một hack vì nó đang sử dụng một API riêng, nhưng có thể ít mong manh như đề xuất ban đầu của Simon.

Lưu ý rằng bạn cần phải chăm sóc bố cục một cách riêng biệt. Bạn sẽ cần phải triển khai một phương thức chọn bố cục dựa trên tác nhân người dùng hoặc một cái gì đó tương tự. Việc sẽ chỉ chăm sóc dự phòng cho các mẫu thông thường.

+1

'hằng số không được khởi tạo MyApplication :: Application :: ExtensionFallbackResolver' avec Rails 3.1 – Dorian

-2

tôi giải quyết vấn đề này bằng cách sử dụng before_filter này trong ApplicationController tôi:

def set_mobile_format 
    request.formats.unshift(Mime::MOBILE) if mobile_client? 
end 

Điều này đặt các định dạng điện thoại di động vào phía trước của danh sách các định dạng có thể chấp nhận. Do đó, Trình giải quyết thích các mẫu .mobile.erb nhưng sẽ quay trở lại .html.erb nếu không tìm thấy phiên bản dành cho thiết bị di động.

Tất nhiên, để làm việc này bạn cần phải thực hiện một số loại #mobile_client? chức năng và đưa Mime::Type.register_alias "text/html", :mobile vào bạn config/initializers/mime_types.rb

+0

Không có phiên bản đường ray nào được chỉ định cho bản sửa lỗi này. Đã thử trong 3.0.1. Các request.formats không hoạt động trả về một mảng '[text/html]' với 'Mime :: Type.register_alias" text/html "thích hợp",: mobile' tại chỗ. không có cách nào để unshift rằng – kevzettler

+0

** này hoạt động ** trong Rails 3.2.1 và 3.0.8.Xin vui lòng xem cho chính mình bằng cách nhân bản và chạy https://github.com/janv/test_mobile.Nó không hoạt động cho các bố cục nhưng tôi không nghĩ đó là vấn đề. – Jan

2

tôi thêm câu trả lời khác bây giờ mà chúng tôi đã cập nhật để 3.2.X. Để lại câu trả lời cũ như trong trường hợp ai đó cần câu trả lời đó. Nhưng, tôi sẽ chỉnh sửa nó để hướng mọi người đến phiên bản hiện tại.

Sự khác biệt đáng kể ở đây là sử dụng tính khả dụng "mới" (kể từ 3.1) để thêm vào trình phân giải đường dẫn tùy chỉnh. Mà làm cho mã ngắn hơn, như Jeroen đề nghị. Nhưng lấy thêm một chút. Đặc biệt, #find_templates không còn là riêng tư nữa và dự kiến ​​bạn sẽ viết một tùy chỉnh.

# lib/fallback_resolver.rb 
class FallbackResolver < ::ActionView::FileSystemResolver 
    def initialize(path, fallbacks = nil) 
    @fallback_list = fallbacks 
    super(path) 
    end 

    def find_templates(name, prefix, partial, details) 
    format = details[:formats].first 

    return super unless @fallback_list && @fallback_list[format] 

    formats = Array.wrap(@fallback_list[format]) 
    details_copy = details.dup 
    details_copy[:formats] = formats 
    path = Path.build(name, prefix, partial) 
    query(path, details_copy, formats) 
    end 
end 

# app/controllers/application_controller.rb 
class ApplicationController < ActionController::Base 
    append_view_path 'app/views', { 
    mobile: [:sponsor_mobile, :mobile, :sponsor_html, :html], 
    html: [:sponsor_html, :html] 
    } 
    respond_to :html, :mobile 

# config/initializers/mime_types.rb 
register_alias 'text/html', :mobile 
+0

Điều này không hiệu quả đối với tôi trên Rails 3.2.3 Sau khi thêm vào bản vá, tôi không thể bắt đầu webrick. Tôi nhận được lỗi sau tại dòng trong application_controller (đối với append_view_path) gems/activeadmin-0.4.4/lib/active_admin/namespace.rb: 191: trong 'eval ': sai số đối số (2 cho 1) (ArgumentError) \t từ /Users/nikhil/Projects/niceniche/LocalNote3/app/controllers/application_controller.rb:7:in ' ' –

0

tôi đã thực hiện một monkey patch cho rằng, nhưng bây giờ, tôi sử dụng một giải pháp tốt hơn:

Trong application_controller.rb:

layout :which_layout 

def which_layout 
    mobile? ? 'mobile' : 'application' 
end 

Với mobile? phương pháp bạn có thể viết.

Vì vậy, tôi có bố cục khác nhưng tất cả các chế độ xem giống nhau và trong bố cục mobile.html.erb, tôi sử dụng tệp CSS khác.

2

Dưới đây là một giải pháp đơn giản hơn:

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

Hóa ra Rails (3.2.11) cho biết thêm một: html dự phòng cho các yêu cầu với: js dạng. Dưới đây là cách hoạt động:

  • ActionController :: Rendering # process_action gán mảng định dạng từ yêu cầu (xem action_controller/kim loại/rendering.rb)
  • ActionView :: LookupContext # định dạng = được gọi với kết quả

Dưới đây là ActionView :: LookupContext # định dạng =,

# 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 

giải pháp này là tổng nhưng tôi không biết một cách tốt hơn để có được Rails để giải thích một reque Loại MIME của "di động" là trình định dạng [: di động,: html] - Đường ray đã thực hiện theo cách này.

0

Tôi cần điều tương tự.Tôi đã nghiên cứu điều này bao gồm câu hỏi tràn ngăn xếp này (và một câu hỏi tương tự khác) cũng như theo chủ đề đường ray (như được đề cập trong câu hỏi này) tại https://github.com/rails/rails/issues/3855 và theo chủ đề/gists/đá quý của nó.

Heres những gì tôi đã kết thúc làm việc đó với Rails 3.1 và công cụ. Giải pháp này cho phép bạn đặt * .mobile.haml (hoặc * .mobile.erb v.v.) vào cùng một vị trí với các tệp xem khác của bạn mà không cần 2 cấu trúc phân cấp (một cho thông thường và một cho thiết bị di động).

Động cơ và Mã chuẩn bị

trong công cụ của tôi 'cơ sở' Tôi bổ sung này trong 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 

Sau đó, trong điều khiển ứng dụng 'cơ sở' động cơ của tôi Tôi đã thêm một điện thoại di động? Phương pháp:

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

Và cũng before_filter này:

before_filter :set_layout 

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

Cuối cùng, tôi thêm này vào config/initializers/mime_types.rb:

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

Cách sử dụng

Bây giờ tôi có thể có (ít ứng dụng của tôi cấp độ hoặc trong một công cụ):

  • app/views/layouts/application.mobile.haml
  • và trong bất kỳ xem một .mobile.haml thay vì một tập tin .html.haml.

Tôi thậm chí có thể sử dụng một cách bố trí di động cụ thể nếu tôi đặt nó trong bất kỳ điều khiển: bố trí 'di động'

mà sẽ sử dụng app/views/layouts/mobile.html.haml (hoặc thậm chí mobile.mobile.haml).

1

Rails 4.1 bao gồm Biến thể, đây là một tính năng tuyệt vời cho phép bạn đặt các chế độ xem khác nhau cho cùng một đồng xu. Bây giờ bạn có thể chỉ cần thêm một before_action và để cho các biến thể để làm điều kỳ diệu:

before_action :detect_device_variant 

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

Sau đó, trong hành động của bạn:

respond_to do |format| 
    format.json 
    format.html    # /app/views/the_controller/the_action.html.erb 
    format.html.phone   # /app/views/the_controller/the_action.html+phone.erb 
    format.html.tablet do 
    @some_tablet_specific_variable = "foo" 
    end 
end 

Thông tin thêm here.

Các vấn đề liên quan