将 foreign_key 值传递给 Rails 控制器的更好方法
Posted
技术标签:
【中文标题】将 foreign_key 值传递给 Rails 控制器的更好方法【英文标题】:The better way to pass the foreign_key value to the Rails controller 【发布时间】:2011-03-05 21:55:13 【问题描述】:自从我开始深入研究表单、关联、哈希、符号以来已经快一周了……但如果没有你的帮助,我似乎无法解决这个难题。
我正在开发一个显示不同画廊内容的项目。基本思想是当用户看到画廊的名称(名称是链接)时,能够点击选择的画廊。然后显示属于该图库的所有图像。在底部应该有一个链接“在此图库中添加图片”。
我的模型:
class Gallery < ActiveRecord::Base
attr_accessible :name
has_many :pictures
end
class Picture < ActiveRecord::Base
attr_accessible :image
belongs_to :gallery
end
我在 gallery_id 上为“图片”表创建了索引。
我的大问题出现在这里,如何将 gallery_id 传递给控制器的操作 'new' 。正如我在“使用 Rails 进行敏捷 Web 开发”中看到的那样:@gallery.id) %>
在这种情况下,foreign_key :gallery_id 似乎暴露在浏览器的 URL 栏中。第二个问题是 :gallery_id 可用于控制器的“新”功能,但“消失”用于“创建”功能(导致错误“找不到没有 ID 的画廊”)。 当我在图片的_form中添加一个隐藏字段时,问题就消失了,就我而言:
<%= form_for(@picture) do |f| %>
<div class="field">
<%= f.hidden_field :gallery_id , :value=>params[:gallery_id] %>
<%= f.label :image %><br />
<%= f.file_field :image %>
</div>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
这是我在“图片”控制器中的定义:
def new
@gallery=Gallery.find(params[:gallery_id])
@picture=@gallery.pictures.build
end
def create
@gallery = Gallery.find(params[:gallery_id])
@picture = @gallery.pictures.new(params[:picture])
if @picture.save
redirect_to(@picture, :notice => 'Picture was successfully created.')
else
redirect_to(galleries ,:notice => 'Picture was NOT created.')
end
end
最后是 show.html.erb 中用于画廊的 link_to 定义:
<% for picture in selpics(@gallery) %>
<div id= "thumb" >
<%= image_tag picture.image %>
</div>
<% end %>
<%= link_to 'Add a picture here...',new_picture_path(:gallery_id=>@gallery.id) %>
这是提交图像之前的调试输出: --- !map:ActiveSupport::HashWithIndifferentAccess 画廊 ID:“6” 动作:新 控制器:图片
并在提交“创建”按钮后(引发异常):
"utf8"=>"✓",
"authenticity_token"=>"IGI4MfDgbavBShO7R2PXIiK8fGjkgHDPbI117tcfxmc=",
"picture"=>"image"=>"wilsonblx.png",
"commit"=>"Create"
如您所见,“图片”哈希中没有像“gallery_id”这样的东西。
总结我的问题给你:
有没有办法在没有 hidden_field 的情况下传递 foreign_key ?
我可以通过 URL 栏中显示的外键表单以某种方式隐藏吗?
是否有使用 'link_to' 传递参数的替代方法?
谢谢。
【问题讨论】:
隐藏外键是一个常见的pb。适当的路由会导致它们的清晰暴露。如果您想隐藏这些,请使用缓存、cookie 或会话。 谢谢你鼓励我,我在想'我迷路了,应该放弃......'。因此,在这种情况下,会话和 cookie 不是“麻雀大炮”。 【参考方案1】:您可能需要考虑阅读有关嵌套资源的 Rails 指南:
http://guides.rubyonrails.org/routing.html#nested-resources
简而言之:
routes.rb
resources :galleries do
resources :pictures do
end
# Generates the routes: /galleries/:gallery_id/pictures
pictures_controller.rb
def new
@gallery = Gallery.find(params[:gallery_id])
@picture = Picture.new
end
def create
@gallery = Gallery.find(params[:gallery_id]) # gallery_id is passed in the URL
@picture = @gallery.build(params[:picture])
if @picture.save
# success
else
# fail
end
end
图片/new.html.erb
<%= form_for [@gallery, @picture] do |f| %>
<div class="field">
<%= f.hidden_field :gallery_id , :value=>params[:gallery_id] %>
<%= f.label :image %><br />
<%= f.file_field :image %>
</div>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
好的,gallery_id 仍然是通过 URL 传递的,但我真的看不出有什么问题。你必须把它传递到某个地方,对吧?您实际上只有 3 个明智的选择来传递它:隐藏字段,作为查询字符串参数,或隐藏在 URL(嵌套资源)中。在这 3 个中,后者是恕我直言的最干净的方法。
如果您想让自己的事情变得更轻松,我强烈建议您研究 Jose Valim 的 Inherited Resources gem,它可以为您解决很多这些样板文件的肮脏问题:
https://github.com/josevalim/inherited_resources
【讨论】:
乔希,你真的让我的星期天闪闪发光!!!谢谢你,好人。真的,通过向我指出嵌套资源和 Jose Valim 继承的资源,你揭示了一个全新的宇宙。我希望有一天我能帮助人们(分享知识)。 甜蜜。我很高兴你发现它有帮助。我肯定会说在深入继承资源之前熟悉嵌套资源的工作原理。婴儿步骤! 我对 Rails 不是很有经验,但我认为resources :galleries do resources :pictures do end
的部分应该是resources :galleries do resources :pictures end
(没有第二个'do'关键字)。【参考方案2】:
您无需在 RESTful 路由中使用数字 ID。查看 permalink_fu,并使用 :permalink 字段而不是 :id 来引用每个画廊资源。
/galleries/louvre
/galleries/moma/382
和
... new_picture_path(:gallery_id => @gallery.permalink)
这里的关键是使用不是 ID 的符号唯一键,永久链接非常适合。
您可以选择将永久链接作为 :id 传递并更新您的控制器操作以达到预期效果。
【讨论】:
谢谢你,全软件!非常有用的资源。我敢肯定,你的帖子会帮助很多像我这样的新手。以上是关于将 foreign_key 值传递给 Rails 控制器的更好方法的主要内容,如果未能解决你的问题,请参考以下文章