如何在 Rails 中为 iPhone 创建单独的视图路径/目录?
我正在制作现有 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,你的方法有错误。您仅“设置”视图路径,而不能“取消设置”它。当您执行类似的操作时,
实际上会在请求之间持续存在(在内部,您正在设置一个类变量,并且由于类在生产中缓存,因此该变量在请求之间保持设置状态)。因此,当前的查看路径就是你上次请求的查看路径。
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
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.
我能够通过使用名为 theme_for_rails 的 gem 来解决这个问题:
https://github.com/lucasefe/themes_for_rails
安装 gem 后,以下是我添加到应用程序文件中的内容:
我将主题放置在
[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:
I placed my themes in
[application_root]/themes
. Make sure you don't put it in[application_root]/app/themes
.