【问题标题】:How is the 'new' action redirected to 'create' in Rails?Rails 中的“新”操作如何重定向到“创建”?
【发布时间】:2014-10-02 17:09:32
【问题描述】:

在 Rails 中,我可以使用路由文件中的 resources 自动为 CRUD 操作创建一组路由。

这会创建indexnewcreateeditshowupdate 并破坏路由。

我了解这些路由如何工作的一般流程,通常当调用路由时,会根据传递给相应操作的参数创建模型对象,并创建相应的视图或将客户端重定向到另一个指定的操作。

newedit 视图都可以使用相同的_form 部分在各自的操作中更新模型对象。但是我很难理解客户端是如何被重定向到另一个动作的。

例如,在new 操作中,客户端被重定向到create 操作,并且在new 中更新的模型对象作为参数传递给create。我不明白这是怎么发生的,因为没有指定重定向,而且我看不到模型对象是如何变成参数的。

def new
    @article = Article.new
end

def create
    @article = Article.create(article_params)

    redirect_to(article_path(@article.id))
end

_form 部分:

<%= form_for(@article) do |f| %>
    <ul>
        <% @article.errors.full_messages.each do |error| %>
        <li><%= error %></li>
            <% end %>
        </ul>
    <p>
        <%= f.label( :title ) %><br>
        <%= f.text_field( :title ) %>
    </p>

    <p>
        <%= f.label( :body ) %><br>
        <%= f.text_area( :body ) %>
    </p>

    <p>
        <%= f.submit %>
    </p>

    <% end %>

【问题讨论】:

    标签: ruby-on-rails forms redirect routes


    【解决方案1】:

    面向对象

    您的问题的底线答案是Rails 是object orientated(由于构建在Ruby 之上)。这非常很重要,因为这意味着 Rails 中的一切都应该基于对象:

    这将我引向路由 - Rails 路由的 resourceful 本质归结为相同的想法,即您需要在应用程序中使用 objects - 因此 resources 指令提供 7 个关键操作来操作这些对象

    要全面了解 Rails,您确实需要了解它如何与对象一起工作,特别是它们如何相互交互


    重定向

    要回答您关于redirect 的问题,简单的答案是Rails 不会“重定向”到任何具体的操作

    请记住,Rails 是 stateless - 它不会通过请求保存数据 - 它只有包含您当时初始化或已发送的数据

    您感到困惑的是某些 Rails 操作似乎如何将您的请求发送到适当的“请求”操作。答案在于您使用的助手/方法,特别是 form_for


    form_for

    form_for 从其 ActiveRecord 对象构建表单。

    因此,如果您执行以下操作:

    #app/controllers/your_controller.rb
    Class YourController < ActiveRecord::Base
       def new
          @model = Model.new
       end
    end
    

    这将使 Rails 知道它正在加载一个 new 对象,因此将使用 form_for 方法将请求发送到 create 操作

    如果您使用 form_tag,您将不会重定向到 create 操作——这就是 Rails 的魔力——它是为容纳对象而构建的

    【讨论】:

    • 谢谢,这很有帮助,所以它是 Rails 命名约定的一部分,任何引用初始化对象的 form_for 将始终重定向到“create”,并且任何具有现有值的对象都将重定向到“更新” '?那么按照惯例,必须始终存在“创建”和“更新”操作?
    • 是的,你完全正确!您必须注意,您只需要使用 createupdate 操作(如果您愿意)——它们不需要一直存在,但如果使用 form_for 之类的操作,它们 需要在场
    • 我刚刚遇到了一个 form_for,它将数组中的两个对象作为参数。这种情况下路由是如何工作的?
    • 只是为了占nested routes
    • 谢谢,我正在查看的当前示例是一篇文章及其 cmets。因此,当给对象分配 form_for 值时,我也给它是属于的对象,以便可以自动分配正确的 key_value。对吗?
    【解决方案2】:

    当您在路由中通过/articles/new 执行新操作时。 它呈现您的表单,如果您检查该表单,您会看到 form_for 生成的 html 是这样的

    <%= form_for @article, html: {class: "nifty_form"} do |f| %>
      <%= f.text_field :title %>
      <%= f.text_area :body, size: "60x12" %>
      <%= f.submit "Create" %>
    <% end %>
    

    它的 HTML 是

    <form accept-charset="UTF-8" action="/articles/create" method="post"  class="nifty_form">
      <input id="article_title" name="article[title]" type="text" />
      <textarea id="article_body" name="article[body]" cols="60" rows="12"></textarea>
      <input name="commit" type="submit" value="Create" />
    </form>
    

    因此,当您点击提交按钮时,您的表单会带您使用表单参数创建文章方法

    编辑动作中的相同形式

    当您点击编辑操作时articles/edit/1。如果您查看您的编辑操作,它将有

    def edit
      @article = Article.find(params[:id])
    end 
    

    因此,这会将您的表单呈现为 id 为 1 的文章

    同样的表单会有像这样的html

    <form accept-charset="UTF-8" action="/articles/1/update" method="patch"  class="nifty_form">
      <input id="article_title" name="article[title]" type="text" />
      <textarea id="article_body" name="article[body]" cols="60" rows="12"></textarea>
      <input name="commit" type="submit" value="Update" />
    </form>
    

    请注意您的操作在 html 中发生了更改,因为在您的编辑操作中您已经初始化了@article,并且您的表单根据您的初始化变量生成了 url

    【讨论】:

    • 谢谢,有道理。我仍然感到困惑的唯一一件事是,因为我对“新建”和“编辑”操作都使用了相同的表单部分,所以 form_for 助手如何知道将请求发送到哪个操作?因为我没有指定这些。当表单在“新”操作中呈现时,它会将请求发送到“创建”,但在“编辑”中它发送到“更新”,它怎么知道?
    • @Cu1ture 正如我在新操作中的回答中所解释的那样,您有 @article = Article.new 并且在编辑中您有 @article = Article.find(params[:id]) 并且在您的 form_for 助手中您使用 @article 所以取决于它的值 rails 生成相应的 url给你
    • 因此,如果我有一个没有值的已初始化 Article 对象,form_for 会向“创建”操作发送请求,但如果它有值则将其发送到“更新”操作?
    • @Cu1ture 没错!对于您的编辑操作,您的文章将具有类似 id: 2, title: xyz 的内容,对于新操作,它将是 id: nil, title: nil 因此 rails 检查@article 并为您创建表单操作。详情请查看polymorphic urls
    • 谢谢,我想我开始掌握这个窍门了。只是为了澄清被调用的操作,例如“创建”与控制器对应的操作,该操作对应于呈现视图的位置或部分文件所在的位置?例如,我正在创建一个位于 /cmets/ 但呈现在 /articles/show 中的评论部分。调用的操作是 cmets#create 还是articles#create?
    【解决方案3】:

    好吧,它不使用重定向。它通过 html 表单操作将您定向到确切的方法。

    澄清一下:

    当您在“/articles/new”中时。 Rails 会将您分派到 Controller#new 操作。

    并且,如果 _form 部分是通过使用 form_for 使用 Form Helpers 实现的

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

    它会生成html表单,如下所示:

    <form accept-charset="UTF-8" action="/article" method="post">
    </form>
    

    如您所见,表单操作属性是"/article",它映射到资源中的 CRUD 操作。

    然后,当您点击表单中的提交按钮后,表单中的数据将被发送到表单标签动作属性中指定的create动作。

    与我们使用的完全相同的部分_form (form_for) 代码也可用于编辑文章。如果表中已经存在@article 记录,而 form_for 将生成此 html 表单:

    <form action="/article/1" class="edit_article" id="edit_person_1" method="post">
    </form>
    

    而且,您会注意到 action 属性现在会将您定向到 CRUD 中的 update 操作。

    因此,form_for 反映了有关其处理的资源的知识或记录标识,如 Rails 文档所述 (http://guides.rubyonrails.org/form_helpers.html#2.3)

    希望这能帮助你理解它:)

    【讨论】:

    • 这对我来说很有意义,只是我没有在我的 form_for 表单部分中指定一个操作。我会将我的 _form 部分添加到我的问题中以澄清
    • @Cu1ture 我刚刚更新了我的答案以描述 form_for 魔术的工作原理。
    • rails 表单助手不会生成操作“/articles/create”
    • @SergioTulentsev 哦,对不起,这是来自上一个示例,form_forand :url => {:action => 'create'}。现在它已经改变了。
    猜你喜欢
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    相关资源
    最近更新 更多