如何在 Rails 中为 iPhone 创建单独的视图路径/目录?

发布于 2024-10-02 07:00:11 字数 2522 浏览 3 评论 0原文

我正在制作现有 Rails 应用程序的 iPhone 版本。我希望通过子域(例如 iphone.mysite.com)访问移动版本。

我知道我可以对单个 erb 文件使用格式和 respond_to 块,例如 index.iphone.erb ,如下所示:

创建 iPhone 优化版本使用 iUI 和 Rails 2 的 Rails 站点

但我想为移动版本和常规版本保留完全独立的视图目录,如下所示:

app/views/iphone

这是我在应用程序控制器中尝试过的内容:

class ApplicationController < ActionController::Base
before_filter :set_site

def set_site
   subdomain=self.request.subdomains[0]
   ActionController::Base.prepend_view_path("app/views/#{subdomain}")
end

测试时,但是,视图会切换到与任何用户最后请求的子域关联的视图。

例如,如果我访问 http://iphone.mysite.com,然后立即在另一个单独的浏览器中转到 http://www.mysite.com,我会看到移动版本而不是普通版本。刷新它将纠正此问题并调出正确的版本。但是,如果我在另一个浏览器中返回 http://iphone.mysite.com 并刷新,它会显示非移动网站!我抓狂了,不明白发生了什么。

任何建议将不胜感激。

编辑 1

Vlad 在下面找到了一个链接< /a> 有一个可能的解决方案,但它对我不起作用。这是我尝试过的代码。我创建了一个名为 subdomain_view.rb 的文件,并将其放置在 config/initializers 中:

# Put all of this in a bootstrap-only initializer
ActionController::Base.class_eval do
  APP_ONE_VIEW_PATH = "app/views/iphone"
  APP_TWO_VIEW_PATH = "app/views/default"

  cattr_accessor  :application_view_path
  self.view_paths = ["app/views", APP_ONE_VIEW_PATH, APP_TWO_VIEW_PATH]

  # This is where you determine the switching mechanism for your application. Here, it is a simple GET parameter.
  # You can probably argue that this specific piece SHOULD be in your actual app_controller class definition, as it is the only piece
  # of info pertinent to the rest of your application.
  before_filter do |controller|
    ActionController::Base.application_view_path = request.subdomains[0]=="iphone" ? APP_TWO_VIEW_PATH : APP_ONE_VIEW_PATH
  end
end

require 'aquarium'
ActionView::PathSet.class_eval do
  include Aquarium::DSL
  before :find_template do |join_point, object, *args|
    object.each_with_index do |path,i|
      object.unshift(object.delete_at(i)) if path.to_s == ActionController::Base.application_view_path
    end
  end
end
# I'll leave the exercise of testing this or implementing it for your particular app up to you.

使用上面的代码,无论我放入哪个子域,我都会得到相同的视图。关于可能出现问题的建议?我是否将此代码放在错误的位置?

I'm making an iPhone version of an existing Rails app. I'd like to make the mobile version accessible via a subdomain such as iphone.mysite.com.

I know I can use formats and the respond_to block for individual erb files, such as index.iphone.erb as show here:

Creating an iPhone optimised version of your Rails site using iUI and Rails 2

But I'd like to keep entirely separate view directories for the mobile version and regular version such as this:

app/views/iphone

Here's what I've tried in my Application controller:

class ApplicationController < ActionController::Base
before_filter :set_site

def set_site
   subdomain=self.request.subdomains[0]
   ActionController::Base.prepend_view_path("app/views/#{subdomain}")
end

When testing this, however, the view switches to the view associated with the last requested subdomain by any user.

For example, if I visit http://iphone.mysite.com, then immediately go to http://www.mysite.com in another separate browser, I see the mobile version instead of the regular one. Refreshing it will correct this and bring up the right version. But if I go back to http://iphone.mysite.com in the other browser and refresh, it brings up the non-mobile site! I'm tearing my hair out and not understanding what's going on.

Any advice would be much appreciated.

Edit 1

Vlad below found a link with a possible solution however it is not working for me. Here is the code I tried. I made a file called subdomain_view.rb and placed it in config/initializers:

# Put all of this in a bootstrap-only initializer
ActionController::Base.class_eval do
  APP_ONE_VIEW_PATH = "app/views/iphone"
  APP_TWO_VIEW_PATH = "app/views/default"

  cattr_accessor  :application_view_path
  self.view_paths = ["app/views", APP_ONE_VIEW_PATH, APP_TWO_VIEW_PATH]

  # This is where you determine the switching mechanism for your application. Here, it is a simple GET parameter.
  # You can probably argue that this specific piece SHOULD be in your actual app_controller class definition, as it is the only piece
  # of info pertinent to the rest of your application.
  before_filter do |controller|
    ActionController::Base.application_view_path = request.subdomains[0]=="iphone" ? APP_TWO_VIEW_PATH : APP_ONE_VIEW_PATH
  end
end

require 'aquarium'
ActionView::PathSet.class_eval do
  include Aquarium::DSL
  before :find_template do |join_point, object, *args|
    object.each_with_index do |path,i|
      object.unshift(object.delete_at(i)) if path.to_s == ActionController::Base.application_view_path
    end
  end
end
# I'll leave the exercise of testing this or implementing it for your particular app up to you.

With the above code, I am getting the same view no matter what subdomain I put in. Any suggestions on what might be wrong? Am I putting this code in the wrong place?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蓝礼 2024-10-09 07:00:11

首先,你的方法有错误。您仅“设置”视图路径,而不能“取消设置”它。当您执行类似的操作时,

ActionController::Base.prepend_view_path

实际上会在请求之间持续存在(在内部,您正在设置一个类变量,并且由于类在生产中缓存,因此该变量在请求之间保持设置状态)。因此,当前的查看路径就是你上次请求的查看路径。

IMO,您应该动态计算当前子域的 view_path (这意味着一些 ActionView 黑客攻击)。 此处提供了一个很好的解决方案。

First, you have an error in your approach. You only 'set' a view path, you don't 'unset' it. When you do something like

ActionController::Base.prepend_view_path

this actually persists between your requests (internally, you are setting a class variable, and because classes are cached in production, this variable remains set between requests). Therefore, the current view path is the view path of your last request.

IMO, you should dynamically compute view_path for your current subdomain (this implies some ActionView hacking). A nice solution is provided here.

面如桃花 2024-10-09 07:00:11

我能够通过使用名为 theme_for_rails 的 gem 来解决这个问题:

https://github.com/lucasefe/themes_for_rails

安装 gem 后,以下是我添加到应用程序文件中的内容:

#application_controller.rb
class ApplicationController < ActionController::Base
  theme :theme_resolver
  def theme_resolver
      current_subdomain=self.request.subdomains[0]
  end
end


#routes.rb
MyAppName::Application.routes.draw do
  themes_for_rails
end


#Gemfile
gem 'themes_for_rails'

我将主题放置在 [application_root]/themes 中。确保不要将其放在 [application_root]/app/themes 中。

I was able to solve the problem by using a gem called themes_for_rails:

https://github.com/lucasefe/themes_for_rails

After installing the gem, here's what I added to my application files:

#application_controller.rb
class ApplicationController < ActionController::Base
  theme :theme_resolver
  def theme_resolver
      current_subdomain=self.request.subdomains[0]
  end
end


#routes.rb
MyAppName::Application.routes.draw do
  themes_for_rails
end


#Gemfile
gem 'themes_for_rails'

I placed my themes in [application_root]/themes. Make sure you don't put it in [application_root]/app/themes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文