【问题标题】:Variables in Rails RoutingRails 路由中的变量
【发布时间】:2014-12-11 19:46:51
【问题描述】:

我已经搜索并尝试了http://guides.rubyonrails.org/routing.html 中提到的许多不同的东西,但没有一个接缝可以做我想做的事。

要点: 我有一个控制器,可以为不同的手机类型设置视图

class PhoneViewsController < ApplicationController
  def android_automated
    #Do Android Stuff
  end
  def android_interactive
    #Do Android Stuff
  end
  def ios_automated
    #Do Apple Stuff
  end
  def ios_interactive
    #Do Apple Stuff
  end
  def blackberry_automated
    #Do Blackberry Stuff
  end
  def blackberry_interactive
    #Do Blackberry Stuff
  end
end

上述每个方法在 phone_views 视图文件夹中都有对应的视图部分

我希望将 /android/interactive 之类的网址读取为 phone_views#android_interactive

Rails 路由的语法允许我使用诸如

之类的参数进行重定向
 get 'android/:action', to: redirect('/phone_views/android_%{action}')
 get 'phone_views/:action' , :controller => 'phone_views'

这会呈现正确的页面,但有一个时髦的 url 的讨厌的副作用

我尝试过将其用作:

get 'android/:mode', :to => 'phone_views#android_%{mode}'

但我得到一个动作 %{mode} not found 错误,好像它没有将 %{mode} 视为变量

get 'android/:action', :controller => 'phone_views', :action => 'android_%{action}'

导致找不到“交互式”错误操作,并且:

get 'android/:mode', :controller => 'phone_views', :action => 'android_%{mode}'

得到与上述相同的操作 %{mode} not found 错误。

在获取请求中获取命名变量(例如 :mode)并将其用于形成操作的语法是什么?

更新: 我相信我几乎想通了。这些变量似乎无法以我尝试使用它们的方式访问,但如果您将请求传递给 proc{},它们似乎是可访问的。

match 'android/:mode', to: proc{|params| action = params['action_dispatch.request.path_parameters'][:mode]; control = PhoneViewsController.new(); control.send('android_' + action)}, via: [:get]

然而,这只会导致错误 undefined method `[]' for nil:NilClass 但错误在适当的控制器中。希望这有助于解决这个问题。

【问题讨论】:

  • 你试过简单的get 'android/interactive', :to =&gt; 'phone_views#android_interactive'吗?
  • 是的,这确实有效,但这意味着我必须为每种可能的 android 模式输入一个条目。如果我能弄清楚访问变量的语法,我可以使这种方法更加动态。

标签: ruby-on-rails variables routing


【解决方案1】:

我不认为你想让一个随机的互联网用户能够选择他们喜欢访问的任何控制器方法,所以这是你应该做的:

[:automated, :interactive].each do |mode|
  [:android, :ios, :blackberry].each do |device|
    get "#{ device }/#{ mode }", :to => "phone_views##{ device }_#{ mode }"
  end
end

如果您需要添加其他设备或模式,您只需在完成控制器/视图/等中的方法后更新您的 routes.rb 文件即可。

如果你真的想变得花哨,你可以将这些静态符号数组移动到它们自己的类中,用于管理设备和它们支持的模式。

此外,请确保在处理路由中的冒号变量时对输入施加约束。

编辑:get 调用末尾的额外 " 已删除

【讨论】:

  • 干得好,这确实有效(在我取出第 3 行的额外报价之后),您甚至考虑了安全性。您能否添加一个指向描述此解决方案(为什么有效)的来源的链接,以便我可以为您提供赏金?
  • 它之所以有效,是因为它是基本的 Ruby 代码。您遍历模式数组,并且对于其中的每一种模式,您都遍历设备。对于这些组合中的每一个,您都调用get 方法并为其提供来自这两个数组的字符串。关于字符串本身,#{} 语法是 Ruby 字符串插值的一部分。 learnrubythehardway.org/book/ex6.html
  • 我将奖励赏金,但我正在寻找在 routes.rb 中使用的 this 的引用或在 routes.rb 中允许这样做的内容,因为虽然简单的 ruby​​ 语法需要使用字符串搜索字符串中的替换和控制器/操作字符串中的转义序列。
【解决方案2】:

当您应该使用# 时,您正在使用%。这对我有用:

get 'android/:mode', :to => 'phone_views#android_#{mode}'

【讨论】:

  • 无法为控制器 phone_views 找到错误 android_。它看到 # 符号并认为它是另一个参数,例如 ID
  • 今天早上我又看了一遍,发现你使用的是字符串字面量,我改成双引号,得到一个不同的错误信息:undefined local variable or method `mode' for #<:routing::mapper :guid> 至少它现在将其识别为变量。但是想知道为什么它会是未定义的,因为 url 是 android/interactive 的?
  • 你应该使用单引号,否则它会在路由加载而不是运行时尝试使用模式变量。
  • 单引号导致我在第一条评论中提到的错误。我在推测,但它似乎看到了 # 并忽略了语句的其余部分。
  • 你使用的是什么版本的 Rails?
【解决方案3】:

我认为您的方法之所以困难,是因为您正在尝试做应该在路由中的控制器中发生的事情。为什么不尝试这种方法:

get 'android/:mode', :to => 'phone_views#android'

在你的控制器中:

class PhoneViewsController < ApplicationController
  def android
    self.send("android_#{params[:mode]")
  end

  def android_automated
    #Do Android Stuff
  end
  def android_interactive
    #Do Android Stuff
  end

end

虽然这种方法在params[:mode]没有正确清理时可能会出现一些安全问题(但我认为路由方法可能有类似的问题)

【讨论】:

  • 我曾探索过在控制器中使用带有传入参数的 switch 语句,实际上这是第一次尝试,但为什么在路由引擎应该执行此工作时使控制器逻辑复杂化。想象一下,如果我有一个预先存在的控制器,然后市场营销人员说“我们需要更改所有用于 SEO 的 url”,我应该更改控制器还是动态生成路由?这种方法也遇到了 proc 路由的缺失模板问题,因为它没有实例化正确的视图。
【解决方案4】:

你试过了吗

get 'android/:action', :controller => 'phone_views', :action => "android_#{:action}"

【讨论】:

  • 错误 找不到 PhoneViewsController 的操作“交互式”,因为您将变量命名为 :action,它会自动关联它并忽略您的声明。如果我将变量重命名为模式 ie: android/:mode', :controller => 'phone_views', :action => "android_#{:mode}" 错误变为:找不到操作'android_mode' PhoneViewsController
猜你喜欢
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多