RoR: как обрабатывать отправку пользовательских вложенных форм
Мне удалось почти полностью пройти путь к счастью с помощью моей пользовательской формы в ruby-on-rails, но последний шаг отсутствует, и невозможно найти ответ в сети из-за слишком большого числа распространенных слов.
Я считаю, что ответы на мои вопросы тривиальны для людей, которые делали RoR какое-то время, но имейте в виду, что изложение вопроса будет несколько сложным.
Давайте посмотрим эквивалентную проблему!
Схема:
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)
Пользовательское действие:
Имя: Продать (контекст: книга)
Входные данные:
qty
,comment
(неявный ввод:book.id
,timestamp
; производные данные:user_id
,book.unit_price
,book.qty
)Результат:
sell_log добавлен
books.qty уменьшился
Возможные ошибки:
Кол-во неположительно или нецелое число.
Кол-во при вводе пользователем больше, чем кол-во доступных (book.qty)
(К вашему сведению: это не вопрос дизайна базы данных.)
Таким образом, у нас есть настраиваемая форма (скрытый идентификатор книги; кол-во, комментарий), которую мы хотим реализовать как действие в поведении, аналогичном "редактированию" книги (update
). Что сделано (это почти все):
- 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 работает (действие успешно завершено, когда ввод правильный).
Чего нет, так это того, что форма остается на месте. Теоретически я должен вернуть соответствующий javascript в местах, отмеченных Q1
, Q2
а также Q3
, Я не хочу перепроектировать вещи и писать javascripts вручную, потому что при обновлении фреймворка я был бы вынужден повторить этот шаг. Я хочу создать необходимые javascript-скрипты наилучшим образом с точки зрения простоты и удобства обслуживания. Как я полагаю, сейчас моя концепция не плохая.
Информация о версии
- JRuby 1.5.0
- драгоценные камни
- рельсы 2.3.4
- activerecord 2.3.4
- Активная поддержка 2.3.4
(Скажи мне, если что-нибудь еще нужно)
Частичный результат
# ...
if errors.empty?
render :action => 'on_update.js'
else
# ...
end
# ...
2 ответа
Шаг № 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
и установить parent_model
, parent_column
, nested
а также eid
в url
, Вы должны установить update
в book_list
, и вы должны сгенерировать правильный идентификатор HTML для формы с 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
%>
Шаг № 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
Какую версию 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 приложения или какие плагины и / или гемы использует ваше приложение, чтобы объяснить текущий шаблон в вашем контроллере.