RoR: form_for :symbol vs @object 做奇怪的事
RoR: form_for :symbol vs @object do the odd way
我正在学习 Getting Started with Rails 教程。
当为 create new article
controller
生成 view
时,我使用:
案例 1::article
<%= form_for :article do |f| %>
并得到错误 No route matches [POST] "/articles/new"
我以为应该是 [POST] "/articles
案例2我改为:@artical
<%= form_for @article do |f| %>
没关系。
请注意,在 case 1 中,submit button
的文本是:Save article
,在 case 2[ 中是 Create article
=51=]
它与 This SOF answer.
相反
对我来说太暧昧了!!!那么有人可以帮我解释一下吗?
这是我的 source code on github
form_for :article
创建了一个表单,但默认 url 提交是 /articles/new
用于显示提交表单的文章操作 new
,不处理创建新文章
=> resources :articles
将使用 GET
方法映射它
您可以为该表单指定一个 url,或者更改请求方法(不推荐)
<%= form_for :article, url: articles_path do |f| %>
简答
这就是 Rails 的工作方式,所以基本上,您应该将一个对象传递给 form_for
。
长答案
查看源代码后,这里发生了什么。
当您将对象传递给 form_for
时,action
将计算为:
url_for(polymorphic_path(@object))
如果对象是一篇未持久化的文章,它将给出 /articles
,如果对象是一篇持久化的文章,它将给出 /articles/:id
。
当您传递字符串或符号时,action
会导致 url_for
调用
使用空散列,导致当前路径,在您的情况下 /articles/new
。请注意,如果您显示来自 /articles/custom
的表单,则路径将为 /articles/custom
.
对于按钮,如果传递一个对象,提交输入值将是
I18n.t('helpers.submit.create')
或 I18n.t('helpers.submit.update')
取决于您的模型是否保留。但是,如果您传递字符串或符号,则该值将为 I18n.t('helpers.submit.submit')
.
这是来自 Rails 来源的相关代码行。
# actionview/lib/action_view/helpers/form_helper.rb#L422
def form_for(record, options = {}, &block)
# .....
when String, Symbol
object_name = record
object = nil
else
object = record.is_a?(Array) ? record.last : record
raise ArgumentError, "First argument in form cannot contain nil or be empty" unless object
object_name = options[:as] || model_name_from_record_or_class(object).param_key
apply_form_for_options!(record, object, options)
end
# .....
html_options = html_options_for_form(options[:url] || {}, html_options)
form_tag_with_body(html_options, output)
end
# actionview/lib/action_view/helpers/form_helper.rb#L451
def apply_form_for_options!(record, object, options) #:nodoc:
# ....
options[:url] ||= if options.key?(:format)
polymorphic_path(record, format: options.delete(:format))
else
polymorphic_path(record, {})
end
end
# actionview/lib/action_view/helpers/form_tag_helper.rb#L840
def html_options_for_form(url_for_options, options)
options.stringify_keys.tap do |html_options|
# ....
html_options["action"] = url_for(url_for_options)
# ....
end
end
# actionview/lib/action_view/helpers/form_helper.rb#L1873
def submit_default_value
object = convert_to_model(@object)
key = object ? (object.persisted? ? :update : :create) : :submit
# .....
defaults = []
defaults << :"helpers.submit.#{object_name}.#{key}"
defaults << :"helpers.submit.#{key}"
defaults << "#{key.to_s.humanize} #{model}"
I18n.t(defaults.shift, model: model, default: defaults)
end
# locale/en.yml#L142
helpers:
select:
prompt: Please select
submit:
create: Create %{model}
submit: Save %{model}
update: Update %{model}
对于操作,您可以看到在传递字符串时未调用 apply_form_for_options!
,因此 options[:url]
仍然是 nil
。传递对象时,如果未设置,apply_form_for_options!
将 options[:url]
设置为 polymorphic_path(@object)
。然后将其传递给 html_options_for_form
,其中 action
设置为将 url_for
应用于值。
对于提交值,可以看到根据表单目标是否为对象取key,然后翻译。
我正在学习 Getting Started with Rails 教程。
当为 create new article
controller
生成 view
时,我使用:
案例 1::article
<%= form_for :article do |f| %>
并得到错误 No route matches [POST] "/articles/new"
我以为应该是 [POST] "/articles
案例2我改为:@artical
<%= form_for @article do |f| %>
没关系。
请注意,在 case 1 中,submit button
的文本是:Save article
,在 case 2[ 中是 Create article
=51=]
它与 This SOF answer.
相反
对我来说太暧昧了!!!那么有人可以帮我解释一下吗?
这是我的 source code on github
form_for :article
创建了一个表单,但默认 url 提交是 /articles/new
用于显示提交表单的文章操作 new
,不处理创建新文章
=> resources :articles
将使用 GET
方法映射它
您可以为该表单指定一个 url,或者更改请求方法(不推荐)
<%= form_for :article, url: articles_path do |f| %>
简答
这就是 Rails 的工作方式,所以基本上,您应该将一个对象传递给 form_for
。
长答案
查看源代码后,这里发生了什么。
当您将对象传递给 form_for
时,action
将计算为:
url_for(polymorphic_path(@object))
如果对象是一篇未持久化的文章,它将给出 /articles
,如果对象是一篇持久化的文章,它将给出 /articles/:id
。
当您传递字符串或符号时,action
会导致 url_for
调用
使用空散列,导致当前路径,在您的情况下 /articles/new
。请注意,如果您显示来自 /articles/custom
的表单,则路径将为 /articles/custom
.
对于按钮,如果传递一个对象,提交输入值将是
I18n.t('helpers.submit.create')
或 I18n.t('helpers.submit.update')
取决于您的模型是否保留。但是,如果您传递字符串或符号,则该值将为 I18n.t('helpers.submit.submit')
.
这是来自 Rails 来源的相关代码行。
# actionview/lib/action_view/helpers/form_helper.rb#L422
def form_for(record, options = {}, &block)
# .....
when String, Symbol
object_name = record
object = nil
else
object = record.is_a?(Array) ? record.last : record
raise ArgumentError, "First argument in form cannot contain nil or be empty" unless object
object_name = options[:as] || model_name_from_record_or_class(object).param_key
apply_form_for_options!(record, object, options)
end
# .....
html_options = html_options_for_form(options[:url] || {}, html_options)
form_tag_with_body(html_options, output)
end
# actionview/lib/action_view/helpers/form_helper.rb#L451
def apply_form_for_options!(record, object, options) #:nodoc:
# ....
options[:url] ||= if options.key?(:format)
polymorphic_path(record, format: options.delete(:format))
else
polymorphic_path(record, {})
end
end
# actionview/lib/action_view/helpers/form_tag_helper.rb#L840
def html_options_for_form(url_for_options, options)
options.stringify_keys.tap do |html_options|
# ....
html_options["action"] = url_for(url_for_options)
# ....
end
end
# actionview/lib/action_view/helpers/form_helper.rb#L1873
def submit_default_value
object = convert_to_model(@object)
key = object ? (object.persisted? ? :update : :create) : :submit
# .....
defaults = []
defaults << :"helpers.submit.#{object_name}.#{key}"
defaults << :"helpers.submit.#{key}"
defaults << "#{key.to_s.humanize} #{model}"
I18n.t(defaults.shift, model: model, default: defaults)
end
# locale/en.yml#L142
helpers:
select:
prompt: Please select
submit:
create: Create %{model}
submit: Save %{model}
update: Update %{model}
对于操作,您可以看到在传递字符串时未调用 apply_form_for_options!
,因此 options[:url]
仍然是 nil
。传递对象时,如果未设置,apply_form_for_options!
将 options[:url]
设置为 polymorphic_path(@object)
。然后将其传递给 html_options_for_form
,其中 action
设置为将 url_for
应用于值。
对于提交值,可以看到根据表单目标是否为对象取key,然后翻译。