RoR:form_for:symbol vs @object做奇怪的方式

时间:2015-09-11 04:55:04

标签: ruby-on-rails ruby form-for

我正在关注Getting Started with Rails教程。
view create new article生成controller时,我使用:
案例1 :article

<%= form_for :article do |f| %>

enter image description here
并得到错误No route matches [POST] "/articles/new"
我认为它应该是[POST] "/articles
案例2 我更改为:@artical

<%= form_for @article do |f| %>

enter image description here
没关系。

请注意,在案例1 中,submit button的文字为:Save article,在案例2 Create article /> 它与This SOF answer的方式相反 这对我来说太模糊了!那么有人可以帮我解释一下吗? 这是我的source code on github

2 个答案:

答案 0 :(得分:1)

form_for :article创建了一个表单,但提交的默认网址为/articles/new

用于显示要提交的表单的文章的动作new,而不是处理创建新文章

=&GT; resources :articles会将其与GET方法

进行映射

您可以为该表单指定一个网址,或更改请求方法(不推荐)

<%= form_for :article, url: articles_path do |f| %>

答案 1 :(得分:1)

简短回答

这是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值。

对于提交值,您可以看到如何根据表单目标是否为对象来获取密钥,然后进行翻译。