Rails 询问一个从 view 回调回来的参数问题。。

lin_style · 2012年03月30日 · 最后由 help5305fff 回复于 2012年03月31日 · 2976 次阅读

环境如下: controllers/events_controller.rb

def new
  @event1 = Event.new
end 

def create
  @event = Event.new(params[:event])
  @event.save

  redirect_to :action => :index
end

events/new.html.erb:

<%= form_for @event1, :url => { :controller => 'events', :action => 'create' } do |f| %>
    <%= f.label :name, "Name" %>
    <%= f.text_field :name %>

    <%= f.label :description, "Description" %>
    <%= f.text_area :description %>

    <%= f.submit "Create" %>
<% end %>

我不明白,def create 里面,new(params[:event]) ,event 这个变量从哪里来的?

查看 HTML 源代码

<input name="event[name]" />

就是把这个 name 里面的东西转换过来的。

突发奇想 new feature,是不是可以给主题帖子加一个 RTFM 的 tag 按钮,这样对我来说,这条帖子就显示出来。哈哈。

#3 楼 @xds2000 有的人是真着急,也许来不及看文档,也许不明白怎么看文档,也许是看不懂英语.... 这里发一个新手帖,经常分分钟就被人回复了,虽然能直接从文档上找到答案的问题,大多数人不愿意回答。

我经常发现有些新人会以你意想不到的速度快速成长,其中有些后来就成长为了一棵大树,所以我总是需要自我反省,一定要对新人 nice 一点,在 nice 一点,说不定以后就是你的朋友,同事,或者良师益友呢,谁知道呢?

#1 楼 @huacnlee 这个我知道,但是 中的 event 又是哪儿来的?

看生成的 html 代码,你就懂了。。

@lgn21st 赞。偶是一个 ruby 新手,以前也没多少语言基础,上次在知乎问的一个问题很基础,高手看了可能觉得很低级,最后有人回答得知是 ruby 版本的原因,有时老手的一句指点真的很重要。

#7 楼 @ruby_sky 看了,我知道源码里面有这个东西。但是我想问,他是根据什么生成这个名字的,名字可能会变吗?为什么一定是这个名字呢

@lin_style 这个跟你的 form_for 的第一个参数类型有关,具体不是很了解,看了看源码,看蒙了

@lgn21st 理解。我也被你感染了。

#9 楼 @lin_style 习惯约定优于配置?

约定大于配置,没有为什么

#10 楼 @davidqhr 我把 form_for 的第一个参数类型 都改成@event1了。。但也不能写成 @event = Event.new(params[:event1])

#13 楼 @ywjno 那约定又是根据什么呢?是因为我这个 controll 的名字叫 event 吗?

#14 楼 @lin_style 约定大于配置这个对,我也不是特别明白内部实现,我对 rails 代码还是有点敬畏,不太有信心看 我个人理解

def new
  @event1 = Event.new
end

form 的@event1,要看 new action,而不是 create 的 这个里头,你的@event就是一个 Event 的一个实例,空的 所以如果你的这个 form 只是为了 new 和 create,你的 form_for 第一个参数完全可以写成 Event.new

但是大家一般都写成@event的原因是因为,修改和创建一个 model 一般都是用的相同的 partial, 你可能会有这样的代码

def edit
  @event1 = Events.find(params[:id])
end

这样的话,你的 edit action 触发的时候就不会有这个记录的默认数据在表单中

如果在 lz 的表单里,name 填写 somename,在 description 里填写 somedescripition,那么点击表单后,浏览器会发送一个 POST 请求给服务器,这 POST 请求的 body 会是如下内容(这是浏览器干的,和 rails 没关系):

commit=Create&event%5Bdescription%5D=somedescription&event%5Bname%5D=somename

服务器在接收到这请求后,就会去解析这个 body。比如,Rack 会这样解析这个字符串(见 https://github.com/rack/rack/blob/master/lib/rack/request.rb 中的 Rack::Request#params 方法)

s = "commit=Create&event%5Bdescription%5D=somedescription&event%5Bname%5D=somename"
Rack::Utils.parse_nested_query(s)
# => {"commit"=>"Create", "event"=>{"description"=>"somedescription", "name"=>"somename"}}

假设一个叫 #params 的方法的返回值,是上面的 Hash,那么就可以通过 params['event'] 得到用户输入的表单数据。

Rails-3 里,就是使用类似方法来解析 GET 请求的查询串和 POST 请求的 body,只不过增加了一些高级功能(比如既可以用字符串作为 Hash 的 key,也可以用 Symbol 作为 key)。具体可以参考 ActionDispatch::Http::Parameters#parameters#params方法是 #parameters的别名。

由于大多数 ruby web application 都是基于 Rack,而这些 application 大都基于Rack::Utils.parse_nested_query 方法来解析请求参数。这就形成了这种参数格式的惯例。

其实这个问题挺简单的

params 就是 http request 发过来的 paramter. params[:event] 就是 http request 发过来的 parameter 里面叫做:event 的。

这个可以是从 form 里面来的,也可以是 query string 里的来的。

这个跟前端这个 request 怎么生成的其实关系不大。 不光 rails,任何 web 框架,甚至以前的 cgi 等都得跟 request 打交道。

如果这部分不清楚的话,最好还是学习一下 http 的基本知识。

严重同意 #4 楼 @lgn21st ,所以请大家对我 nice 一点点 再 nice 一点点,谢谢~

#15 楼 @lin_style form_tag 生成的 name="event[name]" 是更根据 @event1 的类名来的,跟你去什么对象名称没有关系。

#18 楼 @hisea

这个跟 http 的基础知识真没什么关系。我改成 event1 就是验证下,这个跟参数名有没关系,后来发现没关系,所以才来论坛问的。我也不关心 event 到底哪儿来的,我只关心 event 命名的依据而已。我也知道习惯优于配置,我也看到了 http 中的源码,但是这个习惯不是凭空而降的,所以我才追问习惯的依据在哪里?

谢谢 #17 楼 @zhangyuan 的源码解析

目前看就 #20 楼 @huacnlee 回答了我的疑问,我也是怀疑是不是和我的类名有关系,比如我叫 events_controller.rb,就取前面的 event.现在只要有个权威人士说明确实是这个,我就满足了。

或许我描述得不够清楚,让大家回答偏了,抱歉。

匿名 #22 2012年03月31日

form_for 的参数@event1获得了你的类,然后 f.text_field :name 里,f 就代表这个实例的信息,这里获得了 event,最后形成的 input 的 name 就是 event[name] 这目的是为了让你在 action 里接受容易些。 event[name]、event[description] 在 action 里 params[:event] 就可以获得{:name=>"xxx",:description=>"xxx"} 说白了,约定好,你就省事了。。。偶以前用 dotnet,老点的版本的,就得把提交每一个参数都写一遍。。。。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号