RoR:如何处理自定义嵌套表单的提交
我成功地用 ruby-on-rails 中的自定义表单几乎一路走向幸福,但最后一步缺失了,而且由于常用词太多,不可能在网上找到答案。
我相信我的问题的答案对于曾经做过一段时间 RoR 的人来说是微不足道的,但请注意,问题的呈现会有些复杂。
让我们看看一个等效的问题!
架构:
出版商(id、名称、地址)
图书(id、标题,publisher_id,publishing_year,unit_price,数量)
sell_log(id,user_id,时间戳、book_id、数量、单价、评论)
自定义操作:
名称:销售(上下文:一本书)
输入:
数量
,评论
,(隐式输入:书.id
、时间戳
;派生输入:user_id
、book.unit_price
、book.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 按钮起作用(输入正确时操作成功完成)。
所不存在的是形式仍然存在。理论上,我应该在标有 Q1
、Q2
和 Q3
的位置返回适当的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
该应用程序使用哪个 Rails 版本?
该应用程序使用什么 JavaScript 库?
Book 和 SellLog 是 RESTful 资源吗?
这是您不在帮助程序中使用
link_to_remote
和在控制器操作中使用respond_to
块的原因吗?对于使用原型的 Rails 2.3,我这样做:
_PARTIAL_FOR_ROW_INFO_LAYOUT_ 将会有:
遵循 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 andrespond_to
blocks in the controller actions?With Rails 2.3 using prototype I do it like this:
_PARTIAL_FOR_ROW_INFO_LAYOUT_ would have:
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.
步骤 #1:您必须修改帮助程序中的
link_to
以包含eid
步骤 #2:您必须修改
sell_form.erb
和在url
中设置parent_model
、parent_column
、nested
和eid
。您必须将update
设置为book_list
,并且必须使用element_from_id()
为表单生成正确的 HTML id。步骤#3:将
if request.xhr?
部分修改为以下简单代码。 (未经过充分测试,最好的情况可以正常工作。)Step #1: You have to modify the
link_to
in your helper to includeeid
Step #2: You have to modify the
sell_form.erb
and setparent_model
,parent_column
,nested
andeid
in theurl
. You have to set theupdate
tobook_list
, and you have to generate a proper HTML id for the form withelement_from_id()
.Step #3: Modify the
if request.xhr?
part to the following simple code. (Not fully tested, the best case works properly.)