STI,一个控制器

Piz*_*ato 58 ruby ruby-on-rails ruby-on-rails-3

我是铁杆的新手,我很难解决这个设计问题,这可能很容易解决,但我无处可去:我有两种不同的广告:亮点和便宜货.它们都具有相同的属性:标题,描述和一个图像(使用回形针).它们也有相同的动作应用于它们:索引,新建,编辑,创建,更新和销毁.

我设置了一个像这样的STI:

广告模型:ad.rb

class Ad < ActiveRecord::Base
end
Run Code Online (Sandbox Code Playgroud)

讨价还价模型:bargain.rb

class Bargain < Ad
end
Run Code Online (Sandbox Code Playgroud)

突出显示模型:highlight.rb

class Highlight < Ad
end
Run Code Online (Sandbox Code Playgroud)

问题是我想只有一个控制器(AdsController)执行我在讨价还价或亮点上所说的操作,具体取决于URL,比如www.foo.com/bargains [/ ...]或www.foo.com /强调[/...].

例如:

  • 获取www.foo.com/highlights =>所有重点广告的列表.
  • 获取www.foo.com/highlights/new =>表格以创造新的亮点......

我怎样才能做到这一点?

谢谢!

fl0*_*00r 101

第一.添加一些新路线:

resources :highlights, :controller => "ads", :type => "Highlight"
resources :bargains, :controller => "ads", :type => "Bargain"
Run Code Online (Sandbox Code Playgroud)

并修复一些行动AdsController.例如:

def new
  @ad = Ad.new()
  @ad.type = params[:type]
end
Run Code Online (Sandbox Code Playgroud)

对于所有此控制器作业的最佳方法,请查看此评论

就这样.现在你可以去localhost:3000/highlights/new,新的Highlight将被初始化.

索引操作可能如下所示:

def index
  @ads = Ad.where(:type => params[:type])
end
Run Code Online (Sandbox Code Playgroud)

转到localhost:3000/highlights并将显示突出显示列表.
讨价还价的方式相同:localhost:3000/bargains

等等

URLS

<%= link_to 'index', :highlights %>
<%= link_to 'new', [:new, :highlight] %>
<%= link_to 'edit', [:edit, @ad] %>
<%= link_to 'destroy', @ad, :method => :delete %>
Run Code Online (Sandbox Code Playgroud)

为多态:)

<%= link_to 'index', @ad.class %>
Run Code Online (Sandbox Code Playgroud)

  • 哦,我明白了.你可以尝试`<%= link_to'index',@ ad.class%>`以及polymorphic_path的简短形式 (2认同)

Ala*_*ody 64

fl00r有一个很好的解决方案,但我会进行一次调整.

在您的情况下,这可能需要也可能不需要.这取决于您的STI模型中的行为正在发生变化,尤其是验证和生命周期挂钩.

向控制器添加一个私有方法,将类型参数转换为您想要使用的实际类常量:

def ad_type
  params[:type].constantize
end
Run Code Online (Sandbox Code Playgroud)

然而,上述情况并不安全.添加类型的白名单:

def ad_types
  [MyType, MyType2]
end

def ad_type
  params[:type].constantize if params[:type].in? ad_types
end
Run Code Online (Sandbox Code Playgroud)

更多关于rails constantize方法:http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-constantize

然后在控制器动作中你可以做到:

def new
  ad_type.new
end

def create
  ad_type.new(params)
  # ...
end

def index
  ad_type.all
end
Run Code Online (Sandbox Code Playgroud)

现在,您正在使用具有正确行为的实际类,而不是具有属性类型set的父类.

  • **不要在生产代码中原样使用此方法.**最初可能并不明显,但默认情况下,此Ad#ad_type方法隐式信任用户提供的数据,违反了Web应用安全性的基本规则.想象一下对`/ ads?type = User`的POST请求,其有效负载包括`is_admin = 1`(或者适用于所使用的认证机制的任何内容).现在攻击用户拥有自己的管理员权限的用户帐户!(从技术上讲,这种攻击向量可以通过改变或删除默认的"ads"路线来消除,但是后来的新路线可能会无意中再次打开洞.) (2认同)
  • 在检查是否包含`params [:type]`之前,必须将有效`ad_types`数组转换为字符串 (2认同)

And*_*ank 12

我只是想包含这个链接,因为有很多有趣的技巧都与这个主题有关.

Alex Reisner - Rails中的单表继承

  • 该链接已更改为http://www.alexreisner.com/code/single-table-inheritance-in-rails (3认同)