RoR:如何处理自定义嵌套表单的提交

发布于 2024-09-16 09:19:12 字数 3048 浏览 4 评论 0原文

我成功地用 ruby​​-on-rails 中的自定义表单几乎一路走向幸福,但最后一步缺失了,而且由于常用词太多,不可能在网上找到答案。

我相信我的问题的答案对于曾经做过一段时间 RoR 的人来说是微不足道的,但请注意,问题的呈现会有些复杂。

让我们看看一个等效的问题!

架构:

  • 出版商(id、名称、地址)

  • 图书(id、标题,publisher_id,publishing_year,unit_price,数量)

  • sell_log(id,user_id,时间戳、book_id、数量、单价、评论)

自定义操作:

  • 名称:销售(上下文:一本书)

  • 输入:数量评论,(隐式输入:书.id时间戳;派生输入:user_idbook.unit_pricebook.qty

  • 结果:

    • sell_log 已附加

    • 书籍数量减少

  • 可能的错误:

    • 数量为非正数或非整数。

    • 用户输入的数量大于可用数量 (book.qty)

(仅供参考:这不是关于数据库设计。)

因此,我们有一个自定义表单(隐藏的书本 ID;数量、评论),我们希望将其实现为与书籍“编辑”行为类似的操作(更新)。所做的事情(几乎是所有事情):

-- books_controller.rb:添加了 custom_qty_display 列。

-- books_helper.rb:

def custom_qty_display_column(record)
  record.qty.to_label + " ["
  link_to( "Sell..." \
            , { :controller => "books", :action => "sell_form", :id => record.id, :page => false } \
            , { :position => "replace", :inline => true, :class => "action" } \
          ) \
  + "]"
end

-​​-views/books/sell_form.erb (仅关键细节)

<%
  form_remote_tag( \
    :url => { :controller => :books, :action => :sell, :id => params[:id] } \
  ) do
%>
...
<%= submit_tag 'Submit' %>
<%= link_to as_(:cancel), main_path_to_return, :class => 'cancel' %>
<% end %>
<div id="as_books-messages" class="messages-container" />

-- books_controller.rb:

def sell
  errors = [] # We will collect error messages here
  # Checking parameters ...
  # Checking of available qty ...
  # If "errors" is still empty here, perform the action
  # Produce the output according to the above:
  if request.xhr?
    if errors.empty?
      # Q1: rendering of javascript which replaces the form with the modified row in the table.
    else
      # Q2: rendering of javascript which provides the "errors" for the user
    end
  else
    if errors.empty?
      index
    else
      # Q3: Redisplay the form and errors
    end
  end
end

当前进度

当我点击图书列表中的“出售...”链接时条目条目消失,取而代之的是自定义表单出现。在表单上,​​“取消”链接(和 [X] 按钮)运行良好; SUBMIT 按钮起作用(输入正确时操作成功完成)。

所不存在的是形式仍然存在。理论上,我应该在标有 Q1Q2Q3 的位置返回适当的 javascript。我不想对事物进行逆向工程并手动编写 JavaScript,因为在框架升级时我将被迫重做此步骤。我想在简单性和可维护性方面以尽可能最好的方式生成必要的 JavaScript。我现在相信我的想法还不错。

版本信息

  • JRuby 1.5.0
  • gems
    • 导轨2.3.4
    • activerecord 2.3.4
    • 主动支持2.3.4

(如果还需要什么,请告诉我)

部分结果

# ...
if errors.empty?
  render :action => 'on_update.js'
else
  # ...
end
# ...

I managed to do almost all the way towards happiness with my custom form in ruby-on-rails, but the very last step is missing and it is impossible to find the answer on the net because of too many common words.

I believe that the answers to my questions are trivial for people who have done RoR for a time, but be warned that the presentation of the question will be somewhat complicated.

Let's see an equivalent problem!

Schema:

  • publishers (id, name, address)

  • books (id, title, publisher_id, publishing_year, unit_price, qty)

  • sell_log (id, user_id, timestamp, book_id, qty, unit_price, comment)

Custom action:

  • Name: Sell (context: a book)

  • Input: qty, comment, (implicit input: book.id, timestamp; derived input: user_id, book.unit_price, book.qty)

  • Result:

    • sell_log is appended

    • books.qty decreased

  • Possible errors:

    • The qty is non-positive or non-integer.

    • The qty at the user input is greater than the qty available (book.qty)

(FYI: It is not a question about database design.)

So we have a custom form (hidden book-id; qty, comment) which we want to implement as an action in a similar behavior as "Edit" of a book (update). What is done (is almost everything):

-- books_controller.rb: Added custom_qty_display column.

-- books_helper.rb:

def custom_qty_display_column(record)
  record.qty.to_label + " ["
  link_to( "Sell..." \
            , { :controller => "books", :action => "sell_form", :id => record.id, :page => false } \
            , { :position => "replace", :inline => true, :class => "action" } \
          ) \
  + "]"
end

-- views/books/sell_form.erb (only key details)

<%
  form_remote_tag( \
    :url => { :controller => :books, :action => :sell, :id => params[:id] } \
  ) do
%>
...
<%= submit_tag 'Submit' %>
<%= link_to as_(:cancel), main_path_to_return, :class => 'cancel' %>
<% end %>
<div id="as_books-messages" class="messages-container" />

-- books_controller.rb:

def sell
  errors = [] # We will collect error messages here
  # Checking parameters ...
  # Checking of available qty ...
  # If "errors" is still empty here, perform the action
  # Produce the output according to the above:
  if request.xhr?
    if errors.empty?
      # Q1: rendering of javascript which replaces the form with the modified row in the table.
    else
      # Q2: rendering of javascript which provides the "errors" for the user
    end
  else
    if errors.empty?
      index
    else
      # Q3: Redisplay the form and errors
    end
  end
end

Current progress

When I click the "Sell..." link at a book list entry the entry disappears, custom form appears instead of it. On the form the "Cancel" link (and [X] button) works perfectly; the SUBMIT button works (the action is completed successfully when the input is correct).

What is not there is that the form remains in place. In theory I should return the appropriate javascript on places marked with Q1, Q2 and Q3. I do not want to reverse engineer things and write javascripts with hand because on a framework upgrade I would be forced to redo this step. I want to produce the necessary javascripts in the best possible way regarding simplicity and maintainability. As I believe now my concept is not bad.

Version information

  • JRuby 1.5.0
  • gems
    • rails 2.3.4
    • activerecord 2.3.4
    • activesupport 2.3.4

(Tell me if anything else needed)

Partial result

# ...
if errors.empty?
  render :action => 'on_update.js'
else
  # ...
end
# ...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

预谋 2024-09-23 09:19:12

该应用程序使用哪个 Rails 版本?
该应用程序使用什么 JavaScript 库?
Book 和 SellLog 是 RESTful 资源吗?

这是您不在帮助程序中使用 link_to_remote 和在控制器操作中使用 respond_to 块的原因吗?

对于使用原型的 Rails 2.3,我这样做:

in controller:

def sell 
  # …
  # book / quantity / errors
  # …
  respond_to do |format|
    if errors.empty?
      format.js {render :update do |page|
        page.replace_html '_ID_OF_DOM_OBJECT_CONTAINING_ROW_INFO_', :partial => '_PARTIAL_FOR_ROW_INFO_LAYOUT_' 
      end}
      format.html { redirect_to :action => _WHATEVER_THE_SUCCESS_ACTION_IS_ }
    else
      format.js {render :update do |page|
        page.replace_html 'form', :partial => '_DOM_ID_OF_FORM_' 
      end}
      format.html { render :action => _WHATEVER_ACTION_DISPLAYED_THE_FORM_ }
    end
  end
end

_PARTIAL_FOR_ROW_INFO_LAYOUT_ 将会有:

<div id="_ID_OF_DOM_OBJECT_CONTAINING_ROW_INFO_">
  <!-- row display markup -->
</div>

遵循 Rails 约定时,您正在做的很多事情会更容易,但我不知道您的 Rails 版本、应用程序 DSL 或哪些插件和/或者您的应用程序使用的 gems 可以解释控制器中的当前模式。

Which Rails version is the app using?
What javascript library is the app using?
Are Book and SellLog RESTful resources?

Is their a reason you're not using link_to_remote in the helper and respond_to blocks in the controller actions?

With Rails 2.3 using prototype I do it like this:

in controller:

def sell 
  # …
  # book / quantity / errors
  # …
  respond_to do |format|
    if errors.empty?
      format.js {render :update do |page|
        page.replace_html '_ID_OF_DOM_OBJECT_CONTAINING_ROW_INFO_', :partial => '_PARTIAL_FOR_ROW_INFO_LAYOUT_' 
      end}
      format.html { redirect_to :action => _WHATEVER_THE_SUCCESS_ACTION_IS_ }
    else
      format.js {render :update do |page|
        page.replace_html 'form', :partial => '_DOM_ID_OF_FORM_' 
      end}
      format.html { render :action => _WHATEVER_ACTION_DISPLAYED_THE_FORM_ }
    end
  end
end

_PARTIAL_FOR_ROW_INFO_LAYOUT_ would have:

<div id="_ID_OF_DOM_OBJECT_CONTAINING_ROW_INFO_">
  <!-- row display markup -->
</div>

A lot of what you're doing would be easier when following the Rails conventions, but I don't know your Rails version, app DSL, or what plugins and/or gems your app uses that would explain the current pattern in your controller.

你与清晨阳光 2024-09-23 09:19:12

步骤 #1:您必须修改帮助程序中的 link_to 以包含 eid

link_to( "Close..." \
    , { :controller => "books", :action => "sell_form", :id => record.id, :page => false, :eid => @controller.params[:eid] } \
    , { :position => "replace", :inline => true, :class => "action" } \
  )

步骤 #2:您必须修改 sell_form.erb 和在 url 中设置 parent_modelparent_columnnestedeid。您必须将 update 设置为 book_list,并且必须使用 element_from_id() 为表单生成正确的 HTML id。

<%
  form_remote_tag( \
    :url => { :controller => :books, :action => :sell, :id => params[:id], :parent_column => "books", :parent_model => "Publisher", :nested => "true", :eid => params[:eid] } \
    , :update => :book_list \
    , :html => { :id => element_form_id(:action => :update) } \
  ) do
%>

步骤#3:将 if request.xhr? 部分修改为以下简单代码。 (未经过充分测试,最好的情况可以正常工作。)

if request.xhr?
  if @record.valid?
    render :action => 'on_update.js'
  else
    render :action => 'form_messages.js'
  end
else
  if @record.valid?
    return_to_main
  else
    render :action => 'sell_form'
  end
end

Step #1: You have to modify the link_to in your helper to include eid

link_to( "Close..." \
    , { :controller => "books", :action => "sell_form", :id => record.id, :page => false, :eid => @controller.params[:eid] } \
    , { :position => "replace", :inline => true, :class => "action" } \
  )

Step #2: You have to modify the sell_form.erb and set parent_model, parent_column, nested and eid in the url. You have to set the update to book_list, and you have to generate a proper HTML id for the form with element_from_id().

<%
  form_remote_tag( \
    :url => { :controller => :books, :action => :sell, :id => params[:id], :parent_column => "books", :parent_model => "Publisher", :nested => "true", :eid => params[:eid] } \
    , :update => :book_list \
    , :html => { :id => element_form_id(:action => :update) } \
  ) do
%>

Step #3: Modify the if request.xhr? part to the following simple code. (Not fully tested, the best case works properly.)

if request.xhr?
  if @record.valid?
    render :action => 'on_update.js'
  else
    render :action => 'form_messages.js'
  end
else
  if @record.valid?
    return_to_main
  else
    render :action => 'sell_form'
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文